|
#include<iostream>: E _& Y9 Y* v( S5 W+ C
#include<opencv2/core/core.hpp>/ f+ J/ s+ `8 a( t$ Q5 X8 e
#include<opencv2/highgui/highgui.hpp>! s0 O" u5 b) q7 t4 g) b
#include <opencv2/opencv.hpp># Y$ A" J: A3 K: m" F# T+ _% i
#include <opencv2/imgproc/imgproc.hpp>" T& R! H0 M0 K5 Z8 h- C% K
#include <opencv2/imgproc/types_c.h>
0 ], _$ A5 I: Q: f#include <stdlib.h>
$ Y g0 f7 C. d) A; ^#include <stdio.h>
# F% E" Y. H4 z$ M7 d& U#include <opencv2/highgui/highgui_c.h>
+ c3 v; S% B& m. f. Y% J9 p#include <math.h>: }- D; }7 b0 p* W! F( ?9 y) l/ X
//#include "iostream"* }4 [1 W' x+ ?* j! K7 r
//#include "cv.h"
- o9 K) _. G- X. G6 b) b//#include "highgui.h"& P# v5 l6 Q' i6 D
//#include "math.h"# S! H5 _- T8 J
using namespace cv; //命名空間CV8 C/ U; l: b% L) e
using namespace std; //命名空間 std
2 v D. d8 z+ b z" R
0 n1 q2 I4 I* c5 Oint threshold_value = 225; //啟動(dòng)程序時(shí)的閾值初始值,因?yàn)?27能夠完全提取輪廓,所以設(shè)置為225,,實(shí)際上227也可以,。+ o2 F9 G3 T* j; H3 j0 k
int threshold_type = 3; //啟動(dòng)程序的時(shí)候閾值類(lèi)型,默認(rèn)的為不足部分取零0 t! s1 R F1 j
int const max_value = 255;
# a) n$ L8 e1 R! wint const max_type = 4;
4 D! v: X$ }* g) M' C$ @" F5 tint const max_BINARY_value = 255;
) b# J# C7 k8 T z/ u' r% Z! r5 g" k l! {; R
CvFont font;8 r! w3 t6 v) W. n3 F2 O' ]9 a
uchar* ptr;
0 w8 i0 S! P8 B1 ~% x* n char label[20];
! V' F5 z3 Z) ~0 _1 ?! {: M char label2[20];& `1 u& t5 N5 d2 S! I
" b+ }! c3 Z0 I3 y
Mat src, blured, src_e, src_gray, dst; //類(lèi)定義幾個(gè)圖片變量,dst是最后轉(zhuǎn)化閾值之后的圖片,,src.gray是灰度圖3 Y3 h) s. T+ S7 g+ u/ }. q$ d
//在C語(yǔ)言中“char*”是聲明一個(gè)字符類(lèi)型du的指針,,定義數(shù)據(jù)類(lèi)型,char可以定義字符zhi有變量,、數(shù)組,、指針。dao
! }, L8 J; f! P //例如:char *string="I love C#!"( v1 O) l* \9 @# ]8 c& `& j4 l
//定義了一個(gè)字符指針變量string,,用字符串常量"I love C#!",,對(duì)它進(jìn)行初始化。對(duì)字符指針變量初始化,,實(shí)際上就是把字符串第1個(gè)元素的地址(即存放字符串的字符數(shù)組的首元素地址)賦給string,。*/
! z, I4 I& [8 t+ @+ i' j) c' [Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蝕的參數(shù)' b; g/ \. \( s
char* window_name = "閾值演示程序20201121";
% w6 b* W% h0 |8 Kchar* trackbar_type = "類(lèi)型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
4 H6 b! ?2 {) ^3 [$ R, f& x5 [$ H. rchar* trackbar_value = "數(shù)值";5 I; [; l; i8 [! L
2 g6 M( F+ A$ _( y/// 自定義函數(shù)聲明
% l* I2 V; q- S. ^: j8 T) v' l4 Lvoid Threshold_Demo( int, void* );
# q. F$ ^8 W7 U. ? @
! n) C' H- l# ~" |7 A/**# L9 F5 E$ O3 ^/ |
* @主函數(shù)
; W# m% Y; A$ p, X! e */
' C! F& v! Y2 S( q8 J- qint main( int argc, char** argv )( ]' ?# `4 E. l. V7 R" J% z, s9 p
{
0 f: C$ K( J1 F% a- h8 |# p /// 讀取一副圖片,不改變圖片本身的顏色類(lèi)型(該讀取方式為DOS運(yùn)行模式)6 D# p# x% y c1 L$ n: a
src = imread("121.JPG", 1); //目前還未使用攝像頭拍攝照片,,暫時(shí)以直接讀取文件的方式來(lái)測(cè)試,。- c Y7 j! V4 y+ `, {. o3 i
erode (src, src_e, element); //對(duì)圖片進(jìn)行腐蝕,參數(shù)可調(diào),,正常為9或者10,,過(guò)大則造成輪廓過(guò)小,應(yīng)該再進(jìn)行降噪% {, m! v- k) |
blur (src_e, blured, Size (3,3));//3*3內(nèi)核降噪
% d& ], w8 d: M' } imshow("腐蝕和降噪后的圖片", blured); //顯示圖片
6 z2 j! l: o, }. d7 E int width=blured.rows; //圖像的行列1 {1 u+ k/ m* O0 C8 w
int height=blured.cols; //圖像的列數(shù)量$ A9 l7 |" v) d* F$ e
cout<<width<<endl; //顯示行列的具體像素
' W0 x' |" Q: m" y cout<<height<<endl;
+ K' i& Z Q7 s, o" P% T) M int a[500][1]; //定義整型數(shù)組,,后面的1應(yīng)該可以不要的
6 j5 ?6 }0 r& t K int b[500]; //設(shè)置一維數(shù)組,,用于判斷曲線(xiàn)的切線(xiàn)斜率
' y$ Q1 x( ~) M# u0 h
4 }6 a2 E+ V6 Y+ ?- o. u4 x1 x/ c3 ~ /// 將圖片轉(zhuǎn)換成灰度圖片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時(shí)直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過(guò)一定閾值的點(diǎn)提取出來(lái),,并找到該點(diǎn)的坐標(biāo),,然后記錄該點(diǎn)坐標(biāo),用于后期的比對(duì)6 {; d5 W, ?* s& Q, V" g
cvtColor( blured, src_gray, CV_RGB2GRAY );
! o1 b7 |, I5 R6 @, t: Q; Y# H3 B3 b! y- z
/// 創(chuàng)建一個(gè)窗口顯示圖片
7 ^4 Y ]3 r5 M- u7 X k J namedWindow( window_name, CV_WINDOW_AUTOSIZE );
% r6 X) \0 a8 N. w
M( T4 i. ^8 l& ?9 G7 } /// 創(chuàng)建滑動(dòng)條來(lái)控制閾值
" X9 g9 V) _/ ^' i% {- E; R createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
8 d* C3 x, U( W6 n1 d8 k# f
8 P' d ?; S( E2 u createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
) c! c$ {) N- q9 r. \/ |4 c* F' P; N+ Y- x' `* v; {6 [
/// 初始化自定義的閾值函數(shù)
. Z) U- w; U% l( f5 f, N3 s Threshold_Demo( 0, 0 );. b2 M. J# v/ i/ Y4 j: P
: {( k% M, A/ `: O% i // Mat img=src; //暫時(shí)無(wú)用: Q6 e) O ]$ u
//imshow("轉(zhuǎn)化之后圖片",dst);
1 `' f5 u1 q+ h6 g8 A- M j w' [& f7 p
//遍歷圖片的每個(gè)像素點(diǎn),,當(dāng)像素點(diǎn)的閾值大于227時(shí),,將最左側(cè)的該像素地址保存在二維數(shù)組中,在該行之后的像素點(diǎn)拋棄,,如果閾值低于227,,則向下遍歷至該行末,然后從下一行開(kāi)始對(duì)像素進(jìn)行比較' O8 e8 N0 c7 D! M
6 E6 B6 I* y: y& X6 t: v7 n1 q2 P//Mat BW = imread(imgName);
3 u2 C1 r& v2 n8 \//int value = BW.at<uchar>(191, 51);
) _& I/ w& C- G int width1=dst.rows; //處理之后圖像的行列3 B0 l8 d d3 q1 D( `4 n3 b
int height1=dst.cols; //處理之后圖像的列數(shù)量/ X$ S: k4 q' p! c* h/ U
: B. b; f9 ?! E3 g1 C for (int i=0 ; i<height1; i++) //從第一行開(kāi)始 應(yīng)該從最后一行開(kāi)始向上檢索,,這樣可以減少計(jì)算量,,一旦出現(xiàn)與之前曲線(xiàn)K值相反的方向,則確定是拐點(diǎn),,不用再考慮,,但是要考慮出現(xiàn)切線(xiàn)斜率始終是減少的趨勢(shì),這種情況下往往是蒜尖9 }! u. D# D& v( ]
{4 ], H0 T% I6 d3 Q4 m3 x
for (int j = 0; j < width1; j++) //從第一行的第一列開(kāi)始$ G/ Y" ?$ L. ^# x/ m/ R
{
" i" ]1 k' N! @& Q( K- k //int index = i * width + j;
4 Q; V! v p: z int value = dst.at<uchar>(i,j); //讀取給定坐標(biāo)處的像素值. O0 F. w" K6 |5 ~' _# f- J
//if; //像素值
/ [1 J( q0 v; b/ H Y4 Q' p) s% j //int data = (int)dst.data[index];' a/ i- D" Z0 u6 {! O( Z# |8 d/ B
if ( value >200) //如果像素值大于某個(gè)數(shù)值,,則將其地址記錄在數(shù)組內(nèi),且僅記錄首像素,,后面的舍棄6 p& f) I* q. }* D- y' } H
{ & n' g" V; `! v8 ~. f( @' `
a[i][1]=j; //數(shù)組值等于列數(shù),,便于后期對(duì)比
# ~% N- g+ p. T- F9 A: j //cout<<i<<" --- "<<j<<endl; //i為行數(shù)
* r" E% n- ?2 r9 P4 O5 b //cout<<i<<" -坐標(biāo)-- "<<a[i][1]<<endl;0 m* o# D- A; v6 `/ s* `2 b
if (i>1)( M# y( t5 k8 X' |
{ //11, `8 A8 P. F% C0 L
if (a[i-1][1]<a[i][1]) //如果第一行中大于某個(gè)閾值的像素地址與下一行相比靠右,也就是列數(shù)比上一行要大,,則說(shuō)明該曲線(xiàn)向左側(cè)傾斜,,說(shuō)
! F( m3 Y! R6 t //明是底部,如果曲線(xiàn)向右側(cè)彎曲,,則是蒜尖 (之所以用i-1,,是因?yàn)榭偛荒芎蜎](méi)有像素的地址對(duì)比,所以必須向后取值)
: G! n% p+ y6 M+ Z% k { $ \6 T, S) Q' o) r
b[i]=0; //因此,,當(dāng)下一行的地址比上一行的地址小,,則用1表示,如果下一行地址比上一行大,,用0表示,,1是蒜尾,0是蒜尖,。: x* Y8 x6 N8 Q ~
}
5 w; G1 Q4 x- O else if (a[i-1][1]>=a[i][1])
# `. L( {% D! ]' r9 J {
: R) ?7 |1 b5 G b[i]=1;
& X/ [: y5 {+ L" b9 o7 v }
; O) N: t8 G/ H, n# x+ _' j- U: ?8 I3 ]: ?
cout<<i<<" -標(biāo)識(shí)符-- "<<b[i]<<endl; ( k9 w ~8 F x! R9 F7 H
//cout<<j<<endl; //j為列數(shù)9 {8 b7 `# j* A6 v* g
} //11* m7 V7 y- |1 W& L, O* d" x
' m" c6 V3 A: | c
- r. K- b! t* y0 B: v break;
/ l$ K) u3 C; z- b }
! W1 T, {. }) Q4 K8 S W5 U }
/ j1 L7 Z4 K: r: a- ?% ] }' e4 [4 f$ Q8 u: w7 E3 \( {6 k
//開(kāi)始對(duì)b數(shù)組進(jìn)行分析,,確定是否為頭尾(但是需要對(duì)曲線(xiàn)進(jìn)行圓滑處理)! S* b) C/ S3 _( _8 D
for (int i=0 ; i<height1; i++) //對(duì)數(shù)組b進(jìn)行遍歷,檢查是否存在誤判的問(wèn)題. l; f7 t4 Q, w$ p: ]. l
//尋找拐點(diǎn),,找到用于判斷的后段曲線(xiàn)的拐點(diǎn)$ a$ e; D: m \
//對(duì)圖形進(jìn)行圓滑處理,除了最大的拐點(diǎn)之外,,盡量不要出現(xiàn)折線(xiàn)
s: r% m; Y. h7 s6 k " f* U# s, h1 [! ]! }
& y- L. C/ U. ~9 `
0 r- Q: {4 x4 } // int width=dst.rows; //圖像的行列6 |% K% l; w5 V2 w# V
//int height=dst.cols; //圖像的列數(shù)量$ k- w/ J- [3 }% o' S3 x9 f$ X
cout<<width<<endl; //顯示行列的具體像素
: D3 c/ X& r8 j& C( ?: c4 H cout<<height<<endl;
4 I V9 E! ^% n+ { //for (int i =height1-5 ; i>20; i--) //對(duì)收集的坐標(biāo)數(shù)據(jù)進(jìn)行分析
B& [, b5 y8 v! s- `& ]: x % x3 Y( e; n1 L2 x4 h, Z9 s
// 等待用戶(hù)按鍵,。如果是ESC健則退出等待過(guò)程。9 \# l+ n6 Z( o: |. @8 W# T
while (true)
0 m- M) ^' a% q3 }; x+ V {
+ A5 |7 H4 G0 y, E1 h+ N5 p int c;
4 Q7 G' ?. [" v" g$ @( ` c = waitKey( 20 );
* e6 S) K$ e4 m; F( t if( (char)c == 27 )
7 L) I- z7 t3 F { break; }: M7 q1 W0 d) @0 x
}& m" j5 q; W* s9 E% }
% E& {. `7 {$ L3 t3 j5 a" [ l/ ?6 ~}6 \1 n8 p, b( k8 |: f6 B* C
, \ q8 P: \7 M: |: @
+ L8 b3 I9 O; }8 h/ u/**$ K; }5 `, O, O
* @自定義的閾值函數(shù)
" c+ l; X$ h0 ? */
; z1 u, K, b) A7 E+ l& E0 avoid Threshold_Demo( int, void* )
) c+ M' O Z9 i/ m+ ~{
+ B' m* u9 q+ |- O" ?$ D8 `1 L /* 0: 二進(jìn)制閾值
I# d( w2 f# `. P$ s' Y0 G 1: 反二進(jìn)制閾值4 g u/ C2 ]7 C4 U8 ]2 F( _4 W1 e, ^
2: 截?cái)嚅撝?font class="jammer">5 k& p+ D$ p8 N4 m) R0 t6 h2 n: Q2 `
3: 0閾值
4 C9 [: W% G Z! e 4: 反0閾值& a$ V6 J. J- D# \0 d; V
*/( x% y( M6 G; X! @$ N0 ]' E$ X+ W
' B7 e8 R( c& m) p) A6 U& T threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );
* q: F: o. K' V" v8 m+ g4 R% j. A& E8 i. j& P
imshow( window_name, dst );
8 ^0 p+ Y7 W& f0 }$ V0 U}) ~: I6 Q3 H( J. Y! ]; k. R; h
- v# F. |/ i7 J q" p3 D$ Y
: H9 P6 c" M V. n8 d6 `
) u* ]9 R) n7 ?
6 K" H! G; A0 Z+ i- }$ I" \
8 w0 j8 J# O7 P4 `. d! N/*
2 v' \* Q! G$ { d1 n% J- N* V; J1 E+ O) J' Dvoid main()
% D' L% q* ^ Z, c{
" P/ ? \. t. V h8 E7 S3 K4 H
% j' D/ S6 r9 |5 V" C9 }, U& O" w: p //讀入彩色圖像 單通道圖像(CV_8UC1),;CV 8位未指定的1通道的圖像,,backImg是單通道灰色圖3 i( m u+ ^# d+ p
4 s% E" y2 F5 T9 P) i; k. S //Mat img = imread("fruits.jpg");
! T. Y8 L. i ?, {9 G& D6 u Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時(shí)直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過(guò)一定閾值的點(diǎn)提取出來(lái),,并找到該點(diǎn)的坐標(biāo),,然后記錄該點(diǎn)坐標(biāo),用于后期的比對(duì)2 z" o2 y2 j2 c+ ]! }: U3 W
imshow("灰度圖", img);* j/ x% l0 Q3 ~0 n
//確定圖像的尺寸,行列,,
/ l; O9 V2 ]% q* D, j) L; T int width=img.rows; //圖片的變量名加上行列,,就是行列的數(shù)據(jù)7 ~* k7 k- [ v: Q4 n7 L( S- _
int height=img.cols;# n& Z3 o- F* N h, R% e
cout << width << endl; //顯示行列的數(shù)據(jù) 本圖片已經(jīng)用358的像素值裁剪了,所以形成的就是高寬都是3587 c! m/ x" g. H
cout << height << endl;$ `) z. ~6 @" P; L
//定義一個(gè)二維數(shù)組,,a[i][1],其行數(shù)等于圖像行數(shù),,列數(shù)就一列,用于記錄圖片上像素的亮度超過(guò)某個(gè)閾值的像素所在的列數(shù),,用于下一步的對(duì)比,。; w. y& ]6 E' z7 `) e/ b0 Y, ~
int a[358][1]; //確定一個(gè)358的二維數(shù)組
' c; i3 L; a' d: |/ k! r5 q
9 Y1 A. C/ W* _9 X6 ~4 r//int height = backImg.rows; //backImg是圖片變量名
/ y& C, ?7 x/ e2 E3 `( ~( ]8 g//int width = backImg.cols;
7 [0 T6 O. I, Z! ?2 y7 J( Tfor (int i = 0; i < height; i++)
5 R: |. y! m. O: |) F, K {! C7 s1 G% r/ \( W- ^4 n! h
for (int j = 0; j < width; j++)- E, r* @* n4 G3 H( u
{
& a: G7 d) `) [. f7 n8 W" T int index = i * width + j;3 A! M9 y) t/ O9 o0 [! s$ D5 m
//像素值
4 K+ p# X9 ]) ^3 `, d& V; H int data = (int)img.data[index];" [: u) T8 N9 z4 N7 N6 K6 P7 F
}$ {6 b7 L/ z9 I8 S; D0 x9 `. v P/ A
}
! R! t& N/ x$ u5 O4 L5 r waitKey();1 n2 ? C$ O1 J5 Z6 \
}% d: b/ n5 k/ ]- W7 }
*/ |
|