|
#include<iostream>
- r" g+ X8 H! q4 o) ]# `#include<opencv2/core/core.hpp>
* C& z" q5 l! n" y#include<opencv2/highgui/highgui.hpp>
& P9 J" ?3 c" \ w. H/ M#include <opencv2/opencv.hpp>2 {8 V9 F7 Z ^# _% @
#include <opencv2/imgproc/imgproc.hpp>7 e4 Z" Y. s/ f! k
#include <opencv2/imgproc/types_c.h>
! Z% r7 U8 z$ P! C) s9 H0 c# [#include <stdlib.h>+ b. B+ Z U* y& N. m
#include <stdio.h>3 W* ^) k! ]2 [; [; G v3 Q
#include <opencv2/highgui/highgui_c.h>" i; g; Z& Y: f* H: {0 x! T. l5 I
#include <math.h>
$ L* O5 q3 i* o" c$ b//#include "iostream"+ A& r1 J" D2 l9 [$ W
//#include "cv.h"
, g4 y2 c$ ^6 ?: l8 g3 ]1 z) X//#include "highgui.h"
* y: l% p, E& g) d: c//#include "math.h"
) n8 a" {8 _8 \: s9 jusing namespace cv; //命名空間CV
! V( ]; Q2 n9 T ausing namespace std; //命名空間 std
# l0 h* A6 \ h7 @8 Z
4 E# ]: @8 P# b9 `1 ]# Jint threshold_value = 225; //啟動程序時的閾值初始值,因為227能夠完全提取輪廓,所以設(shè)置為225,實際上227也可以。9 j4 }8 ?7 `3 c; A
int threshold_type = 3; //啟動程序的時候閾值類型,默認的為不足部分取零1 f' H* C; R5 ]- T9 e/ \* ]
int const max_value = 255;. N' `; R" y+ p
int const max_type = 4;5 |: W0 B) P% ~& J% H0 B; u
int const max_BINARY_value = 255;
5 [& P0 i/ |7 O" \' _; s8 W9 r8 V& a, h) a% B* b
CvFont font;+ |. B* d# x8 U) f) a) {
uchar* ptr;
& |: Q1 [5 c. r" u4 J char label[20];
7 Y0 L" {7 c& R# F char label2[20];
5 B' H5 Y/ G8 X9 y$ H# j4 [& b+ G1 `
4 z7 a0 p9 Z4 @% U6 o0 w, @Mat src, blured, src_e, src_gray, dst; //類定義幾個圖片變量,dst是最后轉(zhuǎn)化閾值之后的圖片,src.gray是灰度圖) p# {; f# b3 t
//在C語言中“char*”是聲明一個字符類型du的指針,定義數(shù)據(jù)類型,char可以定義字符zhi有變量、數(shù)組、指針。dao
9 ]1 V% {, ]* H! s7 S" q //例如:char *string="I love C#!"
, F: F& j# N# w' N% p' e/ G) [ //定義了一個字符指針變量string,用字符串常量"I love C#!",對它進行初始化。對字符指針變量初始化,實際上就是把字符串第1個元素的地址(即存放字符串的字符數(shù)組的首元素地址)賦給string。*/* G. L" v4 V. |, h0 Q& k! i& i
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蝕的參數(shù)
P5 {6 r$ H' _" f% F3 ychar* window_name = "閾值演示程序20201121";
0 z1 b# k( b3 ^/ Fchar* trackbar_type = "類型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
8 b. S/ W/ Z, \6 k. @+ Rchar* trackbar_value = "數(shù)值";& F* ]' b3 d) ]
# m% G' Q# F/ J. l7 L
/// 自定義函數(shù)聲明
% z! D6 _3 {0 B# y4 _# Avoid Threshold_Demo( int, void* );
; a' B" V9 E: p3 F# g# m. y, O
: F7 Z4 L1 p" {7 C. X/**
, y. _* J! ^1 W- T/ N * @主函數(shù); O7 Z4 r0 j2 P! V4 P' g* I+ Y
*/
7 f. @0 y- J# D% Oint main( int argc, char** argv )& P, p8 o* J, ?5 t
{& b" }# S& R/ P7 K5 O4 X
/// 讀取一副圖片,不改變圖片本身的顏色類型(該讀取方式為DOS運行模式)
) R" V0 }" N, E/ l; w src = imread("121.JPG", 1); //目前還未使用攝像頭拍攝照片,暫時以直接讀取文件的方式來測試。4 k9 a( ^8 |& x5 S
erode (src, src_e, element); //對圖片進行腐蝕,參數(shù)可調(diào),正常為9或者10,過大則造成輪廓過小,應該再進行降噪
* A3 C# q. n- [3 J' A blur (src_e, blured, Size (3,3));//3*3內(nèi)核降噪4 S* Z& P- m7 @5 t3 q
imshow("腐蝕和降噪后的圖片", blured); //顯示圖片# ?' l, f% p+ H9 C6 I! m
int width=blured.rows; //圖像的行列
' B, n8 {# x. C/ e! R7 ]2 [ int height=blured.cols; //圖像的列數(shù)量
- |+ c* h* n/ b2 J; X2 ^6 t cout<<width<<endl; //顯示行列的具體像素& S4 W+ K( N, W3 E+ c3 }
cout<<height<<endl;
6 w' k% ~8 J5 t& F5 Y. j int a[500][1]; //定義整型數(shù)組,后面的1應該可以不要的
6 h& ?- D$ C& \4 a int b[500]; //設(shè)置一維數(shù)組,用于判斷曲線的切線斜率
$ l, Y+ p& E$ e) U9 `
: y1 {9 q% u/ \. f8 n( i) u /// 將圖片轉(zhuǎn)換成灰度圖片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過一定閾值的點提取出來,并找到該點的坐標,然后記錄該點坐標,用于后期的比對
4 X3 k/ B9 q e cvtColor( blured, src_gray, CV_RGB2GRAY );
$ m: _; |% D& w( }* w4 r* z! `3 y" D3 G$ T0 C* b
/// 創(chuàng)建一個窗口顯示圖片; F _+ b @, i2 l- z
namedWindow( window_name, CV_WINDOW_AUTOSIZE );6 w/ W: o7 e$ E6 D0 b
. J2 e$ k7 L1 [% f+ ]: L+ u; a /// 創(chuàng)建滑動條來控制閾值% w5 _7 U; H4 R* `9 t. `
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
5 u& \& x$ ]+ t$ H, ]1 G. _9 U5 c" ^9 T: `# J, N
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
; Z% A* w$ W8 p G+ ~- g6 T0 }" Y5 a$ k, C+ ^) e
/// 初始化自定義的閾值函數(shù)+ w8 v( b5 W' c, A6 y) _
Threshold_Demo( 0, 0 );
J* A) G' t. \3 _
5 {6 B) g9 h! u8 a7 D // Mat img=src; //暫時無用0 w6 F4 i7 _# z' k
//imshow("轉(zhuǎn)化之后圖片",dst);
* X( Y9 c+ [4 a. h0 ^; y% t% X4 }" c* j9 C: k" U N' F [
//遍歷圖片的每個像素點,當像素點的閾值大于227時,將最左側(cè)的該像素地址保存在二維數(shù)組中,在該行之后的像素點拋棄,如果閾值低于227,則向下遍歷至該行末,然后從下一行開始對像素進行比較
/ P' x% w& R- A0 K8 A ; q, j, @1 y0 d) G0 x# L( q
//Mat BW = imread(imgName);
! A2 f `: A `& O! y6 T//int value = BW.at<uchar>(191, 51);6 e1 H& \: l" H. l$ b& v
int width1=dst.rows; //處理之后圖像的行列
) H# {6 G0 `$ |/ n. r int height1=dst.cols; //處理之后圖像的列數(shù)量 z/ b& `- R/ q* Q2 e; Y: C8 I* L% T
0 A7 s* ?: I) ~4 G2 d' R* M3 x for (int i=0 ; i<height1; i++) //從第一行開始 應該從最后一行開始向上檢索,這樣可以減少計算量,一旦出現(xiàn)與之前曲線K值相反的方向,則確定是拐點,不用再考慮,但是要考慮出現(xiàn)切線斜率始終是減少的趨勢,這種情況下往往是蒜尖
9 U- V4 B5 K- r {; ]: K: W4 x# c8 ?, z$ D# Q
for (int j = 0; j < width1; j++) //從第一行的第一列開始
6 Y* l6 l4 g# X* f& ? {! |6 l I0 g0 E& S
//int index = i * width + j;
2 A* d5 o+ Z6 e6 U: i; R3 u int value = dst.at<uchar>(i,j); //讀取給定坐標處的像素值! }% M1 A, L" ^' N: l
//if; //像素值
0 A. \' }& o" @0 Y, ~/ U- H# U6 q //int data = (int)dst.data[index];
/ b$ `- N7 P; F9 j! k if ( value >200) //如果像素值大于某個數(shù)值,則將其地址記錄在數(shù)組內(nèi),且僅記錄首像素,后面的舍棄( C9 J+ S" o( C% u% x0 q# j1 l* G! Q+ D
{
. l. h( u% C- \ a[i][1]=j; //數(shù)組值等于列數(shù),便于后期對比2 i8 M, Z3 d) j8 b& X* J
//cout<<i<<" --- "<<j<<endl; //i為行數(shù)
, M* u: u/ {0 r' d+ g) I1 g9 T //cout<<i<<" -坐標-- "<<a[i][1]<<endl;
, e' ~- b+ |3 t( x3 j if (i>1)9 I" w1 v: g4 r. M
{ //119 c) u. ?" P! ?1 a( ]
if (a[i-1][1]<a[i][1]) //如果第一行中大于某個閾值的像素地址與下一行相比靠右,也就是列數(shù)比上一行要大,則說明該曲線向左側(cè)傾斜,說
9 H" L( s" ?! {9 L) G* `$ F8 S //明是底部,如果曲線向右側(cè)彎曲,則是蒜尖 (之所以用i-1,是因為總不能和沒有像素的地址對比,所以必須向后取值)
8 L9 i) y- h* J& R! d T8 Z { ! x5 w$ H$ V1 T3 g6 f
b[i]=0; //因此,當下一行的地址比上一行的地址小,則用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。) K p+ g; Q! I0 ^ E
}9 u; n' H/ P7 X6 S8 p
else if (a[i-1][1]>=a[i][1])
6 c7 X8 I& L& f) y. l {, L6 B" c7 y4 o I' P
b[i]=1;
0 [* O$ @4 v- p% L6 ? }1 G0 ] \4 }( Q( L' u3 E
* E; T" ?& T$ L* d4 q, ] h cout<<i<<" -標識符-- "<<b[i]<<endl;
2 D& g& t' ~; e" I* I3 \& W //cout<<j<<endl; //j為列數(shù)
( |+ ?3 h* l" n" ]' @) v7 ~$ g } //11- u) q8 L N/ ]* p: T4 q
6 z) \% e _% j( ^( O
' n4 `! J% G7 A break; 1 F4 d% C, `( M/ n; b) f& X/ G3 b
}
1 G; E h' H8 ]- ~ }8 l; G; h. X' |# @ r
}# K( B3 B5 M; w6 O: l* K* {
//開始對b數(shù)組進行分析,確定是否為頭尾(但是需要對曲線進行圓滑處理)
3 ] R+ F" X1 K' m& ?/ Z, o2 V for (int i=0 ; i<height1; i++) //對數(shù)組b進行遍歷,檢查是否存在誤判的問題' ]4 q) i# a: c+ S# G' s) K
//尋找拐點,找到用于判斷的后段曲線的拐點
4 z" ~$ Q% o/ o) M1 ~ //對圖形進行圓滑處理,除了最大的拐點之外,盡量不要出現(xiàn)折線
6 q" E$ |- ~9 b3 E0 a 5 @& D- ]5 y! b+ ]2 i- Z# c* y( x
W$ t& Q* A1 w; o" o0 Y' x; u% {1 V
& ` ~, G; U; K5 e; p // int width=dst.rows; //圖像的行列2 d, ^. M. c+ Z" Y
//int height=dst.cols; //圖像的列數(shù)量& R* [6 J* u6 O9 M" E3 R$ [1 l% w
cout<<width<<endl; //顯示行列的具體像素
( s9 K' y i0 s) k7 G- o% g cout<<height<<endl;
* I- V( T& ?" K5 D' N7 r( O //for (int i =height1-5 ; i>20; i--) //對收集的坐標數(shù)據(jù)進行分析: j8 `/ {" }0 W g
$ ]! y( X: J* M8 A; V+ d E
// 等待用戶按鍵。如果是ESC健則退出等待過程。
2 _9 A5 I% [1 P7 Q; b' d while (true)' l" M- t) l) U
{
0 K7 G% c1 b- O& i4 | int c;( l$ a& @: h+ U1 Q' I% V7 Q
c = waitKey( 20 );
4 ~7 `% b2 Z1 L, S4 D8 W! _) m9 _ if( (char)c == 27 )" v; [# o* @0 i) A
{ break; }; Y9 e5 {" U* m
}
9 [ `: i, O- E O" w
* `, _$ R& S/ x. D}* F- c) k A3 n6 p' a
% c; V X0 ?3 a/ w4 A4 t: M
& ^) M) w' Q4 \3 i7 u$ W. v
/**! U. L A, n* J* C/ S: ^: n
* @自定義的閾值函數(shù). v4 h, O2 c/ W% _. o& {
*/3 e7 C* i3 m+ o6 H; Z
void Threshold_Demo( int, void* )
) {: m" _4 @2 k# y{
u& M1 W, ^! k0 _ /* 0: 二進制閾值
- _; n4 l$ _3 Y1 c$ F4 n 1: 反二進制閾值9 Z3 w/ {3 W! [4 A6 H; M
2: 截斷閾值2 W. T) H& R; ]9 A% P
3: 0閾值7 Q7 m: o: r* K8 d9 o) ^
4: 反0閾值4 Q9 w/ n: I% A' M4 l, Y6 y
*/
" j- H) \8 J& M; u z, L6 Q1 W# v2 ~6 M
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );# e* s; z, e* \7 T* v: q3 Q0 |; A
; D; q3 A- a/ u8 ?1 y imshow( window_name, dst );6 M) H9 p- V4 ]# B2 Y' j
}8 c$ t1 y: L1 s5 X1 ]
" p1 `! M- u( ]8 z0 v
5 h5 D$ ]+ D. {5 u" o
) P9 F$ I6 v2 V& j7 I* E! h, T6 w" ]2 v: F9 V( ?' U
3 u. p3 V [/ X. X! w/*8 a @. h9 V- V6 L5 {' F1 v/ A* k
void main()* O- g4 g0 W0 P M
{
! A' M. B6 P5 p% r / w) h0 v1 c) c. z) `
//讀入彩色圖像 單通道圖像(CV_8UC1);CV 8位未指定的1通道的圖像,backImg是單通道灰色圖* K6 O* V6 | Q' x9 I- ~
' ~ e0 n! q4 v& j4 ? //Mat img = imread("fruits.jpg");0 H2 q- C7 V' ~0 D8 y" s' N
Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時直接轉(zhuǎn)化成灰度圖, 下一步是要將像素亮度超過一定閾值的點提取出來,并找到該點的坐標,然后記錄該點坐標,用于后期的比對9 x0 B2 _& r1 E3 _
imshow("灰度圖", img);9 W+ Y% q; y! }7 q$ ^( T3 `7 |
//確定圖像的尺寸,行列,! R, j; F$ T( j: B
int width=img.rows; //圖片的變量名加上行列,就是行列的數(shù)據(jù)
1 B D: U0 L1 q int height=img.cols;2 _( o Y3 O* K6 M) \# B
cout << width << endl; //顯示行列的數(shù)據(jù) 本圖片已經(jīng)用358的像素值裁剪了,所以形成的就是高寬都是358
* k0 n! y- I9 ]+ `9 I( w5 k# ] K cout << height << endl;
0 V- e- M5 X% O* L4 H: E4 y //定義一個二維數(shù)組,a[i][1],其行數(shù)等于圖像行數(shù),列數(shù)就一列,用于記錄圖片上像素的亮度超過某個閾值的像素所在的列數(shù),用于下一步的對比。
3 u) E3 y3 S+ B: N! q# q4 s int a[358][1]; //確定一個358的二維數(shù)組
( D5 H' l, m8 {# R/ V- u7 m$ ~- I' q3 q/ J) G+ Y
//int height = backImg.rows; //backImg是圖片變量名
# f; B0 [! {! l! w: a/ K, }//int width = backImg.cols; [ J Y- y$ Y5 h2 q( T
for (int i = 0; i < height; i++)
' `5 q/ k! w( t {, `( m5 j, \6 z0 m" h' D2 c
for (int j = 0; j < width; j++)- D- @5 q+ R; e
{
1 g: c, B" F! H2 K% R( T6 G8 R int index = i * width + j;% d: y9 t) U, U$ b# {
//像素值% X: _7 x: F5 v L0 O w5 {" V
int data = (int)img.data[index];, m0 J7 ~# D; V/ j
}& T* F- c: K; K/ l" W. k$ L9 s
}" _' h; l {# m8 v! l
waitKey();
1 |( F& r0 k" ^ a}
) d8 ^( `2 O6 y$ Q4 [2 v*/ |
|