|
#include<iostream>' E0 Y" Y D: { q
#include<opencv2/core/core.hpp>
3 H: [+ X# O0 G! M1 y; k9 O! a#include<opencv2/highgui/highgui.hpp>
/ N6 s c" w5 M$ k! f* p#include <opencv2/opencv.hpp>
0 E( K, s2 x! u6 k* p2 j& ~#include <opencv2/imgproc/imgproc.hpp>' E- {' U7 ]8 J* b8 `
#include <opencv2/imgproc/types_c.h>: F0 {/ @2 O* I5 }' T
#include <stdlib.h>, D0 U' d3 `) q- h. V' ?
#include <stdio.h>
' {7 T/ p8 X! i7 y F8 c3 [0 @#include <opencv2/highgui/highgui_c.h>
" o6 s1 W* Q2 Q#include <math.h>
" S$ Z( A: F; N/ C: U! e6 j: a' J//#include "iostream"% h0 d4 }0 Y* \& z v* {' w' h
//#include "cv.h"
1 |& C/ H+ {: \" E//#include "highgui.h"% m+ W; }) y# ~( ]2 A- J% A' i
//#include "math.h"9 z; F2 _$ h4 Y3 H3 K
using namespace cv; //命名空間CV4 e9 ^2 {. A! {
using namespace std; //命名空間 std" J' I, t+ L: T* T$ D0 l/ b
# z' L# T4 ~/ v( D) z: z
int threshold_value = 225; //啟動(dòng)程序時(shí)的閾值初始值,因?yàn)?27能夠完全提取輪廓,所以設(shè)置為225,實(shí)際上227也可以。
" ~9 D; q0 `0 qint threshold_type = 3; //啟動(dòng)程序的時(shí)候閾值類型,默認(rèn)的為不足部分取零, ~2 J+ n8 j1 h9 P4 t a% p
int const max_value = 255;# P0 e) e* G1 ^. C
int const max_type = 4;
3 D; E+ [! u: D( R/ Mint const max_BINARY_value = 255;
7 I* O% q- C6 L! i3 k& _. `( I' Y# U! L1 }8 h/ X
CvFont font;0 R8 T8 @% o7 e3 t; c9 e* d+ {! m$ ]
uchar* ptr;' _7 C$ a! Q" r7 L0 B
char label[20];7 T6 X$ z: [+ b3 X- w( T* o& ~( r
char label2[20];/ i; y: x9 Y: V- d' F6 d: F
/ m. i) \' z, I8 A: Y
Mat src, blured, src_e, src_gray, dst; //類定義幾個(gè)圖片變量,dst是最后轉(zhuǎn)化閾值之后的圖片,src.gray是灰度圖2 O3 m5 F8 Q9 K
//在C語言中“char*”是聲明一個(gè)字符類型du的指針,定義數(shù)據(jù)類型,char可以定義字符zhi有變量、數(shù)組、指針。dao3 P" E, p9 E: R/ p
//例如:char *string="I love C#!"
& b3 f# o: ?' [+ A& ^ //定義了一個(gè)字符指針變量string,用字符串常量"I love C#!",對它進(jìn)行初始化。對字符指針變量初始化,實(shí)際上就是把字符串第1個(gè)元素的地址(即存放字符串的字符數(shù)組的首元素地址)賦給string。*/; G) b R" w x. n5 k/ \0 w3 Y
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蝕的參數(shù)
( V m: |% j8 u- t& y& A5 ~- hchar* window_name = "閾值演示程序20201121";4 l7 p6 q2 F% x9 h/ E' d
char* trackbar_type = "類型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
W: ]3 _5 w' T; xchar* trackbar_value = "數(shù)值";
6 T% ^4 Z$ ]8 G% K. f: u/ _. |- o( A" ~; ?+ `0 ~( @& i* d
/// 自定義函數(shù)聲明; T; R/ N( K2 N3 t4 W
void Threshold_Demo( int, void* );$ R% g G% O% E) n0 T2 E! m3 ^
+ s6 y3 A8 N6 R& c' ~$ J9 T/**
$ s1 Z2 l. x' k( Z) d. w6 J4 { * @主函數(shù)
3 b. R# u9 U& i+ e1 G0 @* n */' B! K H6 J! y" {, j+ x! y9 Y# Z
int main( int argc, char** argv )
9 h }: }; Q$ ]3 P! D{
# r6 D: S, I6 W# K9 m /// 讀取一副圖片,不改變圖片本身的顏色類型(該讀取方式為DOS運(yùn)行模式)4 V: Y+ A- u! L
src = imread("121.JPG", 1); //目前還未使用攝像頭拍攝照片,暫時(shí)以直接讀取文件的方式來測試。/ @, ], I: M6 {/ c
erode (src, src_e, element); //對圖片進(jìn)行腐蝕,參數(shù)可調(diào),正常為9或者10,過大則造成輪廓過小,應(yīng)該再進(jìn)行降噪 ^* F- o# L7 r: W
blur (src_e, blured, Size (3,3));//3*3內(nèi)核降噪0 }1 A* k: u* e! w. n5 A
imshow("腐蝕和降噪后的圖片", blured); //顯示圖片
6 ~4 L/ ]: V; E& s0 s& r int width=blured.rows; //圖像的行列
) G2 _2 G8 J- i int height=blured.cols; //圖像的列數(shù)量
9 ?, {& M( I: q$ L. K- p cout<<width<<endl; //顯示行列的具體像素4 l5 I/ ?2 @6 w; D
cout<<height<<endl;
/ K! C: W1 _3 p int a[500][1]; //定義整型數(shù)組,后面的1應(yīng)該可以不要的. X, p9 J! x. }0 V. S* z3 d
int b[500]; //設(shè)置一維數(shù)組,用于判斷曲線的切線斜率
! s c+ E+ X0 E Y- K/ N1 n) V
6 y& ], F7 [! n1 l, ~0 z9 Z /// 將圖片轉(zhuǎn)換成灰度圖片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時(shí)直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過一定閾值的點(diǎn)提取出來,并找到該點(diǎn)的坐標(biāo),然后記錄該點(diǎn)坐標(biāo),用于后期的比對
" y8 y8 O: l: Z; a5 M2 b7 x cvtColor( blured, src_gray, CV_RGB2GRAY );
. o) W) c8 a1 N- E# J- i: r( f* L: h* h9 ^8 l
/// 創(chuàng)建一個(gè)窗口顯示圖片% I- Q: U! \( E+ d) m9 T
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
1 K6 F8 q' X( z! s
4 l6 y; u8 A y& l8 p1 d( j /// 創(chuàng)建滑動(dòng)條來控制閾值
' x# _0 O# B, K% _; a createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);& k* P- s- [1 d7 A/ N8 N
: T5 y0 G; `$ ?
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo); u* L" B% [ [1 {: ^% [. E3 ]
( }2 Y, Y& M$ _6 Y9 ~
/// 初始化自定義的閾值函數(shù)4 B5 a n8 H8 t0 S3 ^: G- }8 B3 z' ?
Threshold_Demo( 0, 0 );/ o3 S( [3 P8 f c7 w! i
# ]; `; {( p9 a" T& m+ Y% l# p // Mat img=src; //暫時(shí)無用8 S) O. S; ~1 T, y8 D ]- O
//imshow("轉(zhuǎn)化之后圖片",dst);) Y/ G; O1 Z2 F7 b0 u4 K' Q
- r% A) f/ Q/ X
//遍歷圖片的每個(gè)像素點(diǎn),當(dāng)像素點(diǎn)的閾值大于227時(shí),將最左側(cè)的該像素地址保存在二維數(shù)組中,在該行之后的像素點(diǎn)拋棄,如果閾值低于227,則向下遍歷至該行末,然后從下一行開始對像素進(jìn)行比較
# Q5 H+ Z' F- S1 G$ X6 ^+ Y
5 @6 d+ p) W8 m. G5 B6 P//Mat BW = imread(imgName);0 D; o: _9 Z$ A+ O
//int value = BW.at<uchar>(191, 51);
) _3 G, S- R# k0 P. { int width1=dst.rows; //處理之后圖像的行列
( P3 N: y6 ~0 H1 k. X$ M int height1=dst.cols; //處理之后圖像的列數(shù)量
+ G4 B. t- u. {3 s( T" g1 x2 M0 a* b' A
for (int i=0 ; i<height1; i++) //從第一行開始 應(yīng)該從最后一行開始向上檢索,這樣可以減少計(jì)算量,一旦出現(xiàn)與之前曲線K值相反的方向,則確定是拐點(diǎn),不用再考慮,但是要考慮出現(xiàn)切線斜率始終是減少的趨勢,這種情況下往往是蒜尖
6 K! F# @* Z* p- V, w {5 y j: P: z: n" ?6 @$ q
for (int j = 0; j < width1; j++) //從第一行的第一列開始
1 d1 }+ ^* u+ p- f4 | {
. o1 l& i4 c1 C //int index = i * width + j;
( Z0 X/ Y- h! x0 S8 n2 n int value = dst.at<uchar>(i,j); //讀取給定坐標(biāo)處的像素值: J1 v* o Z" U( R% j, o
//if; //像素值4 c6 K3 M* h0 {; _ `( v5 j& c/ {" `, x
//int data = (int)dst.data[index];" n( ~' L9 x j8 ] F2 J* Q
if ( value >200) //如果像素值大于某個(gè)數(shù)值,則將其地址記錄在數(shù)組內(nèi),且僅記錄首像素,后面的舍棄
2 e% `2 B; _! M6 D4 i. O {
; z0 [) p, g- n a[i][1]=j; //數(shù)組值等于列數(shù),便于后期對比
1 B# i. L+ I& ~# M; a, u0 \) `. o //cout<<i<<" --- "<<j<<endl; //i為行數(shù)- C6 L6 m( ?- _* f' S
//cout<<i<<" -坐標(biāo)-- "<<a[i][1]<<endl;- e$ d% m U1 ]# K0 ^
if (i>1)0 s1 g$ O s. k+ K2 F
{ //11
\0 r4 Q4 i0 o" n/ }% ~: b1 G if (a[i-1][1]<a[i][1]) //如果第一行中大于某個(gè)閾值的像素地址與下一行相比靠右,也就是列數(shù)比上一行要大,則說明該曲線向左側(cè)傾斜,說
: ^9 [$ Z, V v //明是底部,如果曲線向右側(cè)彎曲,則是蒜尖 (之所以用i-1,是因?yàn)榭偛荒芎蜎]有像素的地址對比,所以必須向后取值)2 R: K/ F7 U: T% {
{
l! L, B7 w2 u, i b[i]=0; //因此,當(dāng)下一行的地址比上一行的地址小,則用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。
6 q4 ~$ x2 \7 W2 A& J* k }
G0 c3 q: ~: p5 d& ^" t, P else if (a[i-1][1]>=a[i][1]) ! L& d" C' w' c p& W2 y7 V
{/ v" ?/ E7 [/ N
b[i]=1;
6 [# p3 @: w# ?+ e6 w }7 J9 h: W( D; H. `
+ [6 P; a! q+ S8 U cout<<i<<" -標(biāo)識(shí)符-- "<<b[i]<<endl; " p; l5 w, p5 d7 r" m* i- l( s
//cout<<j<<endl; //j為列數(shù)
1 }) M) U* P- d } //11: T3 o; J" k3 c* \9 J0 {- }) h2 }
$ y- E& D. g# h8 O& f! K& x
( k6 _# V5 g/ r' F" t- {
break;
; q0 e) _) e; l }5 ?4 B0 k8 \& l' e: i" l) ^
}1 R) j' e7 q+ |
}
0 m$ I" J, a$ J1 y8 {- g //開始對b數(shù)組進(jìn)行分析,確定是否為頭尾(但是需要對曲線進(jìn)行圓滑處理)% O5 m8 y0 A- |
for (int i=0 ; i<height1; i++) //對數(shù)組b進(jìn)行遍歷,檢查是否存在誤判的問題
! y) c5 B* U" V* P& r( l* L //尋找拐點(diǎn),找到用于判斷的后段曲線的拐點(diǎn)
, `. Z) Y. F; j, @ //對圖形進(jìn)行圓滑處理,除了最大的拐點(diǎn)之外,盡量不要出現(xiàn)折線% y |. \# K: M
5 [# E+ I5 }% t/ D& e; G z
! J: Q# p$ j7 U% z6 |
3 A3 Q& n* b' t* V+ g& p& F$ P! k // int width=dst.rows; //圖像的行列
* |6 Y! D# G% c6 }/ d6 [) j //int height=dst.cols; //圖像的列數(shù)量3 ]1 ^, h/ U, O/ O: P
cout<<width<<endl; //顯示行列的具體像素
. ?0 N9 ^4 O! H! J cout<<height<<endl;
8 Y4 a l3 O% u( X7 V8 @ //for (int i =height1-5 ; i>20; i--) //對收集的坐標(biāo)數(shù)據(jù)進(jìn)行分析
: o) r# T5 K S w$ X, ~, b+ v
0 m1 {4 L( s4 a8 _ // 等待用戶按鍵。如果是ESC健則退出等待過程。: q! d4 t. d/ p% V M
while (true)
b( o* }( E' B o {! Q2 ^, S* x+ R) i, R; i( V( B
int c;2 P3 E' c1 H" R) {. D$ |! I! n
c = waitKey( 20 );
) Z6 k1 x3 f* Y5 U if( (char)c == 27 )
2 f, t% B# ^7 ^2 ]" a2 s5 D2 i! w { break; }
3 Y& _$ _! }/ R% O2 ^) b$ O }
) x+ n+ q- H, ]5 O' @
/ G9 s" E+ x* [) Y1 E" T& b- E' s* R$ P}! J9 u% o! v) d5 F- T
/ F7 Y/ U5 \1 b0 a7 K9 ~$ E
. F5 I0 [" j3 h4 _' A# e
/**0 s4 g7 ^$ d0 n# F/ i& h0 }
* @自定義的閾值函數(shù)
$ n1 N" E1 y7 s, y9 d) r2 H9 y. ~ */8 l9 _# `$ o o, h
void Threshold_Demo( int, void* )& c% r( Q- _4 d. W& Y& v
{, E0 t/ j7 |7 X5 n
/* 0: 二進(jìn)制閾值
0 d* N, g) x1 y8 J. c1 F 1: 反二進(jìn)制閾值
8 j9 J* I8 }' m, d3 O+ h 2: 截?cái)嚅撝?br />
8 S. x+ r: z* c6 d* c# U) j 3: 0閾值6 Z" C, k! @. g: \5 m6 q
4: 反0閾值" K+ v# j' L1 w( \4 M
*/
5 O8 _' ?4 t/ J0 @7 J% o& u1 o4 }7 L2 y9 O( V( K9 W5 N; s3 x
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );; U$ B9 y$ |8 {6 C: N
" I& {* |1 o- g2 Q9 s
imshow( window_name, dst );
$ k2 F' V; A6 t}3 o: T% @! E0 a* n& h3 d
* k: T' W* z2 P+ ~
5 A( e. X2 q* z2 A' G* f
( w1 G$ g0 S- R; F# d4 x1 w& p6 g/ z$ J5 N
4 i( w, }, Z' ?! t/ A/*. k F ~) F- n6 y+ F9 L# m3 x, W
void main()
; D$ A1 K/ S9 O: M8 u) N2 X* N{
2 E: `" _! ?7 M+ ]* E
' k" e4 c+ ^4 I* H: Y( L6 r //讀入彩色圖像 單通道圖像(CV_8UC1);CV 8位未指定的1通道的圖像,backImg是單通道灰色圖
6 M4 _; a' |1 u1 ?
! x7 c; h: r8 d! F4 k //Mat img = imread("fruits.jpg");
. R( J. S/ k6 r, O3 @% }2 U6 L Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時(shí)直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過一定閾值的點(diǎn)提取出來,并找到該點(diǎn)的坐標(biāo),然后記錄該點(diǎn)坐標(biāo),用于后期的比對% d( ^) _8 D* U5 _
imshow("灰度圖", img);# g9 H- W& J4 Z
//確定圖像的尺寸,行列,+ j" U$ h0 u; k$ T. a% A: y8 V; w
int width=img.rows; //圖片的變量名加上行列,就是行列的數(shù)據(jù)
1 v/ ?4 J" }. R( |, b- E$ A int height=img.cols;' ?# F2 a3 P' M* s# z' ~5 o& i4 q
cout << width << endl; //顯示行列的數(shù)據(jù) 本圖片已經(jīng)用358的像素值裁剪了,所以形成的就是高寬都是358; M" f2 S2 @/ @
cout << height << endl;
2 M! r" J7 O- k: v4 [3 N //定義一個(gè)二維數(shù)組,a[i][1],其行數(shù)等于圖像行數(shù),列數(shù)就一列,用于記錄圖片上像素的亮度超過某個(gè)閾值的像素所在的列數(shù),用于下一步的對比。
+ e5 W' a- W0 y; x! I; B& s int a[358][1]; //確定一個(gè)358的二維數(shù)組7 o2 c# [" H6 W6 a+ a7 D
, \ q0 f+ j! D6 v; \& f
//int height = backImg.rows; //backImg是圖片變量名
6 j" M' h9 r0 v+ Z7 Y4 E; T//int width = backImg.cols;
$ v/ a9 X; }. |: h0 C0 tfor (int i = 0; i < height; i++). T$ c$ M7 u) _0 `( o0 L
{ F/ c# E4 Q3 G2 K$ K% D
for (int j = 0; j < width; j++)
: _' F( {) }( _- L0 w {
" {; B- \ z* A' o) e int index = i * width + j;1 U: p. r0 N5 g. W3 L2 ]
//像素值% D' R4 L, b0 |# F k$ H9 z; v
int data = (int)img.data[index];- ~ E$ V! E# p" e% |1 z, H( y" E# g
}
& J& B b0 E8 R/ |2 M$ e, D }& o9 a# [( d. p3 w4 a6 e
waitKey();; d" N0 j, s" _# M; E
}
$ C1 X. s2 ?/ W' `& h*/ |
|