|

楼主 |
发表于 2021-1-2 09:20:48
|
显示全部楼层
#include<iostream>
' m' H3 [! W" f. w% J2 ~#include<opencv2/core/core.hpp>1 r8 X" y0 K! K5 X/ p0 k u
#include<opencv2/highgui/highgui.hpp>
. J+ K% s8 j: X w% t#include <opencv2/opencv.hpp>- b! n+ R7 A( D# g
#include <opencv2/imgproc/imgproc.hpp>! Y, t- h3 ]. X
#include <opencv2/imgproc/types_c.h>
9 x2 {6 _& O0 n' W0 Y9 `$ n#include <stdlib.h>! Z8 V3 S D* V- h6 ?: Q1 n
#include <stdio.h>7 @: A9 Q* ~" z7 [) o L& C+ X* [
#include <opencv2/highgui/highgui_c.h>
5 l+ Z# ]8 k& q6 F' j#include <math.h> ]7 D9 z- p# I& I
//#include "iostream"
2 e' U& n- q7 b# x/ R' ~' _, A& p" D' G//#include "cv.h"2 l$ I' x1 B# ]0 a) W
//#include "highgui.h"
# ^6 ^% w7 t, e! r. z3 J! {//#include "math.h"1 |1 e" ]8 O$ I) X( Y; t
using namespace cv; //命名空间CV6 Q! Z* O0 o* @
using namespace std; //命名空间 std
( O9 _8 S4 A2 K, H& @0 J9 P
0 \( d% D( ~) E. J- W# K/ v2 L+ H- Mint threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。7 W1 o3 N2 Y' }5 J
int threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零7 b6 @% f# E& [$ m' @( B+ g6 l) o) W+ o) }
int const max_value = 255;
% ~+ l9 q0 i0 Tint const max_type = 4;% M1 s- c& t: V+ @' A/ x$ D* v8 l
int const max_BINARY_value = 255;
8 y$ a# l! U7 g8 F( E
% V, J/ a: G5 T6 O3 @# w CvFont font;$ G8 T* f0 x( u; T; n
uchar* ptr;% ]& o1 X0 X5 ~ ]
char label[20];
' u6 R" `! ^; f- q0 q+ S: p6 k char label2[20];/ n, g/ F& R9 G* j
& d- {7 ~- o( W# F1 iMat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图
' N, T9 z% f1 A. U //在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao$ }$ \* ?' s5 q m
//例如:char *string="I love C#!"
/ k }6 v- j$ h, o& y3 w //定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/
3 q- {7 Z; p0 V4 W$ i0 iMat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数
( }4 ~; y# \" w9 Vchar* window_name = "阈值演示程序20201121";7 B7 f2 j" H+ A3 s
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
/ D. Y" d5 E* ~" a! V' Vchar* trackbar_value = "数值";5 O* j4 M, b l1 ^, X! {! T; t
+ d4 a2 m0 `; N) U" q; S% V/// 自定义函数声明 c* @. Y2 p% A+ a, r$ f6 a4 [$ i
void Threshold_Demo( int, void* );& i% ]6 y) G$ l% E4 P& u. A" x0 a
( l y% S6 G- L6 F& P; D
/**
! i N0 E* N% ^ * @主函数9 K! @1 t( O/ `3 _/ P4 k6 J u. t
*/
T" I0 J9 [1 Y' B& f1 Eint main( int argc, char** argv )0 L' X( I' x- e7 I2 q) u) r' z
{
5 C% Q% b, _; p7 I /// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)/ Y' P, S4 @5 a
src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。9 L6 G Y4 u* w3 _5 \' B+ H) \" W
erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪
- g4 F3 i% |4 ?: J" T% f blur (src_e, blured, Size (3,3));//3*3内核降噪
, p5 J6 V6 C* j0 V; P. U imshow("腐蚀和降噪后的图片", blured); //显示图片
" @: N* W& k' ^, A6 I/ a i. v int width=blured.rows; //图像的行列" j: H, q1 C, J( z' x# H8 S
int height=blured.cols; //图像的列数量
; `5 Q4 w+ p; l% y8 v; t cout<<width<<endl; //显示行列的具体像素% s2 W- O& u! ]+ c. R$ G
cout<<height<<endl;
9 M, z8 K, Q. ^ int a[500][1]; //定义整型数组,后面的1应该可以不要的
. X2 E) l3 a; m3 A int b[500]; //设置一维数组,用于判断曲线的切线斜率+ I, Y2 Z$ q. l' U F k
5 R: ^ C1 y, o4 u u1 X5 ?
/// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
7 c2 e4 V! b; M# A2 t, _3 N2 y cvtColor( blured, src_gray, CV_RGB2GRAY );" p8 C- Z# r! z! \8 `
* |* A" I/ d7 ^0 v& a s8 k
/// 创建一个窗口显示图片
) h( u+ T5 P' U- d namedWindow( window_name, CV_WINDOW_AUTOSIZE );; }! O; B9 D# @9 g2 R6 |6 ?. o1 o
\2 [: ~7 C; ^/ @* m/ f
/// 创建滑动条来控制阈值* `$ ?8 ~/ E$ z# F0 }
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
, E; q& J3 z9 E. \3 i3 W5 _' F- Y
- ^9 N3 P* z- {6 ^ createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
9 D# F3 X; h8 {/ y$ f# \3 k( i1 g- ~- C' [& M9 n6 f2 R
/// 初始化自定义的阈值函数" g* L: ~ @4 a+ \) ?" Z+ m& m
Threshold_Demo( 0, 0 );
9 d; W) y8 ?! y8 i8 Y: p0 Y* p
3 n, Z7 L# |* e3 e // Mat img=src; //暂时无用
( ^+ y3 j5 S. e" b; D //imshow("转化之后图片",dst);
7 j; g% Z8 ~- h2 j3 v- r3 e, L4 Z \0 F& s) B
//遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较
1 H6 K$ x9 ^2 n) C 2 Z8 y9 r! v! I* t/ [1 o
//Mat BW = imread(imgName);" j2 X& ^) @0 j3 S$ n' L( e; [2 j
//int value = BW.at<uchar>(191, 51);# o `2 f# R5 e2 m! K
int width1=dst.rows; //处理之后图像的行列9 `! M1 C% t7 L+ { l; Q: ?- k1 @
int height1=dst.cols; //处理之后图像的列数量
$ r% ^; p6 V8 b2 X$ l% U7 O
7 K) v' P5 Q/ ^- Z& U for (int i=0 ; i<height1; i++) //从第一行开始 应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖6 \' s& M1 @! z, H& v0 g6 W& I
{4 a# I7 a2 ?9 T* L3 F/ U, ] \
for (int j = 0; j < width1; j++) //从第一行的第一列开始1 ~" Q- [6 d3 }7 F
{7 i+ Q( y8 F3 N" F
//int index = i * width + j;8 K' ]9 p3 y* @% K& S- k9 k
int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值: d/ U9 I3 y+ v4 f6 a* B
//if; //像素值 Y6 K: I4 B2 W8 D3 E% w
//int data = (int)dst.data[index];
; ?. ` x8 v5 e if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃' J2 l) R: J5 ~( i$ b, u% a6 a
{
) L# ^: P5 X# S a[i][1]=j; //数组值等于列数,便于后期对比
3 a) e# [# h V% ] k1 V5 ]- d //cout<<i<<" --- "<<j<<endl; //i为行数
+ g7 A( Q, ]" @: Y& }( {9 H7 a //cout<<i<<" -坐标-- "<<a[i][1]<<endl;
2 z) [1 k( s/ q" L3 }1 v7 ` if (i>1)% M" @* Y" l7 q5 k. W0 s
{ //11
. @% Z2 U0 [ q$ i f; M if (a[i-1][1]<a[i][1]) //如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说
6 s/ L; v# k0 Q: Z( P //明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)9 Y( e6 |( z) c6 S
{
+ i9 x9 z+ E" ]: I& | b[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。
) M1 O7 A# ?* X2 X' ]3 M. j j, | }
0 q, E$ B( x. C6 H3 L else if (a[i-1][1]>=a[i][1]) * I& n D5 K3 g* x
{" s$ e" D" V: L7 D% w: N
b[i]=1;7 X- W, Y# ?6 K4 h/ s5 Z
}
( W4 z' J; u% j4 `8 f8 Q7 q2 Y0 Z& N& ^0 |
cout<<i<<" -标识符-- "<<b[i]<<endl; 0 `) s4 k) G2 B% l. T
//cout<<j<<endl; //j为列数
, o0 L+ F3 Q% X } //11
( D9 H/ A( f. g# g8 d
; E3 n. x& l v, R; ^- V' x
, q" m/ Q0 e& P, }. w- G% { break;
P7 D2 h; C; w. K# p }
7 d2 B3 s t2 _: J9 {" @3 `7 F }
" o% S% L. o/ `: O% ~( l5 n }# d, L6 ]& w& h( H7 o' i1 G
//开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)7 A% S( W# v9 h5 [3 z" \
for (int i=0 ; i<height1; i++) //对数组b进行遍历,检查是否存在误判的问题
' c$ T9 H: b( V6 Q, V7 k: j //寻找拐点,找到用于判断的后段曲线的拐点5 V c! @" Q9 `& K6 d
//对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线
( W' {; y8 w- n4 g, \ " c& |% l; m8 n; O) g& ?
# k) r2 V, g4 Y, J( x % D" ~$ T) I1 |$ f8 ~$ |
// int width=dst.rows; //图像的行列$ X% i. c. f/ m
//int height=dst.cols; //图像的列数量' f" E0 {4 t4 U& t6 G
cout<<width<<endl; //显示行列的具体像素( x2 ?! F4 B4 R7 ^+ I6 F
cout<<height<<endl;
9 |2 C& C. E& r, g: J8 s4 L //for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析5 s2 r* e7 Q8 Z) e" u6 V: H
/ n P. [/ I/ o$ b- c
// 等待用户按键。如果是ESC健则退出等待过程。/ y" T; p8 `& n0 R5 [3 D9 h
while (true): t# H* x6 L0 ^" e/ Y
{
8 \, d i7 F8 S1 D, l% o" j2 k$ b int c;
4 Y3 v8 _8 ~! W8 d7 z* O) e* x c = waitKey( 20 );
) t$ T O( c8 ] if( (char)c == 27 )9 }9 `) m! C& q( X0 L& d4 }/ l
{ break; }) z. ?" J- V2 ]' {; i' @" t
}
8 w$ m9 b2 D9 D/ R) @! G' i- d" c
}8 e* y1 T9 N3 k
) N D( Z) B$ K0 J" }( w
# P8 _" b& |4 z" R5 `/**
, N/ J$ h+ G+ n3 _4 b) Y" a * @自定义的阈值函数( r( s) N7 F9 Y' |1 q* _9 v. j
*/
8 ?) }% |6 e: j& l2 w9 @% Y& ~. a. Uvoid Threshold_Demo( int, void* )9 b1 d) M& n" ^- q& ^/ O) |
{8 P, v4 X. l2 L4 @7 N( G5 @; R
/* 0: 二进制阈值. N( ^/ Q' y v" [0 w, l% u
1: 反二进制阈值2 g2 c9 d8 c% a A: T' j
2: 截断阈值! c1 W, J3 H/ z. ?
3: 0阈值/ F" O. c4 S3 ~- M* `. q$ I- F
4: 反0阈值
+ A+ }4 {% b% y0 _, D$ j */
! i8 R4 w6 u6 Z4 U. D8 C4 G! z8 N3 m' r/ L; U1 T
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );) ^4 K1 p( C7 }$ B( `
7 n9 ^( ?1 x. E1 Q& }7 t
imshow( window_name, dst );+ i' d: [" M: f: k
}
# f7 o7 |: W4 t" \/ }5 a$ k$ I8 `# _/ h1 r, J4 ~, @# L: X
7 q; x+ g y; |
. l$ X7 N/ L- K
# v1 m+ x6 o# p- `9 S' I1 h _/ P
# e9 ^3 m2 C1 i8 ^: ^/*
1 q8 j5 W0 q0 Svoid main()
2 P0 W4 j# `& b5 p! h) ?) `6 S5 J{5 ?( c8 ^' |8 c0 U
: u A |- v1 e: W //读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图& c. z7 e$ _: A
, W0 f: w* D+ o+ g! Z$ `8 E5 C
//Mat img = imread("fruits.jpg");
+ I: [; w* y& A# z6 z, y& \$ G Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
5 O( Q: m# X0 i; ?* i imshow("灰度图", img);
[1 v( e$ X k5 h //确定图像的尺寸,行列,
$ j+ B0 J& z3 q+ B+ | int width=img.rows; //图片的变量名加上行列,就是行列的数据
* I; m) K7 a5 x. y; P+ { int height=img.cols;
. ]) ^ g: V$ Y! d3 C cout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是358
3 q* ^! S! \0 E" v& c cout << height << endl;
3 L \* D4 H {" S# w //定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
U. ]% [+ o# A6 ]1 W& N int a[358][1]; //确定一个358的二维数组# `$ D* v2 g& |2 s0 E$ j0 S2 T
) S7 Y& K" ~2 R' M5 j//int height = backImg.rows; //backImg是图片变量名/ }& K7 B6 j1 n& U8 u5 s- y L. |5 M
//int width = backImg.cols; K! g& O' k4 [& ~
for (int i = 0; i < height; i++)
; ]: |2 j* I' z5 k4 G% j {
3 S, b, X$ v% h( P for (int j = 0; j < width; j++)- {' F ?+ ]* K! T8 @1 |
{0 S- r, {" ~% C' }; M
int index = i * width + j;
7 r- v$ o+ J4 Z3 [: F* p( ` s //像素值; P# x5 f3 [0 ]+ R2 o4 m) h4 t
int data = (int)img.data[index];+ `4 r1 t6 e0 `" f0 k( v
}
$ P1 k5 K: t1 }! I( [, |$ z& l: m }/ j. P" P; @: D/ |4 E
waitKey();
, w7 V: E4 j1 \}9 [+ X7 s! ?+ k2 W+ R' x
*/ |
|