|
#includeP* d& D7 Q5 S c3 M #include 8 c! P3 W3 u: n$ H' ?7 j#include5 M' c- c8 J7 L7 @1 w% y+ E0 t6 y& v #include % l( c& ~) G0 G7 t) O/ J3 U#include s2 g* P5 @! D5 e9 x. A( P7 f#include 3 q( Z) x( C1 R #include 4 s I+ P$ |6 _1 n7 i! I$ b #include 6 I/ O: O# D8 q+ ?0 ]# R0 K #include , o4 r* E7 ?( Q1 v2 t #include 2 L. g: u0 i Z: _ X0 L! J' ~ //#include "iostream" * W# Y9 d6 M( _% w8 n4 L7 c& B//#include "cv.h" # b$ x0 R) s- \% Z- }//#include "highgui.h"' ^5 s1 v$ q1 q3 F- x# y1 g //#include "math.h"# G) h3 U- K' I using namespace cv; //命名空间CV" G( P% P0 L* X* {- `" L" b8 e5 ? using namespace std; //命名空间 std 1 n% }, x$ p$ S3 b6 _& U6 O* IN3 I6 i, C2 ^ int threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。 , Q! g, Y8 c1 q1 O( e* }int threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零6 C$ O( Y9 e: [ ^( c% ^ int const max_value = 255; ' T& @; h; {' b3 w9 v+ j+ Zint const max_type = 4; " q) ^5 e/ P& I* Nint const max_BINARY_value = 255;d1 { L9 X9 w4 l( [& a
# V# ?. p+ s1 ~. S" k M( pCvFont font;# Q: U" t. O" d' Q3 f uchar* ptr; ' [% [& @" A* ~4 k: zchar label[20];1 H8 {; D" y9 j# D1 ` char label2[20]; / {( j4 Q5 I) H, o2 f5 m$ O, R; R! c2 V Mat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图 * C8 g( H5 g6 @//在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao7 l8 `! w; }, j, Z5 a+ R1 X8 S //例如:char *string="I love C#!" 6 b0 @" M5 Y. K% a- Z. O& z/ r1 T& A//定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*// a( Y) O# J% \) ~2 j0 U8 _0 M- B. { Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数 ! U! `8 i5 e3 Z- E( W! ]. z# l# gchar* window_name = "阈值演示程序20201121"; * k+ g- P! {. C5 e% t! \char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; // 4 y' U5 {& T* p& ]char* trackbar_value = "数值"; & v. n# \$ U$ H( }! u ' k# c2 v( g: u# j, a7 }/// 自定义函数声明 ! z4 P i S7 g Hvoid Threshold_Demo( int, void* );1 d% B% W& y$ e
7 r8 L& a" X+ H& f& D4 ^/**1 F" e1 y! G. E, O( w * @主函数 ( J0 A' o' c: N! Y T6 v2 K" O*/ , E& u- M7 d: J6 m6 m# ^9 Q) @; uint main( int argc, char** argv ) 6 ~. U! G/ x( \{& _% H+ u. C; k) T* W /// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式) 5 v! E# Z1 Y; A$ G+ c1 i! zsrc = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。 0 z/ H- c5 c! j' R. d" x+ g/ @erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪 - d! b$ l% c8 O$ y g4 ~) |. {+ Tblur (src_e, blured, Size (3,3));//3*3内核降噪 , C8 V# [1 s- i- n+ x& Mimshow("腐蚀和降噪后的图片", blured); //显示图片/ V! [' e- Z* P( Y int width=blured.rows; //图像的行列# d" G% M' A" f4 f6 H! q/ ? j int height=blured.cols; //图像的列数量 ( D J* n! s. W0 }; w0 Y5 Qcout<+ y$ t; p' O1 ]. _cout<+ e& ^0 I3 f" E, x4 X: o" eint a[500][1]; //定义整型数组,后面的1应该可以不要的 0 ?% f7 L' u" S1 r9 _int b[500]; //设置一维数组,用于判断曲线的切线斜率 , Y* R& O7 y5 p4 B0 [% i5 O3 p: p0 o% e2 Y% n0 O. t7 y5 L; Z: y /// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对8 N- b8 z: e/ m/ F/ ^, K- | cvtColor( blured, src_gray, CV_RGB2GRAY ); % @( _; z! V1 x6 b5 k " J/ n# f) m1 D' {/// 创建一个窗口显示图片 ) Q* d) b x. n, H/ nnamedWindow( window_name, CV_WINDOW_AUTOSIZE );3 m3 s( L6 C d 0 y0 ]5 `) b R3 [$ x /// 创建滑动条来控制阈值 ' U8 b0 b+ e/ IcreateTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);9 k% q5 r, o& A/ |7 h . u! T# q- ~; }/ f7 W createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);3 w% Y& @- {, r4 b# W, j; ^" y
: A5 c6 o8 }6 H, }& t/// 初始化自定义的阈值函数 0 o2 {' \* s, |5 }Threshold_Demo( 0, 0 ); : y" a* L' w( V+ Y& I& p5 {) A) {' ^1 i/ }/ c // Mat img=src; //暂时无用- n, P0 F: Z! h8 I& F //imshow("转化之后图片",dst);6 k' m9 s- o" I
# H0 t& s( l; X$ q//遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较# ~! k9 s+ X; {* O7 k: q/ M( w1 D ' C0 h$ w2 O- \* p: d i+ Y N //Mat BW = imread(imgName);/ v$ F: \) K ^" u3 t+ s //int value = BW.at(191, 51);. w6 ~. ]- k5 y: ]; r m# g int width1=dst.rows; //处理之后图像的行列 / J) c& }5 u3 ~" t4 |2 Fint height1=dst.cols; //处理之后图像的列数量 1 g F& o |3 H9 `& U9 m6 U" w0 }" T; G# }1 } for (int i=0 ; i. c2 }3 C$ K$ |3 j{" x d @$ m# ^- c* a for (int j = 0; j < width1; j++) //从第一行的第一列开始: f( C- i: X3 |, F! M) w { 2 N+ z" i& T& d' q) _6 O3 _//int index = i * width + j; 8 ~6 q9 c8 N6 ^; Y' l% |% C$ Lint value = dst.at(i,j); //读取给定坐标处的像素值+ l0 U" z7 t# T$ H4 l //if; //像素值3 {0 P4 a7 o7 F' f6 ~5 F5 ? //int data = (int)dst.data[index]; R: @7 [: T5 b% E# A& V/ K4 Vif ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃 ) w$ ?! B' V& U3 {{ * J1 G0 w+ H9 o, f# M) Na[i][1]=j; //数组值等于列数,便于后期对比: q; I# a, K& m. U! h/ U //cout<, F7 e1 P+ i3 Z& H( }6 W; r" f) s//cout<" O1 {' h, s- i- Y* p h% P0 o# dif (i>1)) o5 r& d2 W1 L8 H5 L3 j) _6 a { //11 0 {, u' T( x- j" ^) h. ~if (a[i-1][1]8 |# B' G; x& J//明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值) 5 L4 R8 U0 ?/ A5 E" u2 l{ # D7 N% C6 Y' k: [% j7 lb[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。, ~3 K! q+ X. C* _ }* M0 b+ b, g7 Q1 f" t else if (a[i-1][1]>=a[i][1]). b0 W! _ r1 B3 ?3 I2 ^1 h9 S h1 P {, k! G" J) V2 d b[i]=1; : l$ h( e4 {: z3 X: [} 5 H5 f9 y2 ?9 q6 p5 o; Q1 B! N+ U . Z! ~" d3 |- M8 Z+ p# {3 w9 Z0 gcout<0 D$ g, t) z! f% Y //cout<4 x3 `' X' g9 j } //11+ y) q/ F' V' [ r 8 e& \& y! S6 T: j
7 c7 {8 Z7 c- n2 b' ^; @$ Obreak;% i8 x- `) D6 {2 t2 ] }/ U! @" E6 I2 {- k: h* k } 2 a5 m/ I. z( v: Y2 W} 3 b/ W% ?( w* d: B) }7 U* P//开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)+ U v, }2 s$ _! }+ P for (int i=0 ; i& F+ [( |# _+ e. n4 G //寻找拐点,找到用于判断的后段曲线的拐点7 ^7 K6 U" I9 R$ J: l //对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线 ( g9 {. A( l. o 0 |$ p3 R2 L+ j ' L/ I- e) ?3 v5 N% p1 F- Y/ T# b x/ @" ]" y; Y: J- e8 Y0 M+ r* @// int width=dst.rows; //图像的行列 " M1 S" c6 _& m) u//int height=dst.cols; //图像的列数量 . \' o2 o0 E, O5 y; I" bcout<; \7 ~+ n; z: ^7 C' Qcout<) S+ a9 ?* n0 L9 T z //for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析' t* `) Z; i: Z, N
8 Y5 Z T% h; \" b* R7 w3 S7 R/ H6 r// 等待用户按键。如果是ESC健则退出等待过程。 7 d) A# G, v* t3 B9 ] {5 H2 owhile (true) " Y+ m) c, i7 Y{ # j$ q3 Z* Z/ x. s9 ~: \int c; 7 M% C" u* I2 P) ?/ } U. s, hc = waitKey( 20 );6 G, ~6 N* M- l. A4 \ if( (char)c == 27 ) , Q1 [! ~: i2 V( ?* W{ break; }i6 R: w. K" R, i7 k+ e, l } ) f1 z; G1 ~4 r3 Y' P, E" J) M2 z0 _/ I5 E5 ^3 n4 H" C9 K } + w) l% J# u* d R* H. i , v) }9 M& l# F9 j3 ` ( c6 s, w/ y0 c& v! _* P/**# ?" V+ b Y" T * @自定义的阈值函数 7 w: J& z8 d* K e1 j, q+ A*/0 a! L U' \+ F3 b void Threshold_Demo( int, void* ) % K8 `; ` u+ _1 d" B( @/ C* s{, A7 h3 }5 w' L /* 0: 二进制阈值9 z; T0 H* C( \( P 1: 反二进制阈值 + V- G4 V+ z& f. V9 d& k2: 截断阈值 & o2 Q" M, v$ M, W3: 0阈值 + o& u& b# M9 O( u+ ~2 A) V7 ~4: 反0阈值0 c0 [9 J7 A3 ?4 C) J6 B! J0 r */ , ~: x+ C" q+ T* W# U 6 y: e8 O* S) O5 bthreshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type ); . @/ s$ v9 A5 D, s- t- L& M' B7 d* r, X$ U/ y9 H% W* I$ i% q' f& i5 r imshow( window_name, dst );* a- I- z( X* ~9 B+ }8 z. a } 8 ?& [1 Q# a: _7 L9 S& x- J# o1 H1 H* \9 @ & p! Q0 ~ W3 F/ P2 Z1 n
; B& w, D" H H6 @8 ~/ `/ [& B3 H4 S5 _
4 o6 z5 Y S( Q t7 u: i/* 9 s% T3 P U1 A$ X f8 T: e$ Dvoid main()8 q& [ i$ G, ?! P$ I {* g: ?0 f$ {& b4 [: E5 I 2 ~- S1 t% y, M //读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图 8 I8 K3 e" N9 b( H" c3 b % r2 z0 }' n- g1 D//Mat img = imread("fruits.jpg");" s/ z9 @' M( g* }, Z( A$ x3 u Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对 / `& O3 X- N$ A* E* ^* l2 ]" O% j( wimshow("灰度图", img);/ b1 ~: S. {% N( L //确定图像的尺寸,行列, ; O% T2 p0 o7 X/ H) S0 @; R$ \int width=img.rows; //图片的变量名加上行列,就是行列的数据6 L' V5 ~9 Z. g, Y int height=img.cols; - Z' d W. H, h$ I, L1 X) ycout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是358* i1 L+ M6 q0 r+ Q7 K, {0 v! d cout << height << endl;- O& U' f' ?6 F/ I) a1 O //定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。 5 _% }# I2 Z# Dint a[358][1]; //确定一个358的二维数组& M# I$ f7 Y, B M$ _- g# |
, |% p+ w0 @3 X/ F7 N6 M//int height = backImg.rows; //backImg是图片变量名 + m8 }; j& [( O2 D! k) `$ K3 S//int width = backImg.cols; 6 m0 W4 q" H1 H+ p- lfor (int i = 0; i < height; i++) $ R5 }3 E- `# G. G{ ( S3 g' W: q( Hfor (int j = 0; j < width; j++) + I+ P# v7 w9 r! V- w6 J{ 7 p% I U! L/ r1 x; o1 Gint index = i * width + j; ; E; _9 y8 C' w8 L& L& J- t8 Z//像素值/ O5 D7 n, u- W) z/ b6 n8 n. c6 d int data = (int)img.data[index];4 |- t8 b) b3 p: D& _ }8 E1 o L b5 K6 ` } 2 ?% P E# i2 \9 l+ R# V8 x, N* a- {8 B. JwaitKey();) O% O) H s4 Q( d2 ?' i2 w& Z }+ W; W' h* W: A9 H$ E */ |
|