|
楼主 |
发表于 2021-1-2 09:20:48
|
显示全部楼层
#include<iostream>
3 C( l3 L" h1 g* Z#include<opencv2/core/core.hpp>( X& Z- I M) ?2 X/ ~" H3 v1 F% p
#include<opencv2/highgui/highgui.hpp>% K. M4 G+ G! Z# e7 y) N ]
#include <opencv2/opencv.hpp>; T& o2 S k. f, H: b, Q6 C
#include <opencv2/imgproc/imgproc.hpp>
: ~8 P" G$ n5 O#include <opencv2/imgproc/types_c.h>" a+ m1 i7 B* a- c9 q$ k
#include <stdlib.h>
4 u( O8 l( |0 {9 q#include <stdio.h>1 W2 r p1 ?- \4 \- ]. G
#include <opencv2/highgui/highgui_c.h>1 Z7 X9 E" E0 \8 r
#include <math.h>
- P% q6 h6 s% V! H0 D, s$ J0 S+ \+ @: H//#include "iostream"+ N& X' U! i1 m; {
//#include "cv.h"
: n5 }% l5 T8 j {) ^0 u$ I//#include "highgui.h"" v4 L* K6 a) ]/ F) g, x+ v' O3 V. T
//#include "math.h"
' O/ |& C8 O. ?8 Ausing namespace cv; //命名空间CV
9 F* @- B0 u) |8 m$ ?; Zusing namespace std; //命名空间 std
! z9 `) W" ^+ S: m/ P) A% `
1 {( p6 z6 r: t" A. ]' Yint threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。
4 B6 `: O4 R5 _3 K, pint threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零
. m- n" e( S7 ?6 }1 hint const max_value = 255;
- d( c% L4 z4 D* K' v* ]" D! O, U! h1 \int const max_type = 4;$ x5 z* V0 [% ~( y. Z1 L
int const max_BINARY_value = 255;8 p% F/ u3 ?' D# U7 {( n
6 P( q3 i, b: X0 Z f. |% U6 C
CvFont font;1 I+ |5 N% Q) q6 h
uchar* ptr;0 n: k9 q a# G+ U
char label[20];) L* P5 i5 F% M6 z7 `! `
char label2[20];
1 V+ `0 v! C; v6 C' l1 P8 [! A, @3 q7 x( q- Y z% D8 {
Mat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图* A0 R8 ?) I/ n( s
//在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao: k$ O: r( t0 {$ w; e
//例如:char *string="I love C#!"
: c$ D: \+ M# F2 j //定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/
1 u& \+ f6 T+ z( S, m, BMat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数
1 j$ q8 F) i8 R: T2 c3 lchar* window_name = "阈值演示程序20201121";" Y9 e* E- ?8 C6 w) |
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //) \+ y) Z1 C+ g: C8 e( u
char* trackbar_value = "数值";
6 \% B- L) J& s9 ?. M/ f8 i3 j; _5 p. D% J% V( Q2 e( H% K% @: p
/// 自定义函数声明* s8 n ]$ _% U
void Threshold_Demo( int, void* );
; u4 |8 W6 t" f( h7 n# i
2 ]* D! s% S1 G4 e; w) e/**3 L3 r9 { c) D& ~/ ^# [% z
* @主函数
! b4 H8 d: P# q. E" { }8 N q */6 n+ r3 o6 t" V" Z" Q" o$ H" I
int main( int argc, char** argv )( E/ C; e! {+ c1 Q+ K; X
{6 s2 J f( i. ^8 m
/// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)+ k# t) W$ g8 c( T$ J! z' j
src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。6 ]' W+ {- ~% s
erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪
+ e5 _" W) @! [% H$ ] blur (src_e, blured, Size (3,3));//3*3内核降噪, h$ |$ _. N5 \3 v
imshow("腐蚀和降噪后的图片", blured); //显示图片7 W2 D. t8 P( P, y1 t( y6 b
int width=blured.rows; //图像的行列5 \: e/ t3 z1 ~) D
int height=blured.cols; //图像的列数量
* v* T+ w3 P* R: X: N @ cout<<width<<endl; //显示行列的具体像素
5 a" w" r8 O9 w& H+ j" R cout<<height<<endl;" Y( ]; k& U9 @
int a[500][1]; //定义整型数组,后面的1应该可以不要的
' V4 m" Z, z$ p5 n W4 Q int b[500]; //设置一维数组,用于判断曲线的切线斜率: A5 [9 L' I1 |# `/ N
+ g4 c. ~$ V6 j& M3 c- G. K( B4 `
/// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
' {9 J& u* @- ?( f) B- c' ^ cvtColor( blured, src_gray, CV_RGB2GRAY );
" t/ _8 ]) v1 }0 Q# T5 o; d7 l# }" W+ L: t. b: n% B/ u
/// 创建一个窗口显示图片
4 I& y" l& O% j namedWindow( window_name, CV_WINDOW_AUTOSIZE );: M5 p' W7 T: F5 \- m$ Q3 ~
+ P. o5 D% C3 X, J. ]. }7 W /// 创建滑动条来控制阈值3 r# j; R7 L, B1 h
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);( ^7 t- \& P& J3 w |3 i- [
4 B0 j' X- l- \+ R, b R
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
& Z9 @4 \6 F6 w0 t$ H8 F- z: R5 E# h! A& A- V+ d; F
/// 初始化自定义的阈值函数; [& i' B: ~$ @+ }- h
Threshold_Demo( 0, 0 );
; f/ l5 {( w1 Q, d; Z% ^
) [& i) F0 d7 O+ ?( `5 N // Mat img=src; //暂时无用- ?1 a4 {1 x) Y3 L L
//imshow("转化之后图片",dst);& b B& N5 h5 `% i+ E( D4 r. `3 s
" ]* [7 }' S4 }) x, z //遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较& t: I$ k- S- }3 F
) ?$ M* E- E5 c//Mat BW = imread(imgName);: H* n* e$ k8 q" E
//int value = BW.at<uchar>(191, 51);
4 t" Y* F$ Z/ L* I& E int width1=dst.rows; //处理之后图像的行列
0 r6 y, J/ ]; M$ e6 D6 }' o int height1=dst.cols; //处理之后图像的列数量9 x9 @% U5 L5 F
. m* X; O- _7 J, M" C( M! j for (int i=0 ; i<height1; i++) //从第一行开始 应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖( ?7 d; S% E3 }4 E5 i& X- h1 E
{4 c. T" u0 Y. m( y6 F: S! ~
for (int j = 0; j < width1; j++) //从第一行的第一列开始2 n5 s) L) m2 t) c# R* O
{
: y5 E' }& O$ W; t# X //int index = i * width + j;' e" P# o1 k: M- ^& @; j
int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值
# k+ l+ ]' a( f, [& P //if; //像素值" w/ \4 h' ^' H) ^, J& L+ D
//int data = (int)dst.data[index];
$ E# Q7 G3 N# i! ^3 J9 N9 F2 f if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃
; g, B6 i, F7 i: J2 ?; C" Y { : W: Q0 Z- I* ~
a[i][1]=j; //数组值等于列数,便于后期对比. g+ x4 D4 N" i: i. j) l
//cout<<i<<" --- "<<j<<endl; //i为行数! Q6 F' _7 u" n1 o$ Z% I
//cout<<i<<" -坐标-- "<<a[i][1]<<endl;% K! U3 A) q1 c: k
if (i>1) H) F" Y3 j# T" K4 x8 C) h
{ //11
- ~2 k/ f! A9 x) Z1 C if (a[i-1][1]<a[i][1]) //如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说
- D- j6 F5 ?1 r5 p //明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)! Z. j$ D# l8 F
{
3 U" P1 h$ u( V! ? b[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。
; L/ c! R' A+ C/ u$ b }8 b/ x- ]8 ^. d% q7 p7 P3 ?
else if (a[i-1][1]>=a[i][1])
$ z6 Q: X' E5 z# Q& n {
" b& B8 }+ ?; E; x+ k b[i]=1;
7 p! r0 v8 L! k+ I1 B" ?3 ^ }3 W/ w7 M' V O9 I8 j2 L! g, J
0 ~: o6 L) h- U7 y cout<<i<<" -标识符-- "<<b[i]<<endl; - s" s; d# H5 Z0 D2 g
//cout<<j<<endl; //j为列数. B# A9 p- b- G5 c( T3 L
} //11
0 j# c* K9 A2 W7 d2 E( n
5 O; n5 q% |/ R" L# w! f
d3 y8 A6 ~1 s, X4 X8 o break;
: a. x1 {! x. i% B$ Q/ F. K; U* C }$ u# C8 t0 \4 Y$ y
}; y2 ^+ Z7 e% E* Y* c4 l5 Z
}7 i+ R4 |( G; n" Z8 G. a
//开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)
/ ^% G" g7 `" K! K+ O( E6 T A for (int i=0 ; i<height1; i++) //对数组b进行遍历,检查是否存在误判的问题: V6 Z( i% e/ }' x" R
//寻找拐点,找到用于判断的后段曲线的拐点
' R% c5 C$ A. @* x5 A4 C/ h //对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线3 h) Y, G& `, I3 c8 }
/ b2 c5 {" r. H/ l( Y
( D `$ H. ]5 H4 H5 [, Y + `: n9 D7 u) r, m
// int width=dst.rows; //图像的行列
: o, s" ?5 O+ J9 s: } //int height=dst.cols; //图像的列数量% T G. V( X* g7 @5 g6 X* x) |
cout<<width<<endl; //显示行列的具体像素/ V1 |# m, w& K! I( n0 \
cout<<height<<endl; N6 G' c0 `( o! x' }
//for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析
" V6 Z1 e- q. h7 n- D( Q) K$ c- k5 L
7 W; c0 g; w! T* d // 等待用户按键。如果是ESC健则退出等待过程。
, _# V/ o2 h8 B, b+ I while (true)+ m! m2 C% O; y. ]
{
9 O0 }. [. d6 o int c;. ]; c4 v# H6 L" P4 q0 @( B; x
c = waitKey( 20 );, f; |, [# \9 }) x4 U- y* |" a2 v1 F
if( (char)c == 27 )
; g+ b6 F) S5 W2 x: C$ u" F1 D' f' J+ V { break; }% z, Z4 y# H1 l1 ?0 [; x0 }
}+ R& t8 J0 b8 L3 X" E0 f
9 @6 s: J. w' U, W. k1 Y! c}
: t/ I) a4 U" y
' T; _( _$ M# W( o
9 B/ g+ b) q4 g1 E* V/** V) y8 [' \3 s! \% v
* @自定义的阈值函数
8 A% E3 F" i( q */
0 Y# b( b7 {/ y- J8 Q# F% qvoid Threshold_Demo( int, void* )
4 k" @: v: C& N6 G4 B: a{
* c$ r/ I1 b" S# e9 h1 K /* 0: 二进制阈值
4 t* ^$ |5 i+ Q2 d" Z 1: 反二进制阈值; h. z( w2 T- S) ~; a
2: 截断阈值# O" K P- C2 e9 Q; o' A
3: 0阈值
& ?, x" K2 Y& |/ w0 ? 4: 反0阈值
+ {. ?- c( l& ?4 F6 U6 ~ */4 W1 d0 V$ D! F4 F
) u+ t0 a! j* C1 D1 B# b; u
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );
: W6 |5 Q5 {: j9 |3 P5 r# t: I& p$ K: o7 o0 i2 x/ l
imshow( window_name, dst );! e5 O- u6 k! F" j# Q
}
+ H& L- _# w2 @ P4 w+ L
: D8 ]* ~9 [+ k% _; N" D! u
! Z% J x* p1 Q9 x2 ^* q* _/ x9 {6 F: J/ y3 H
5 d& i' m% G& I9 b! x: [. I
$ b% @/ b4 x% i4 }/*
4 F* {% a/ k1 m5 V, Qvoid main()
6 ~ y: m3 G- s( F! l7 V( n& Y{: }. Q( ~" a: G# }
9 F, v* s6 O; ^- w% q* U //读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图; o8 @& A; Z5 d# D [: B4 j
# {6 U) ?( F+ j+ M/ z //Mat img = imread("fruits.jpg");
1 A( C& v2 x6 J9 T$ r% M Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对: W$ W1 G: v6 b9 O' z
imshow("灰度图", img);
+ Z! g* M) e2 W5 P //确定图像的尺寸,行列,
: M) P8 u' Z7 D int width=img.rows; //图片的变量名加上行列,就是行列的数据
3 F2 B# J0 n# ?, H# m& n int height=img.cols;
4 F5 |" j, E' \' v& C+ b! ^( f cout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是3583 @/ v$ @8 [# _; u; l" `
cout << height << endl;
7 z6 ~. F2 g6 ^4 {1 i //定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
. Q1 b/ M% b" I int a[358][1]; //确定一个358的二维数组
( h9 `9 A3 A' O5 x6 n D
" g! y. V0 s$ p9 C//int height = backImg.rows; //backImg是图片变量名
+ H; q% L) M' I- W//int width = backImg.cols;- ~" v+ k; Y2 ^
for (int i = 0; i < height; i++)
8 U7 k& T/ F9 T5 P* P {; Q; j6 Y+ I# T) f0 x; F
for (int j = 0; j < width; j++)
1 y# U3 U8 K7 ^7 |6 u {
* u6 j: u/ ]2 v4 w2 \ R: R int index = i * width + j;$ V* P9 Z7 N2 G" |
//像素值1 H3 l* g$ i% S& P* a8 l- b
int data = (int)img.data[index];
/ ]: ^( P* w, p) f }
7 E( T: y6 J1 O- } }
& S3 r0 `+ L8 `2 l! m# |' M! @ waitKey();3 C N6 b0 K$ T) |+ w' _3 X
}
5 E2 S0 A- a- j*/ |
|