|
#include<iostream>
- @ k8 g8 S" h' @: `4 p v#include<opencv2/core/core.hpp>/ l5 b7 F( I! N8 h* l7 _2 Y- C0 W
#include<opencv2/highgui/highgui.hpp>
( j% K" o4 [1 q& B#include <opencv2/opencv.hpp>
\& t! q* |* N" ^+ v/ e#include <opencv2/imgproc/imgproc.hpp>3 d( I/ C: l; x" t
#include <opencv2/imgproc/types_c.h>
. h/ f+ c$ e4 @3 D9 l9 k4 ?2 ~#include <stdlib.h>
( { z+ e7 B& G% _: u. r/ S& A. f#include <stdio.h>; z% m5 ^* L% M' R3 k+ p2 R
#include <opencv2/highgui/highgui_c.h>
' R: M# J0 j* W#include <math.h>; [2 {$ m5 n! {- F! v; D
//#include "iostream". [7 U# o+ t! d0 D1 [
//#include "cv.h"
/ `3 F6 U: A! }' R//#include "highgui.h"! Q% Q" [2 T6 O5 i1 }8 s' J$ q
//#include "math.h": d! J9 ]' J( D+ Z# g, A* x
using namespace cv; //命名空間CV. l/ k8 `- b) ?' M0 `8 o& v
using namespace std; //命名空間 std
. M9 O* o; k9 O6 W
' U' N3 i+ j" f* Q1 e: Z5 k- Lint threshold_value = 225; //啟動程序時的閾值初始值,,因為227能夠完全提取輪廓,,所以設置為225,,實際上227也可以,。
" }4 F2 N7 M: n7 F/ mint threshold_type = 3; //啟動程序的時候閾值類型,,默認的為不足部分取零6 v9 @" B( q8 a& @
int const max_value = 255;
% n" R& h+ a9 q8 o& jint const max_type = 4;
, Z% L9 M' Y9 B% D3 _7 O8 {; Sint const max_BINARY_value = 255;
& ]- ]7 I) d/ p8 U3 P( b0 w& M& M' e* P) B
CvFont font;
0 A# D5 b6 V3 ?4 K; A& z$ X uchar* ptr;* O7 V3 [4 t4 }6 t. r) T8 o0 F! G
char label[20];- _; R9 _1 R R% z, v
char label2[20];( o& c' Z9 l& x2 i8 `/ c
) M0 Q4 B u# I2 `# l+ vMat src, blured, src_e, src_gray, dst; //類定義幾個圖片變量,,dst是最后轉化閾值之后的圖片,,src.gray是灰度圖
, p7 i+ L6 U+ } //在C語言中“char*”是聲明一個字符類型du的指針,定義數據類型,,char可以定義字符zhi有變量,、數組、指針,。dao8 D! G8 W' r9 ?6 ~, J$ U
//例如:char *string="I love C#!"
9 [& f2 Z8 O$ z5 }/ `* C //定義了一個字符指針變量string,,用字符串常量"I love C#!",,對它進行初始化。對字符指針變量初始化,,實際上就是把字符串第1個元素的地址(即存放字符串的字符數組的首元素地址)賦給string,。*// v& S/ I0 o+ V* R7 R
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蝕的參數2 J) U% Y1 O) ]; u' r2 o' [
char* window_name = "閾值演示程序20201121";
. ]3 Y9 V0 S9 Fchar* trackbar_type = "類型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //0 Y4 A8 o, C( N$ B! S
char* trackbar_value = "數值";! W# U# J ?& `/ ?4 x }& D6 }
; f" o! A) }: z( Y, F3 a& {
/// 自定義函數聲明
. |+ o) P8 G$ w* u" D6 q9 `- tvoid Threshold_Demo( int, void* );" |- _1 k; c* ^7 Z
7 Q" c, Y$ z' f6 D$ X
/**
! r0 i# c/ r b8 Y- d& o * @主函數
3 V ]3 {2 @) L8 L m* k */
* J5 j* x# f5 \* Z# Y6 jint main( int argc, char** argv )
3 n) r) r" _4 }+ M) ^{! X0 ~* L5 N+ o) [; r
/// 讀取一副圖片,不改變圖片本身的顏色類型(該讀取方式為DOS運行模式)
0 V2 t: K; P, `% f src = imread("121.JPG", 1); //目前還未使用攝像頭拍攝照片,,暫時以直接讀取文件的方式來測試,。/ x8 V Q) \! D5 f
erode (src, src_e, element); //對圖片進行腐蝕,參數可調,,正常為9或者10,,過大則造成輪廓過小,,應該再進行降噪
: B" Y8 j2 v8 M) s6 d8 E5 P blur (src_e, blured, Size (3,3));//3*3內核降噪
& L, X7 M; L. C- u imshow("腐蝕和降噪后的圖片", blured); //顯示圖片
0 M5 e7 L) @" l7 U. C' J* h: C int width=blured.rows; //圖像的行列
/ h+ R8 \+ p1 X int height=blured.cols; //圖像的列數量6 f9 ?9 W# a; l# F
cout<<width<<endl; //顯示行列的具體像素5 S# i* o) L# @% _
cout<<height<<endl;
! K( d' B9 \+ h int a[500][1]; //定義整型數組,,后面的1應該可以不要的: _7 J% t- Y8 ~0 @0 k9 B
int b[500]; //設置一維數組,用于判斷曲線的切線斜率6 h5 [& K5 j7 B- E- }( C; U# n
3 Y/ G I" l$ V! X; Z0 j! t4 p# Y1 b
/// 將圖片轉換成灰度圖片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時直接轉化成灰度圖,, 下一步是要將像素亮度超過一定閾值的點提取出來,,并找到該點的坐標,,然后記錄該點坐標,用于后期的比對7 h, h7 e. H, P
cvtColor( blured, src_gray, CV_RGB2GRAY );/ d8 X6 m$ E+ J
- j* p+ H! |* h, [7 `0 l: q" T7 ?
/// 創(chuàng)建一個窗口顯示圖片
) Z' Z3 y7 R, w& O namedWindow( window_name, CV_WINDOW_AUTOSIZE );
! I6 P" s; u8 [. V/ P1 j- ? C9 Q! z$ M$ Z9 u- z3 i
/// 創(chuàng)建滑動條來控制閾值
3 P9 g/ V- z7 A5 ?0 t createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);1 a6 P5 I& f. ]2 o# H
; |, p7 _6 b: e9 O& }
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);$ I( t- n( |4 u/ |6 @" L1 Y. [
; U, U& I/ M0 h0 L
/// 初始化自定義的閾值函數
! y* O, W+ s6 X' b9 ?1 M( Z Threshold_Demo( 0, 0 );" @4 ^3 Y) ?( i/ d1 d8 c9 }5 F5 |
/ t0 |! L+ V: X' A8 R) y // Mat img=src; //暫時無用; \. d# T5 I" Y
//imshow("轉化之后圖片",dst);
* K: {& }. F9 a3 E$ W2 j. y3 S$ f5 H1 {. m9 j' l9 L2 n
//遍歷圖片的每個像素點,,當像素點的閾值大于227時,,將最左側的該像素地址保存在二維數組中,在該行之后的像素點拋棄,,如果閾值低于227,,則向下遍歷至該行末,然后從下一行開始對像素進行比較
( ?, Q! R' ?! G
, ~2 o- z/ ~9 w+ b# A: d& }//Mat BW = imread(imgName);( |4 |7 g) U2 E% @& j4 ?" e6 U
//int value = BW.at<uchar>(191, 51);: i' m. V! X; S" f
int width1=dst.rows; //處理之后圖像的行列
& q, G' N+ @! x7 @ int height1=dst.cols; //處理之后圖像的列數量
# l' V/ f& d/ |5 p2 F' b1 d, t7 t$ Q8 ^; g
for (int i=0 ; i<height1; i++) //從第一行開始 應該從最后一行開始向上檢索,,這樣可以減少計算量,,一旦出現與之前曲線K值相反的方向,則確定是拐點,,不用再考慮,,但是要考慮出現切線斜率始終是減少的趨勢,這種情況下往往是蒜尖
0 X* X) m+ V& a8 k$ [ {/ C: m% k# X! U
for (int j = 0; j < width1; j++) //從第一行的第一列開始
* m, r5 T1 J/ y% w {. E* f7 z. Y* q4 N! M w
//int index = i * width + j;
; j( ^( v- ?# ^& a( Z int value = dst.at<uchar>(i,j); //讀取給定坐標處的像素值
X, G8 j# T0 t8 s% S% C/ b: h //if; //像素值
% Q. ]- v1 I2 p //int data = (int)dst.data[index];7 D5 B" J$ H. Y3 |
if ( value >200) //如果像素值大于某個數值,,則將其地址記錄在數組內,且僅記錄首像素,后面的舍棄
* C) u J" c. p' _* R( ~ { 5 X/ Z/ P0 }! I; l
a[i][1]=j; //數組值等于列數,,便于后期對比1 Q. F* e* P% p: |& s9 [, a4 {5 k) b
//cout<<i<<" --- "<<j<<endl; //i為行數* H4 F; U H: p
//cout<<i<<" -坐標-- "<<a[i][1]<<endl;
! x( y) \4 [' P5 S N% B if (i>1)
8 T. \: n0 H `$ Y { //11
; ?' U- r: L5 {6 X# G* K7 {" A5 J if (a[i-1][1]<a[i][1]) //如果第一行中大于某個閾值的像素地址與下一行相比靠右,,也就是列數比上一行要大,則說明該曲線向左側傾斜,,說
, b- h3 ?1 E( i8 { //明是底部,,如果曲線向右側彎曲,則是蒜尖 (之所以用i-1,,是因為總不能和沒有像素的地址對比,,所以必須向后取值)$ \ _5 y5 }! G2 w5 _ s0 f
{ + d- a# e: Z- j+ n( \, _: t: e0 T( s6 S
b[i]=0; //因此,,當下一行的地址比上一行的地址小,則用1表示,,如果下一行地址比上一行大,,用0表示,1是蒜尾,,0是蒜尖,。
3 N+ A0 t8 K0 _ g/ M/ V) F4 c0 D! ~ }. S, o$ k/ g7 G1 z2 _
else if (a[i-1][1]>=a[i][1]) ) [ g( |/ O3 a' Q3 p
{4 T# W6 _ w9 n
b[i]=1;
1 X9 t& j+ U# J I3 V6 K }
7 I) ]( D% h" s6 \6 a2 D0 P2 p# Y! W5 l' i) W, y
cout<<i<<" -標識符-- "<<b[i]<<endl; : Y0 W+ n; F' m# X5 m: N D
//cout<<j<<endl; //j為列數1 X7 w$ {- Z. L$ G8 j$ j
} //11
x) ?2 r" _7 M M 7 ]7 q5 j$ s8 p% s7 Y9 C
% G$ G' r [+ E' d break;
' f+ D! p5 I# ^* A1 ?; I6 A% g }
$ G' _ [: M+ W3 V6 a }" T' q8 u+ e8 Z! T: h# Y; c
}
& W4 A# `5 N6 \' W( Y& ` //開始對b數組進行分析,確定是否為頭尾(但是需要對曲線進行圓滑處理)
$ }; a6 V" U9 c# y# `- j# d6 F* F$ ? for (int i=0 ; i<height1; i++) //對數組b進行遍歷,,檢查是否存在誤判的問題* W& l) }; i" z3 r& Z
//尋找拐點,,找到用于判斷的后段曲線的拐點1 L. q! [$ E4 q( W; K
//對圖形進行圓滑處理,除了最大的拐點之外,,盡量不要出現折線" v' A" D2 s/ B% g& c5 x' F
, c+ T+ Q) X6 f' l7 p
. g5 M$ e4 {8 A3 o* h . `! @; w7 w; j1 T; d! `! c
// int width=dst.rows; //圖像的行列
: B% O; I4 K/ c" S# s7 s$ b //int height=dst.cols; //圖像的列數量; E) M1 o3 Q6 x: Y# P
cout<<width<<endl; //顯示行列的具體像素9 j* {+ z% y0 |
cout<<height<<endl;
* J K0 J" P* N- V! x2 W; ` //for (int i =height1-5 ; i>20; i--) //對收集的坐標數據進行分析
# k% o' w P+ v* B 0 T- R t4 ^) M! K/ o& b
// 等待用戶按鍵,。如果是ESC健則退出等待過程。) S- h. ~6 T) |+ g
while (true)
9 v% c$ w2 z9 p* C) U v {) T N. y4 u+ w/ l# ^
int c;" Y2 o9 \+ R. t0 q
c = waitKey( 20 );& L3 v7 R: o! W) @0 O. r
if( (char)c == 27 )
( P0 [3 @" P# ?: c1 M { break; }; V$ l* _7 A! k6 G" v
}
+ U% |2 X) r; M# D: z9 R* R1 T
! m2 g2 s4 x( R, E( [! a4 K! m}
. z8 Y2 n4 e% r/ r1 \5 Y* n- p2 K. S# Q6 Y9 [
* x8 O* z! G5 a5 p/**1 |' E6 P: Q9 B
* @自定義的閾值函數
- T1 H. [/ `/ R( a2 e5 e* B$ }) c */
# t# W8 i" |: Z8 nvoid Threshold_Demo( int, void* )
9 \& c2 l; `+ N- G) }{9 i' c" b$ k( p
/* 0: 二進制閾值
& @4 ^9 T5 i: Y* \ 1: 反二進制閾值$ [) J2 h/ c4 F1 H6 _. M3 g" x
2: 截斷閾值
: F+ q; S' I. d% l 3: 0閾值
2 c% M0 [8 b" H 4: 反0閾值+ e& h0 y/ f) D7 ~: A
*/
( K$ P C3 I/ I: B6 t6 d' m8 p ^, N
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );+ Y3 D; X* k. @ g
1 y2 i! \7 K. Y. B! W0 g, ~
imshow( window_name, dst );
" c2 e c; ^& g1 ~( h}% ]4 i+ C& ]6 f$ ^
8 P: y3 }: a; _+ X0 J3 g
L, @; i- K9 Y. f2 P
( _9 b& B" z' m
- u" n5 U7 V4 W% H) V9 I/ P$ a9 u
. x6 T2 _; C! f4 U% L2 v/*" F( V) B* {( ~7 j
void main()
2 I1 ^) O' n' y( A{5 `8 F5 e2 U3 V
/ y& X+ h, h/ M, `6 l //讀入彩色圖像 單通道圖像(CV_8UC1),;CV 8位未指定的1通道的圖像,,backImg是單通道灰色圖" }' t! h( j2 h# ?3 T
* X8 \; f, c' [& ^5 l- h1 E+ s
//Mat img = imread("fruits.jpg");2 [4 b/ M+ E. H- \
Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時直接轉化成灰度圖, 下一步是要將像素亮度超過一定閾值的點提取出來,,并找到該點的坐標,,然后記錄該點坐標,用于后期的比對# M& d; j8 i# v! x8 n
imshow("灰度圖", img);8 y5 |0 }* E7 T5 `
//確定圖像的尺寸,行列,,
( t0 L0 h* ~! ?& p2 h int width=img.rows; //圖片的變量名加上行列,,就是行列的數據: a( A6 I* E" m- k8 z ~
int height=img.cols;8 s/ N" y1 _! O, P2 p: x' M `
cout << width << endl; //顯示行列的數據 本圖片已經用358的像素值裁剪了,所以形成的就是高寬都是358
) H% D' J( [1 x8 N4 l! N; }: E cout << height << endl;, s. o3 Q' [7 O/ }2 o; Y; D( }0 v
//定義一個二維數組,,a[i][1],其行數等于圖像行數,,列數就一列,用于記錄圖片上像素的亮度超過某個閾值的像素所在的列數,,用于下一步的對比,。
0 j/ e; q/ u* T: s* _! O int a[358][1]; //確定一個358的二維數組
, @& A7 A& y0 N6 v, }- Y- R! o# h2 o) C
//int height = backImg.rows; //backImg是圖片變量名
& ^9 {- n* b X3 x//int width = backImg.cols;; l' @2 j) e0 W5 S7 O+ k) @
for (int i = 0; i < height; i++)
7 S3 k2 N/ {1 i1 j# [, V( O {1 G7 r5 T: u; w5 A5 C& Y# {9 `
for (int j = 0; j < width; j++)
+ `9 C: @2 ~! V- S" _ {
5 y. ^* t" f$ M+ H int index = i * width + j;
( w2 w: Y. X5 f, V; H* z, t //像素值
1 G0 G! g C, A/ s" i/ w4 k int data = (int)img.data[index];
/ r8 U/ G3 C8 t }/ U! Z" C6 W6 K: x7 I+ k
}
% e' |' O! n$ }) c9 |+ q. _+ Q waitKey();
* |1 D" U$ t8 D# {( u}
/ R3 x5 r0 L6 u) b; [ d8 v$ D*/ |
|