|
#include<iostream>
, r% P) F4 ` h4 d3 r* R#include<opencv2/core/core.hpp>! j/ D B* X2 D$ ?& ^* n5 j, W$ G
#include<opencv2/highgui/highgui.hpp>* t/ C% Y5 ]* V2 a, ^ z
#include <opencv2/opencv.hpp>
+ H8 U/ w8 h \1 N4 I5 {. ?#include <opencv2/imgproc/imgproc.hpp>
5 \) ?: U2 N8 w# G/ B#include <opencv2/imgproc/types_c.h>
* j8 k0 l. ^- b" m#include <stdlib.h>. f t7 t% D) M7 S4 ]2 c
#include <stdio.h>/ a8 d( G* l+ X
#include <opencv2/highgui/highgui_c.h>
7 {% _) F: Y5 E3 B9 j5 c#include <math.h> w1 z b6 v* k0 D( C" F3 @
//#include "iostream"
- B8 e, e T k# m) K//#include "cv.h": S3 Y& A! E% P' f
//#include "highgui.h"
& \6 ]) ^8 R! P$ o//#include "math.h" e+ [( N% \( i
using namespace cv; //命名空間CV _! B3 M. f; t( T
using namespace std; //命名空間 std \0 C7 d0 r1 ?1 u l5 g& u
! N5 x0 s s; b/ a6 Hint threshold_value = 225; //啟動程序時的閾值初始值,因為227能夠完全提取輪廓,所以設置為225,實際上227也可以。
: p W/ D5 A# U0 iint threshold_type = 3; //啟動程序的時候閾值類型,默認的為不足部分取零
s% ~1 W, |# J" rint const max_value = 255;5 s) Y2 p. u+ u' T4 M
int const max_type = 4;2 Q- W- k" i9 H; r
int const max_BINARY_value = 255;( F, Q/ ]3 W1 Q5 F
% }4 ~; |% H# H- n! B$ j5 F, [2 i5 t3 V CvFont font;7 X6 L' Q/ F7 h
uchar* ptr;
" v) }) @: E5 R+ v' S, P# k0 C char label[20];
5 u) z( {/ |0 e/ g$ }+ `3 x7 x( t char label2[20];
7 ~0 z! g2 O2 v
- e+ @% W* W' ^* TMat src, blured, src_e, src_gray, dst; //類定義幾個圖片變量,dst是最后轉化閾值之后的圖片,src.gray是灰度圖) v( j: p( `7 B
//在C語言中“char*”是聲明一個字符類型du的指針,定義數據類型,char可以定義字符zhi有變量、數組、指針。dao5 L* t/ }) z2 t3 q' j
//例如:char *string="I love C#!"1 X4 D- ^3 j9 I; O; s
//定義了一個字符指針變量string,用字符串常量"I love C#!",對它進行初始化。對字符指針變量初始化,實際上就是把字符串第1個元素的地址(即存放字符串的字符數組的首元素地址)賦給string。*/3 r, K9 g; V( w0 c+ S7 Q5 n
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蝕的參數
/ x9 D6 k Z+ Q' Y+ J ~char* window_name = "閾值演示程序20201121";/ C( [- K& c. e; L% k
char* trackbar_type = "類型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //' W- U" S& ?1 w2 ^8 j
char* trackbar_value = "數值";1 ^9 ?9 o7 S& H1 {! |8 C% _
. L5 f/ @5 F0 k1 b6 F/// 自定義函數聲明
0 L. F& z6 y# G9 F) O/ Nvoid Threshold_Demo( int, void* );
. E( `+ ]3 _+ X( W' A7 r2 Z W4 l' Y5 ?+ h k) E
/**; q& |% A4 H7 V0 W' Z4 r- ~
* @主函數& R4 p5 ~( E* G0 P- g v
*/
, `8 x3 l: n+ _2 C2 @/ M, u8 qint main( int argc, char** argv ); k5 h4 d5 l5 v* W/ \9 ~9 [, q; P) ~
{1 l6 E" e/ a1 Z0 ^
/// 讀取一副圖片,不改變圖片本身的顏色類型(該讀取方式為DOS運行模式)! w% u) {1 o! t1 s$ o
src = imread("121.JPG", 1); //目前還未使用攝像頭拍攝照片,暫時以直接讀取文件的方式來測試。
; z0 n4 k6 I, q7 J1 c3 F* M erode (src, src_e, element); //對圖片進行腐蝕,參數可調,正常為9或者10,過大則造成輪廓過小,應該再進行降噪
, e' b% L- a9 K% d( O2 z blur (src_e, blured, Size (3,3));//3*3內核降噪& h& S3 y- d) E2 ?
imshow("腐蝕和降噪后的圖片", blured); //顯示圖片
! E* A6 z3 I' l1 ? int width=blured.rows; //圖像的行列8 M$ w; b$ l& a7 Y* C2 l% U& E, ~
int height=blured.cols; //圖像的列數量, }' \2 U- r Q8 C( ]9 p
cout<<width<<endl; //顯示行列的具體像素
' S4 k a$ X4 R; |* B0 o4 `+ \ cout<<height<<endl;
2 k- `0 Y! k# U& `3 Q. U; w6 p int a[500][1]; //定義整型數組,后面的1應該可以不要的
' S* O* s+ a4 W- x) j int b[500]; //設置一維數組,用于判斷曲線的切線斜率7 h' _ O8 F' E, k+ {1 p7 E
& A% k7 B* _' |; Q& O, L$ _
/// 將圖片轉換成灰度圖片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時直接轉化成灰度圖, 下一步是要將像素亮度超過一定閾值的點提取出來,并找到該點的坐標,然后記錄該點坐標,用于后期的比對- O) Z7 V" s" X8 B' h5 r3 v8 h
cvtColor( blured, src_gray, CV_RGB2GRAY );
, a4 S) M$ }( T4 {" P% S
0 ~/ ^! h- O+ j6 Y! X /// 創建一個窗口顯示圖片; A% i$ {' r8 \* F _/ b4 a
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
7 ]/ r1 d" s) J/ x4 J" \8 j# k; j
/// 創建滑動條來控制閾值1 }3 H1 N5 y1 `! S' k u- W) `+ [5 Z1 f
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);, m3 O& R9 U& W" N
2 Q+ }+ A% S' I. u createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
! c0 T# m, |8 h$ k, _* r8 J" G( G: f" t2 _: ^' K0 l
/// 初始化自定義的閾值函數
% T- V o9 G6 g Threshold_Demo( 0, 0 );
% g+ _; m/ p; q
: ` K7 L4 n8 L // Mat img=src; //暫時無用- {7 j2 _! u) d0 j
//imshow("轉化之后圖片",dst);
5 _7 u: s8 O, v* z# c/ {: {* l1 M: m# B; ^8 o* }/ U) v
//遍歷圖片的每個像素點,當像素點的閾值大于227時,將最左側的該像素地址保存在二維數組中,在該行之后的像素點拋棄,如果閾值低于227,則向下遍歷至該行末,然后從下一行開始對像素進行比較
/ }9 q' l' U( l [ 1 s- @8 B9 o( K7 m. V; H
//Mat BW = imread(imgName);2 s6 m% R8 o5 }; U% |6 y% R r
//int value = BW.at<uchar>(191, 51);& d+ E: z5 @6 v* i
int width1=dst.rows; //處理之后圖像的行列 H/ O2 i" M# K7 y/ x( G& A
int height1=dst.cols; //處理之后圖像的列數量; U- D, o4 E# m4 v" @" o
W! t$ a9 @, g6 u; V! f% V
for (int i=0 ; i<height1; i++) //從第一行開始 應該從最后一行開始向上檢索,這樣可以減少計算量,一旦出現與之前曲線K值相反的方向,則確定是拐點,不用再考慮,但是要考慮出現切線斜率始終是減少的趨勢,這種情況下往往是蒜尖- t3 `0 ^5 F+ @; i L2 A
{
4 A. o/ {3 }$ S9 K8 f7 U. c& W for (int j = 0; j < width1; j++) //從第一行的第一列開始
, W& F; W6 }) q4 { J/ X o {
5 P4 v1 ^4 J6 D& O //int index = i * width + j;
7 f8 h. K: o) h4 V int value = dst.at<uchar>(i,j); //讀取給定坐標處的像素值
) ^+ b/ z- Q* d, a$ B //if; //像素值
! B, g) ?$ q* N //int data = (int)dst.data[index];" I: x r* f/ f2 d: C+ k: ]
if ( value >200) //如果像素值大于某個數值,則將其地址記錄在數組內,且僅記錄首像素,后面的舍棄
* ?6 d$ t( y2 y, t: N* r {
3 ]: C3 T4 m& w) u* S a[i][1]=j; //數組值等于列數,便于后期對比
+ h. g/ d. e; I //cout<<i<<" --- "<<j<<endl; //i為行數% f; b- E3 c) S( F4 V- V$ s. k" a
//cout<<i<<" -坐標-- "<<a[i][1]<<endl;0 N. B1 L% ~5 s/ m$ l/ ~
if (i>1)! a9 ~3 n$ r& ~. o6 x
{ //11
+ o' d5 W) H4 o if (a[i-1][1]<a[i][1]) //如果第一行中大于某個閾值的像素地址與下一行相比靠右,也就是列數比上一行要大,則說明該曲線向左側傾斜,說& A6 }0 D: x- L1 ^/ s0 b3 s0 G
//明是底部,如果曲線向右側彎曲,則是蒜尖 (之所以用i-1,是因為總不能和沒有像素的地址對比,所以必須向后取值)
2 H5 J7 R6 S6 J9 e9 [ { ' b. a# [3 x( o4 J
b[i]=0; //因此,當下一行的地址比上一行的地址小,則用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。% ~4 a/ _! O3 ^0 t5 _
}& k" R+ v9 ?, w$ @2 @
else if (a[i-1][1]>=a[i][1])
% ]' p0 Y+ B: j1 N$ k {
! A. V4 P: h" v9 W* d7 }0 g. @ b[i]=1;" _" C4 Z8 n) } H3 _( \
} }! j7 g% B3 s7 N
! r0 w4 o% x$ s& y8 ~. E
cout<<i<<" -標識符-- "<<b[i]<<endl; 6 D2 E6 B4 A) d+ v6 Y
//cout<<j<<endl; //j為列數' X6 N6 {. o, s. G: K
} //11- w6 T# N* E) W8 {+ C6 z2 Y
5 G7 {1 ]1 e( I- a7 |
}; Y [; v# `* f6 c! s9 w
break; 5 b" z* k% V; ~* F7 V1 w5 {' P, S. j
}
* x4 j J* Q& T' T# W }
; U* c; Q1 s# G* H }! E4 ?! b; B4 j. n) y0 F$ }
//開始對b數組進行分析,確定是否為頭尾(但是需要對曲線進行圓滑處理)
; d0 R3 @7 T- c/ M4 x D for (int i=0 ; i<height1; i++) //對數組b進行遍歷,檢查是否存在誤判的問題
w2 I3 m+ ?& K8 D# v //尋找拐點,找到用于判斷的后段曲線的拐點. U, x; ?7 p1 b+ P0 h
//對圖形進行圓滑處理,除了最大的拐點之外,盡量不要出現折線
2 C/ z5 Y, K- c7 Y
1 A( d9 b; v& G/ d- Z : v9 [% d M( B1 V4 C& S
' ?3 ]) r. Y7 B- U& R // int width=dst.rows; //圖像的行列
" C5 Q: B# x+ Y //int height=dst.cols; //圖像的列數量* B# l+ D; @2 l9 s# n( y
cout<<width<<endl; //顯示行列的具體像素; ?4 r) c3 ]6 `
cout<<height<<endl;
8 g' g4 n4 [! \& Z) Y: Q( M& J //for (int i =height1-5 ; i>20; i--) //對收集的坐標數據進行分析, M# H! b# u' M% U1 `8 r
& b) } Y' H# w$ B* w. S! T
// 等待用戶按鍵。如果是ESC健則退出等待過程。, n! P7 |! @3 k
while (true)5 c0 H% l' l9 O
{8 r- _& ]6 b5 S/ q, P7 H2 w
int c;4 l2 z. W9 v# {7 x7 [+ j- H
c = waitKey( 20 );. D& ^6 H/ O4 r2 X; f
if( (char)c == 27 )" B" `. V8 ]7 m# {- C6 g
{ break; }
1 w+ P. n& \" F' x }
) H( V l1 g/ B
7 N5 F1 P$ z$ C H- J5 r3 [}
. r+ |5 C- ^1 P3 U6 C# k6 v: D8 N; T' a- V
1 ~4 L; n. D. r/**" H* P4 E8 k2 q* R, I! Z" f
* @自定義的閾值函數
9 B" |) q& I# d6 ]9 l */
1 b( w: j8 {7 D: F" q P# S6 ^void Threshold_Demo( int, void* ) b8 v! S) R$ n S
{6 f0 T8 D8 Z' w& W0 [
/* 0: 二進制閾值6 u0 N: C1 W9 |# o% _
1: 反二進制閾值/ e0 v. [9 b8 J5 w3 {7 U
2: 截斷閾值4 F H& U# Z g( G! q
3: 0閾值
) [! @) x2 o- ?4 @! X 4: 反0閾值
4 A9 h4 }$ a* ~7 c */) m& N- `" i+ e9 A8 X
6 u( ^/ S: O0 ]4 ?) P threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );
: p K3 t8 V6 L* w, R9 _1 ^7 N- l8 l' r! J
imshow( window_name, dst );
/ }( H! q% w" v}, I6 L8 D' ~2 b( k8 s, u0 G
. `! ? ~ n4 z3 R% @
( y2 z8 Q- A/ G# \- t
3 |# b9 U D. u8 ^9 ^: l) w
( \! B* l5 m; q0 p3 p3 h9 c
) B- n5 {6 r& A U/*
+ H; u- V! ?& avoid main()
0 V' i r2 z+ E9 E( j4 f- z" e{
5 u$ D7 L8 a3 v# z) y& e5 u$ m q . r3 Z7 Y/ a$ s: ]/ M
//讀入彩色圖像 單通道圖像(CV_8UC1);CV 8位未指定的1通道的圖像,backImg是單通道灰色圖
3 l5 U" W2 R! L1 K1 j2 p) D 4 P$ {$ Z1 j: |% w3 k
//Mat img = imread("fruits.jpg");
& w; g; b2 @3 F& _2 I4 E5 e0 B Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在讀取圖片的同時直接轉化成灰度圖, 下一步是要將像素亮度超過一定閾值的點提取出來,并找到該點的坐標,然后記錄該點坐標,用于后期的比對* ^( I; q' {2 y V
imshow("灰度圖", img);) b" J- L+ ]# p, u9 ~* d: w
//確定圖像的尺寸,行列,
4 i3 G8 e* S: f6 L int width=img.rows; //圖片的變量名加上行列,就是行列的數據: ^ |9 t2 F' A6 m# C; r! h
int height=img.cols;. ^, K" N7 Q: F7 P, p1 s4 L" e
cout << width << endl; //顯示行列的數據 本圖片已經用358的像素值裁剪了,所以形成的就是高寬都是3585 \) f% D/ ^/ \' u' X/ ]$ ~* z" E
cout << height << endl;
. ]- g6 H5 O6 H; d8 t$ Z //定義一個二維數組,a[i][1],其行數等于圖像行數,列數就一列,用于記錄圖片上像素的亮度超過某個閾值的像素所在的列數,用于下一步的對比。
2 p4 V. Y3 J4 A1 l int a[358][1]; //確定一個358的二維數組5 D C% z/ _! t f; u
1 I! }4 p2 |0 V( a# a( }//int height = backImg.rows; //backImg是圖片變量名, t" _/ S+ B4 @3 |0 z7 O0 v
//int width = backImg.cols;
, e1 n* x6 Y2 r+ i! Efor (int i = 0; i < height; i++). i# U, `$ ?9 g. x/ a. ^
{
: O8 O5 D6 I+ u- w; Y6 q for (int j = 0; j < width; j++)9 w0 ]( X% j8 C
{
+ I- |1 z: G6 K3 j' G int index = i * width + j;" g- Z0 B$ G0 u5 ` u1 j& \
//像素值1 m* N V( y2 I" B0 {* r
int data = (int)img.data[index];
+ d# A# E! G1 q0 Q" Z. J0 ~$ t }
4 h1 T+ C) N2 \* @ f1 f9 y }. j" a1 S1 r& e. s) ?
waitKey();3 M$ T# n3 A, ~0 t0 u+ l
}
+ U. ^6 T4 Y7 `1 Z0 T*/ |
|