|
#include<iostream>/ K3 Q0 z3 B% H: s+ K
#include<opencv2/core/core.hpp>
. p/ r1 a F% o7 }#include<opencv2/highgui/highgui.hpp>
# ^9 E2 `5 w9 P9 G# ]#include <opencv2/opencv.hpp>
& o5 J, ^/ Q/ S" K8 E1 v#include <opencv2/imgproc/imgproc.hpp>
2 R5 S, V9 Y$ u/ K5 }#include <opencv2/imgproc/types_c.h>
) H( n9 j8 ]2 t#include <stdlib.h>3 x U- E# S8 m
#include <stdio.h>2 B1 v+ B# G, k
#include <opencv2/highgui/highgui_c.h>
3 |2 |7 E# G/ {' U) g$ v#include <math.h>
I2 Z: I( y( w; L6 t- t2 N/ `//#include "iostream"5 M9 C5 o' ^7 S# y
//#include "cv.h"5 M, r' K6 L1 t
//#include "highgui.h"
; t0 ^6 R. Q4 R, a) h//#include "math.h" e4 h% Y3 l8 a6 I2 M* h
using namespace cv; //命名空間CV
5 N) p) j+ b {: ]. E9 _7 e1 Pusing namespace std; //命名空間 std& X& g, e$ j& v8 d$ e9 R- V! U
7 J, M3 W+ Z# [' Q8 H# f [! d2 d
int threshold_value = 225; //啟動(dòng)程序時(shí)的閾值初始值,因?yàn)?27能夠完全提取輪廓,所以設(shè)置為225,實(shí)際上227也可以。/ O2 u! T# @$ K1 R/ [
int threshold_type = 3; //啟動(dòng)程序的時(shí)候閾值類型,默認(rèn)的為不足部分取零% E6 _/ l) w, N" _9 z6 _: l
int const max_value = 255;. y: Q7 Q( Y1 \, j
int const max_type = 4;
3 U. m4 X1 J& k0 v/ H% u$ [int const max_BINARY_value = 255;* T, ^. o# j. J/ j
0 N5 P0 X& Q9 T* r- N CvFont font;) _9 E, j) [. Y1 \ [3 v
uchar* ptr;
; w3 }. S- V' n! a( U char label[20];
z# D- x0 \5 s char label2[20];5 M* d- C7 }* P+ w- \+ z: O
% y" c# {/ v) h& ?. ?8 r
Mat src, blured, src_e, src_gray, dst; //類定義幾個(gè)圖片變量,dst是最后轉(zhuǎn)化閾值之后的圖片,src.gray是灰度圖3 z/ s6 o$ Q% v4 E6 i
//在C語(yǔ)言中“char*”是聲明一個(gè)字符類型du的指針,定義數(shù)據(jù)類型,char可以定義字符zhi有變量、數(shù)組、指針。dao
7 B" f! i) Q' e1 A( Z //例如:char *string="I love C#!"
: }3 W( \& m2 N7 A- X //定義了一個(gè)字符指針變量string,用字符串常量"I love C#!",對(duì)它進(jìn)行初始化。對(duì)字符指針變量初始化,實(shí)際上就是把字符串第1個(gè)元素的地址(即存放字符串的字符數(shù)組的首元素地址)賦給string。*/# x: n. n( j( _5 V) S
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蝕的參數(shù)
- _- B5 b+ [ Y' G0 n( ~( Rchar* window_name = "閾值演示程序20201121";
1 X) K; B Y7 b/ achar* trackbar_type = "類型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
6 T, b; u3 o9 S1 ]9 Q2 Lchar* trackbar_value = "數(shù)值";
# B1 R6 j% S5 C$ ]
! G* U% b- I0 A) n4 w" S, F& W/ _ Y/// 自定義函數(shù)聲明
( l2 D- A" ~) j5 g9 Q# j+ q6 dvoid Threshold_Demo( int, void* );. G; w) q1 Y; s
8 B d7 Q6 a' _2 \1 j% E' ~
/**
+ p6 o8 [ n; h * @主函數(shù) [2 C6 t0 B: K7 {! m* I
*/% h; r6 C$ k( ?4 b* M; X
int main( int argc, char** argv )/ H* w8 ~6 f, B* ]$ x& _
{8 v; i& t* a2 b* }
/// 讀取一副圖片,不改變圖片本身的顏色類型(該讀取方式為DOS運(yùn)行模式)5 J% `# Y- `3 N# V1 y
src = imread("121.JPG", 1); //目前還未使用攝像頭拍攝照片,暫時(shí)以直接讀取文件的方式來(lái)測(cè)試。
2 ]/ g% D7 V1 s1 |9 j erode (src, src_e, element); //對(duì)圖片進(jìn)行腐蝕,參數(shù)可調(diào),正常為9或者10,過大則造成輪廓過小,應(yīng)該再進(jìn)行降噪
- M7 [9 z& l" R' _: u$ H1 N6 i blur (src_e, blured, Size (3,3));//3*3內(nèi)核降噪
4 M% b. c* W$ `! c2 F7 P: X; h3 f imshow("腐蝕和降噪后的圖片", blured); //顯示圖片
# r8 W1 f6 o' m- j8 [ int width=blured.rows; //圖像的行列
) L: e) _" C) `( K int height=blured.cols; //圖像的列數(shù)量
; G' B6 z9 D$ N8 m! c cout<<width<<endl; //顯示行列的具體像素
, c) A; a- z8 ~% s- c; ?7 M. _ cout<<height<<endl;
8 a& `# }8 a1 F int a[500][1]; //定義整型數(shù)組,后面的1應(yīng)該可以不要的
. n0 n! D8 ^/ n% c int b[500]; //設(shè)置一維數(shù)組,用于判斷曲線的切線斜率# C6 V# W9 ?1 x4 g; Y
9 {! H6 F, j1 ~0 e5 r% A/ d
/// 將圖片轉(zhuǎn)換成灰度圖片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時(shí)直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過一定閾值的點(diǎn)提取出來(lái),并找到該點(diǎn)的坐標(biāo),然后記錄該點(diǎn)坐標(biāo),用于后期的比對(duì)
0 }+ N( H0 u+ t* o0 h: W cvtColor( blured, src_gray, CV_RGB2GRAY );
, l/ c7 G. X: b6 V9 B( l2 f1 y9 f! t8 y! R: L: @% c5 y
/// 創(chuàng)建一個(gè)窗口顯示圖片
4 p1 j+ i/ o& _+ C0 k3 h namedWindow( window_name, CV_WINDOW_AUTOSIZE );0 k b, E" h: ]9 `
6 R ^+ } K) Q5 R3 p: x /// 創(chuàng)建滑動(dòng)條來(lái)控制閾值1 @$ O7 N9 U6 m
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
9 P) x: I2 H! i) ?% e% _' D f6 q1 {5 x6 a# g% }) `9 _
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);0 C9 O" y5 @+ Z' ?* ~
$ W5 ^$ R$ F* _1 Q$ r+ ?) e* j /// 初始化自定義的閾值函數(shù)
) q7 f1 m' m. B- G; K4 Y Threshold_Demo( 0, 0 );6 n& {4 U$ H D# E. d" w1 B" H
% T- {* ]$ x0 c% _ i; t // Mat img=src; //暫時(shí)無(wú)用
+ ?" @8 h3 J4 r* G6 ?5 {6 _ //imshow("轉(zhuǎn)化之后圖片",dst);
; {! e+ Q$ V; v7 T9 W5 f, ^% o( ^$ |! v7 L
//遍歷圖片的每個(gè)像素點(diǎn),當(dāng)像素點(diǎn)的閾值大于227時(shí),將最左側(cè)的該像素地址保存在二維數(shù)組中,在該行之后的像素點(diǎn)拋棄,如果閾值低于227,則向下遍歷至該行末,然后從下一行開始對(duì)像素進(jìn)行比較
" o+ v2 Y$ Q1 k! H- X7 P9 r9 s " ^) |: d6 D- T+ t( o! e6 i% l$ p
//Mat BW = imread(imgName);
( {- m5 H1 Y5 x/ i R; a//int value = BW.at<uchar>(191, 51); I0 B W! I% \* O( t
int width1=dst.rows; //處理之后圖像的行列
. B0 F2 H$ ~" l8 S int height1=dst.cols; //處理之后圖像的列數(shù)量' ^/ `" |: ^" p M# x; |9 d7 O
- x! U: u- U7 [4 v9 `8 V9 H for (int i=0 ; i<height1; i++) //從第一行開始 應(yīng)該從最后一行開始向上檢索,這樣可以減少計(jì)算量,一旦出現(xiàn)與之前曲線K值相反的方向,則確定是拐點(diǎn),不用再考慮,但是要考慮出現(xiàn)切線斜率始終是減少的趨勢(shì),這種情況下往往是蒜尖
: @5 `" z8 N# w! H9 f- ` {$ D8 g9 y8 R& D' V) M
for (int j = 0; j < width1; j++) //從第一行的第一列開始, P! Y. ~$ @+ H/ t2 Y; ]3 w
{
8 t" \% U B4 D6 K' g( _ //int index = i * width + j;
5 F2 r* j6 q* H/ B5 n0 @2 V2 q int value = dst.at<uchar>(i,j); //讀取給定坐標(biāo)處的像素值8 t$ p: Z$ P' N3 x9 T1 g6 m
//if; //像素值' O. H) j2 j7 p( |' Q; c
//int data = (int)dst.data[index];3 G; n9 @/ Z( C$ S, o/ e: a, _
if ( value >200) //如果像素值大于某個(gè)數(shù)值,則將其地址記錄在數(shù)組內(nèi),且僅記錄首像素,后面的舍棄: f: T9 G$ G# y
{
% }5 @7 ^: P# X. p# S( J a[i][1]=j; //數(shù)組值等于列數(shù),便于后期對(duì)比' ~) H- s5 e- K; `4 A) d
//cout<<i<<" --- "<<j<<endl; //i為行數(shù)
, t* ~+ p/ @! Z$ ]1 I- w //cout<<i<<" -坐標(biāo)-- "<<a[i][1]<<endl;
0 M7 i3 r3 u8 j9 z Q7 Y5 V if (i>1)% x* O$ z- N$ e$ u2 |
{ //11$ Y# A# ?7 A( }
if (a[i-1][1]<a[i][1]) //如果第一行中大于某個(gè)閾值的像素地址與下一行相比靠右,也就是列數(shù)比上一行要大,則說(shuō)明該曲線向左側(cè)傾斜,說(shuō) @* L9 z( g3 e8 r
//明是底部,如果曲線向右側(cè)彎曲,則是蒜尖 (之所以用i-1,是因?yàn)榭偛荒芎蜎]有像素的地址對(duì)比,所以必須向后取值)
8 j6 C9 S9 s6 t8 L { 9 r8 V# g( y/ L: c1 o' ~& w
b[i]=0; //因此,當(dāng)下一行的地址比上一行的地址小,則用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。; @0 j' ?3 t8 l3 a% K
}
U6 q6 J1 _. ^! r/ n( u; [( q( v& q else if (a[i-1][1]>=a[i][1])
( c& k2 m; k Q# }% ?2 k {4 r- Z4 x, h* o2 n; z# H4 D8 A A8 {
b[i]=1;. N0 \: N9 {1 N; [, g, a8 c
}: A3 u- |0 e3 [: m7 f
6 S; \) [/ s, f' q cout<<i<<" -標(biāo)識(shí)符-- "<<b[i]<<endl;
7 @! i( v) {8 c' u9 G& Y+ `" Z# f" u //cout<<j<<endl; //j為列數(shù)5 K+ w* h4 f) R* F2 f
} //115 ~6 {2 r/ C! c# V% |% X
, N; Q# x- E* h) H3 m3 h- ^6 [* v8 Z+ _7 A
: }# g/ o' O9 S6 c" B7 P' X break;
% J! J% e$ X; d4 A/ {3 N }
9 l/ b- G( j( Z: ` }
- @1 X# i e. Z" ?0 z% ] }
9 ]& n8 ?: H: y9 @/ W9 S //開始對(duì)b數(shù)組進(jìn)行分析,確定是否為頭尾(但是需要對(duì)曲線進(jìn)行圓滑處理)
% {6 Z7 m M' E) ^$ _9 U- p% b$ Z for (int i=0 ; i<height1; i++) //對(duì)數(shù)組b進(jìn)行遍歷,檢查是否存在誤判的問題
b. ^9 _& D$ ]5 n8 n //尋找拐點(diǎn),找到用于判斷的后段曲線的拐點(diǎn)/ k% C4 @ V7 o. P8 p
//對(duì)圖形進(jìn)行圓滑處理,除了最大的拐點(diǎn)之外,盡量不要出現(xiàn)折線- p0 o! V( U& N% \
7 P4 i/ x, [3 B( z4 m `6 \
$ G, e- ^; \ i: U. M/ v" M 0 M* `9 Z' z8 e4 V
// int width=dst.rows; //圖像的行列; ]& n1 s1 D7 p8 N+ t& D
//int height=dst.cols; //圖像的列數(shù)量
- c7 n. t7 ~ |$ R- P cout<<width<<endl; //顯示行列的具體像素
5 S$ s7 O9 Q0 V cout<<height<<endl;
. D) A7 n, |1 a0 ?9 x //for (int i =height1-5 ; i>20; i--) //對(duì)收集的坐標(biāo)數(shù)據(jù)進(jìn)行分析
7 c0 v) _8 z( @
6 c2 M% ~8 [$ t0 [ // 等待用戶按鍵。如果是ESC健則退出等待過程。
2 y/ C# e2 @. b9 F5 G while (true)% f$ g' j2 S8 L" j
{
/ `0 s( Z) l( U* A& w9 K2 ? int c;0 k. v3 Q( U" J( L% r5 b/ V$ U
c = waitKey( 20 );2 P7 Y) [* D: s) {. u& S! w: s
if( (char)c == 27 )
7 \; j# j C6 ^( l: v7 u { break; }
6 I& O% X! R6 A. Q: ]9 M }
5 U# H7 S* j' v; L- a3 Z9 a+ G5 l# `: @* ^" b/ s/ a
}
$ L1 ~% @ o' z7 o
{; u6 X- L: T/ N( ~6 V! j8 [ {& e2 S$ V# W& y% C
/**
0 \4 @4 V0 J7 \' _2 |; y * @自定義的閾值函數(shù)) d% p' c* a/ |, Z3 [( x& `- v9 Z
*/ ?( @' s% U+ v# m8 G4 \" f
void Threshold_Demo( int, void* )$ e/ p" ]$ ]( f! E W" o
{- J4 e) w8 n: r& b. x
/* 0: 二進(jìn)制閾值
. t6 D& `* e M# ? 1: 反二進(jìn)制閾值
/ |1 c3 \, N1 J5 Z2 k" ]! D 2: 截?cái)嚅撝?br />
6 B7 B; z- p$ Y/ `9 K7 o$ U 3: 0閾值
$ P8 D' @ A K: x: G* P; a7 ?4 R 4: 反0閾值
/ Y* P/ _1 f" A7 T# F$ c */
7 g. o4 Y: { U" \
# O) K3 |" ^, f) P* w: n% L6 @ threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );: L* m* I( W- d$ H
& A" w' r9 a7 L2 B) b }
imshow( window_name, dst );7 L, p2 a2 C! S8 M
}
: g) H6 x( `7 C( V5 l: s; e, W' W8 E2 d/ _1 i% X, m6 y
- R( A2 D' ^+ Z5 `& C% l9 W [
9 Z- H9 ^( S0 U/ y: ` ` U5 }% h& X) R' h4 o: x9 J
" b' B3 O0 {; }/ H7 B/*' e v0 i! H* F0 b/ g! Z
void main()' x C. R9 `0 G" Z& X
{
5 u; Y A$ S* z2 I1 E
- M6 t6 ?7 V) k( i0 A" ^9 f; l; @ //讀入彩色圖像 單通道圖像(CV_8UC1);CV 8位未指定的1通道的圖像,backImg是單通道灰色圖! I& Z1 b0 [ K. a
4 H5 @, ^. U! a7 ?- u! Y4 Y4 ]9 b //Mat img = imread("fruits.jpg");' y6 l h: e; b
Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時(shí)直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過一定閾值的點(diǎn)提取出來(lái),并找到該點(diǎn)的坐標(biāo),然后記錄該點(diǎn)坐標(biāo),用于后期的比對(duì)
" ~& }) S* r% W% G# z/ @ imshow("灰度圖", img);
( N: K% B4 {3 X! m# \8 Y/ ^9 b //確定圖像的尺寸,行列,
: V0 m% ~% G* B int width=img.rows; //圖片的變量名加上行列,就是行列的數(shù)據(jù)
1 i& ^* G {* U& _' N int height=img.cols;" R- S4 j2 `: z `. j/ w3 H" e q* T
cout << width << endl; //顯示行列的數(shù)據(jù) 本圖片已經(jīng)用358的像素值裁剪了,所以形成的就是高寬都是358: Y x* @. a# C- {
cout << height << endl;& v/ B; h0 q6 ~" S
//定義一個(gè)二維數(shù)組,a[i][1],其行數(shù)等于圖像行數(shù),列數(shù)就一列,用于記錄圖片上像素的亮度超過某個(gè)閾值的像素所在的列數(shù),用于下一步的對(duì)比。% }2 `5 ~# q7 L9 u7 ]7 M, l
int a[358][1]; //確定一個(gè)358的二維數(shù)組
5 n8 i, x8 E' o' S) z% f7 W7 q$ R" x" v
//int height = backImg.rows; //backImg是圖片變量名
) E3 C" @! _$ S7 t//int width = backImg.cols;
# F7 m1 H1 P" b# e' M! z) Yfor (int i = 0; i < height; i++)0 I5 I' X B: I% n" @
{
0 r0 {1 a4 _1 E; N8 s& W F, u/ ^ for (int j = 0; j < width; j++)/ n! j+ l% b0 M4 R; d
{" S. U4 x- K& }5 @0 l: ~; F1 c& }2 N
int index = i * width + j;0 F [% b; }$ t6 t5 G9 ]
//像素值
4 a2 r# A% ^5 z' L% j int data = (int)img.data[index];3 C5 y* h6 z% m; ]( \$ T3 |4 }
}
0 l6 [' m3 ]" x5 ~ }1 V" d u" f& H9 k( z. i" N
waitKey();
: Y8 j5 ~" b- Z: S- I& B}
8 z& @% Q6 {# a0 ?) }*/ |
|