|
楼主 |
发表于 2021-1-2 09:20:48
|
显示全部楼层
#include<iostream>
9 W/ F) q; J" b% ^5 R9 y#include<opencv2/core/core.hpp>' z3 {' q% t5 F
#include<opencv2/highgui/highgui.hpp>
9 P; m7 W' m- f. `9 n; O* N#include <opencv2/opencv.hpp>6 H3 U! k: @) G* z6 c' T! j
#include <opencv2/imgproc/imgproc.hpp>
: q) W8 L9 w, n/ d9 x/ h#include <opencv2/imgproc/types_c.h>& m/ U9 A5 u; K) z8 I, o
#include <stdlib.h>8 y& N/ u+ L+ t. U. \- g
#include <stdio.h>
" V0 D! Z( F2 j+ I- p: y. O+ s#include <opencv2/highgui/highgui_c.h>% W2 S* }" k% a# u& l$ L
#include <math.h>, o/ k4 b2 e, ]! B8 ]
//#include "iostream"
% T+ l/ z" B+ G& i# w//#include "cv.h"
6 |1 ~7 |; `, I% f [$ v//#include "highgui.h"$ O# q9 t1 C: |$ ^- S! ^
//#include "math.h"% W: N& D2 u8 F. K+ h4 \; D# z7 _1 f
using namespace cv; //命名空间CV6 ?' G; A, L9 l3 X" D! b+ v
using namespace std; //命名空间 std8 s/ y: |, F/ Y$ h% R
+ K" h1 T9 x0 j+ G. t- w
int threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。; S0 }! r5 o$ c: b+ N# O: i" W
int threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零1 p' o. q2 [$ x7 R# Q4 W
int const max_value = 255;- R, w. M/ F' W" B* s% i
int const max_type = 4;' [+ @8 l# j5 S8 B
int const max_BINARY_value = 255;
8 r: W2 u# y) p5 Y
( W4 c& ?3 I3 z, V% M' [1 E% P CvFont font;
m8 w& B/ w2 p/ V9 e0 P: c4 k; r uchar* ptr;
O) a1 w( a: X3 `6 l" ~- d char label[20];
+ z! y1 M& c) ?( g" a) ?& ~( a' f char label2[20];
. f3 K; h/ u7 m# Z9 x
+ e4 f [2 F; Y; vMat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图
5 r, T& u" ?- r3 \ //在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao s4 }+ Z# r2 M
//例如:char *string="I love C#!"' W+ x0 a$ i u9 `
//定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/" g7 V- C S* Y
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数
; l0 q, c- L2 ^. c1 V& kchar* window_name = "阈值演示程序20201121";$ f3 f, W1 P; a4 V
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //1 _ p3 \4 P% Q
char* trackbar_value = "数值";
' T9 t% N* f; ?
5 K4 ?) v. k; l, z# c) a/// 自定义函数声明$ e+ ^) K4 A% L/ j3 {3 w! a
void Threshold_Demo( int, void* );
# k# }2 D1 _ d& ~: V9 `1 c% g' l, y) K
/**, L/ m1 \. }) L
* @主函数
\9 R6 s1 I' A$ w, u g *// G" v L' `, L: V: N) y
int main( int argc, char** argv )
( H6 l% f& z; K! j) b7 o3 I{
4 N5 ^) L+ [4 f- q2 I+ M /// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)6 V3 c- N+ S9 \: g; g
src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。
~4 Y& N' s8 ~ erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪/ H) M5 @) h3 C7 S9 x2 X
blur (src_e, blured, Size (3,3));//3*3内核降噪 m% M0 C1 R$ U
imshow("腐蚀和降噪后的图片", blured); //显示图片! E* T# T& q: D( ~7 X2 d
int width=blured.rows; //图像的行列
. T1 g( ^* n6 ^, u4 ^) m int height=blured.cols; //图像的列数量5 G( L/ a8 L6 e5 z; h8 S; l3 |
cout<<width<<endl; //显示行列的具体像素
( r$ s5 v+ U4 g! M& I cout<<height<<endl;
" t( b5 x, b% C' U/ O int a[500][1]; //定义整型数组,后面的1应该可以不要的- P' J/ g. a3 }' T. O! k+ y8 @1 i
int b[500]; //设置一维数组,用于判断曲线的切线斜率
$ R, u5 c( a4 E# }9 [( j- |
% a, `7 f- O! T) I3 M) c /// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
+ X% p- b# d% Z2 o% A- e, ~ cvtColor( blured, src_gray, CV_RGB2GRAY );
( C* m* u' N4 \
! |- I7 t. o# P: G* Z6 G. m /// 创建一个窗口显示图片. L% o. e7 y. \( j2 x% @
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
+ V8 l8 F, v9 Z& j. `0 a
2 t+ P7 X; r! s /// 创建滑动条来控制阈值$ }4 ^) a* r: E
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
2 `6 y! j6 u4 o; {) Q+ {
2 v5 N( } p: Q) I$ w" |6 [ ` createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);- j. |. t. u' U$ a$ Z) I. M& o
! |3 N7 ]1 ^# R' R' b /// 初始化自定义的阈值函数$ _+ J2 M( c0 \8 q/ h7 f. j- P
Threshold_Demo( 0, 0 );
; s/ Q8 I4 M# [/ E
" i9 F5 v5 ]' c4 X$ j3 N0 J, D // Mat img=src; //暂时无用5 x% T/ ^, u; v4 z1 d
//imshow("转化之后图片",dst);
! }4 z% ]3 n1 J" Z4 `2 U8 f9 R7 _9 p: D b5 b" P, M! o) k! C8 v
//遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较
5 I, g1 c; w; q O T+ G! R ' I% B j/ k, f, ?
//Mat BW = imread(imgName);
1 a: E' c9 a# G2 J) k& P- Z' H//int value = BW.at<uchar>(191, 51);
% L' K% O3 B2 U" h int width1=dst.rows; //处理之后图像的行列
: r$ l7 m, ]5 O int height1=dst.cols; //处理之后图像的列数量( e5 K2 f4 g- E/ l& n, r" T
6 H- T, p! Q& }9 u for (int i=0 ; i<height1; i++) //从第一行开始 应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖8 }! y# v1 D1 v- G3 G9 W% Z( y! K
{
' N+ _! Z' e# T- [" o+ n+ \ for (int j = 0; j < width1; j++) //从第一行的第一列开始
3 W$ l/ p% b: I( }% y/ i {
* U+ c G# G' Q //int index = i * width + j;
1 V" c7 p( I# S: q; w% d% T, H- O int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值* G) s# ` M" J) j
//if; //像素值
; J. w5 ]+ F& k5 Z( G //int data = (int)dst.data[index];
2 q) I* Z: r+ u; K if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃
; R7 z; m. |( G3 g/ E: S { + O0 `( P" W! }4 H
a[i][1]=j; //数组值等于列数,便于后期对比 x; }4 S( t+ N: t
//cout<<i<<" --- "<<j<<endl; //i为行数
9 P4 [( j' O' i //cout<<i<<" -坐标-- "<<a[i][1]<<endl;
& G7 t/ B8 |# x- v8 S7 u% o if (i>1)
- j4 v' e. {) b8 C. p { //11; ?9 h* B0 e5 e6 `
if (a[i-1][1]<a[i][1]) //如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说
0 A1 B6 z9 c- \. e2 O //明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)* j, q3 z! s9 }$ S
{
; i, C# M$ A7 z( h3 a" H- j b[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。
& o! Z: J# w/ w; b* m3 R }: V% ^/ G8 s! v- t! ]' R- u
else if (a[i-1][1]>=a[i][1])
8 G4 Z7 o: h# A {
7 `, Q5 G; M; H- P1 V b[i]=1;
. l; g% f/ R- z1 G9 H1 x6 ~ } s1 R8 f$ p; u3 K, G0 L( x
+ y9 l3 ^% S+ O6 A
cout<<i<<" -标识符-- "<<b[i]<<endl; ( ^9 I5 z9 ~3 w1 I; q% f
//cout<<j<<endl; //j为列数% ~7 E) }- X4 T1 k8 i7 S
} //11, G7 K6 S0 M8 J2 K; [
$ R1 }7 ?. r& e6 q% ?- X4 ~% y) w0 p! O, F" ?
* |' O% r+ T P
break;
6 `- s3 T" m7 f: q9 v9 s0 i- G# `4 S+ _ }6 q" k3 w, a' ~$ l' L6 R5 _/ ~4 z# m
}5 D2 w( w5 n6 Q# p
}
' t, F. }" j1 a. Q* y //开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)
9 r& K4 y0 Z$ ? for (int i=0 ; i<height1; i++) //对数组b进行遍历,检查是否存在误判的问题
) T( E1 z! X1 S //寻找拐点,找到用于判断的后段曲线的拐点
4 {2 R$ q& r( m1 F //对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线; P7 O. X. n" e$ h3 j
* D; i% L6 G# c9 C
1 h) _/ x# ?* K7 K. W: |* B" C
7 X5 \) q* G" @5 h5 C // int width=dst.rows; //图像的行列: V; m) k7 C! q7 D$ u8 a
//int height=dst.cols; //图像的列数量; E3 y D; c# v8 _- P
cout<<width<<endl; //显示行列的具体像素4 E6 P1 J1 E$ S5 j. `
cout<<height<<endl;
' _- \& r( f8 Z* Q* m0 c' t [" R: r //for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析4 P1 N2 [2 j9 X
8 P7 ?2 s, c6 p) L; y* u6 J; W // 等待用户按键。如果是ESC健则退出等待过程。* q" T7 E( I$ D5 {( Z% S6 H/ ^5 s; k
while (true)
M8 t2 H5 V @* w {0 U5 t6 d! g5 P$ t2 @4 q. O% e) u5 o
int c;
& `/ A) [3 Y8 o* P- M c = waitKey( 20 );
9 ^0 [3 Z! i" M% ]; U if( (char)c == 27 ); `" I( I0 |" l/ y
{ break; }
) s' n! F7 @6 q& _2 A4 }, k$ G% p }" P) [8 x1 r0 t2 r2 q5 K
- l1 Z4 t3 c9 B4 l}
% H0 W7 ^7 c- ?! M: h- Q# F/ a. B1 f9 x) V9 E
% {9 a1 R, n# U% v; F8 l/*** I; A6 ^ n/ }" p$ S: D1 R1 Q
* @自定义的阈值函数
, z0 o, W" t3 A */
h. q1 N! c3 D& x8 mvoid Threshold_Demo( int, void* )
8 B+ @' _5 Z! w3 G8 |, k; Z{
- o4 [: J3 j* \ /* 0: 二进制阈值
; f& ]# R5 d7 | 1: 反二进制阈值
2 |3 l! K0 u% ?* X$ ~ 2: 截断阈值7 {3 q% `6 z9 V7 g
3: 0阈值
6 W) c# V: ?4 o* g2 G& y' c$ w& } 4: 反0阈值
$ o6 B3 e/ Q6 d, [5 ? */; h* G) Z' k4 P8 }: M) c
* U' q& C- _1 C# z+ t" y+ p+ f threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );; c. P6 K0 G! w7 l8 V3 w8 o
. L, A! V0 D; S+ [2 T8 ]
imshow( window_name, dst );
( x8 g i! @2 r: W3 o) t/ }8 Q x}
0 ]5 R( D1 {! z* j8 S v
5 n" E* Y5 a0 N. z X
0 @! n8 N5 P+ v% M4 f4 f; G/ K% F
! D% {4 q) M* Q! j3 N: y
, M9 q4 N& s+ N* m8 b2 }. n* `+ e
/*
. _& K- ?. s8 h/ nvoid main()" H/ J4 E: L2 P8 g
{$ C- u1 d" H+ G( t" K
9 \3 [5 G5 |0 S# X# X: _
//读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图6 ?& p5 d6 |7 m! L* } [$ h
& S( ], d. L/ v6 n
//Mat img = imread("fruits.jpg");2 S1 ]# e1 D$ O
Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
" p1 S& e- E% j7 d9 H imshow("灰度图", img);
+ C/ A" o/ Q! o //确定图像的尺寸,行列, U' b1 b4 {. L9 [+ p: a, A& C- b
int width=img.rows; //图片的变量名加上行列,就是行列的数据$ b# e4 x4 i1 I! h* d5 e' q4 I8 O
int height=img.cols;
& R2 o5 b5 n i& @3 p cout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是3586 N; m" X9 Z- x) X# }
cout << height << endl;
( r0 y: [ m6 X8 _* `) t) |2 K //定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
+ ~* Y* X3 m' w' E int a[358][1]; //确定一个358的二维数组
. v8 Y+ x4 W' m9 m' Y( Z5 I- R+ p
//int height = backImg.rows; //backImg是图片变量名
- ]: l! @+ S4 M1 B ]$ n9 ^//int width = backImg.cols;1 A. s6 z; c1 |: V1 |
for (int i = 0; i < height; i++)% [4 Q1 u$ K9 I* V, ^0 t
{
% `4 Y( \6 T* W, c8 F for (int j = 0; j < width; j++)# A1 v% f9 k0 @0 U" k6 F' O: _
{8 X! t) r& Y- i, K7 I+ K
int index = i * width + j;
! u9 s5 `2 q \" ]( e //像素值
7 p# Y8 o& S' n7 [- G. D int data = (int)img.data[index];- F2 c6 Z* O* I8 a% Z0 b
}
/ L4 P% U8 D3 V5 c2 U; j1 z* l2 m. z }
. t! W% u# u8 z$ I: D& D+ i7 i waitKey(); ^+ d! ]2 q+ z0 n
}
: k' x9 ?# o* H6 c*/ |
|