|
楼主 |
发表于 2021-1-2 09:20:48
|
显示全部楼层
#include<iostream>. V" O3 b, Q3 t! i4 m$ e5 G/ V. Z
#include<opencv2/core/core.hpp>
" O( j# V5 Z' q+ n# H! Z#include<opencv2/highgui/highgui.hpp>& ^! s; A* z0 f3 y2 c
#include <opencv2/opencv.hpp>
7 Y- |- r( y/ e7 B! \#include <opencv2/imgproc/imgproc.hpp>7 S3 B6 ^, `- R' P
#include <opencv2/imgproc/types_c.h>$ F+ }6 f& j- D2 ]) f$ X# {
#include <stdlib.h>
; W. u, N! w9 X/ q. ^#include <stdio.h>! R3 `3 y% z6 q& ^: u6 k" V$ G
#include <opencv2/highgui/highgui_c.h>
8 a9 z& v& s; B( W, y- |' [2 H3 q7 `#include <math.h>
2 u1 _9 h: B @# A//#include "iostream"
2 S0 f/ `* }8 A/ T//#include "cv.h"
1 Z& S) C7 U& R! Z0 e//#include "highgui.h"0 T- Z3 a8 r/ @! m0 j5 d- u7 N. q
//#include "math.h"
u/ _) L2 m/ C$ Q# e4 Eusing namespace cv; //命名空间CV
2 t. c/ {" f- Rusing namespace std; //命名空间 std- K p" ]( z' i3 r! p( w
5 u+ g, p' U, l* `
int threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。
. P2 m6 Z" Z9 {+ P) E5 S& ^int threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零
+ }' o0 w( X# d# W9 V) \# z4 yint const max_value = 255;
- }3 K- s: A9 z+ W I$ lint const max_type = 4;- @/ }% p5 Z0 W, Q
int const max_BINARY_value = 255;4 J8 ~ x% B2 k. T- ?
; }1 \- ]+ i! I+ `1 O o CvFont font;) M$ m& L: T$ H9 q, _* U
uchar* ptr;; p; Q# T5 |) F, `) O( x' C G: i* W
char label[20]; `& W( o' t1 ~' L; \( ]
char label2[20];
8 P4 N, ^" r V
; {) C0 D$ Y" {Mat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图
- x* p' D* q! z% m //在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao
7 J& n% I7 [# X7 J L) ] d //例如:char *string="I love C#!"" p: Y6 n% E2 c- d+ T! C, n
//定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/; Q, v1 C1 Z, @1 L, s
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数
, @# e1 P( Z8 tchar* window_name = "阈值演示程序20201121";, [2 ]7 o; V6 P2 [" Z- [6 C" j' Z
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
4 z( H# o( H( Pchar* trackbar_value = "数值";
4 F& \! |) {) y. p! G, D/ K3 t* G6 p+ r
/// 自定义函数声明
- {" Q" `/ L6 @# K( J. A# u) Fvoid Threshold_Demo( int, void* );6 H; b+ g8 _! Y" {
$ [, y3 _0 M( h
/**' C2 f# a: S, b
* @主函数; h0 ^8 ?5 J/ D1 s1 |4 c }
*/8 v) p& G5 V$ Y
int main( int argc, char** argv )/ x9 k7 I" ~* t+ j! c+ q& H
{- v6 P( g/ B) t; c. L
/// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)
2 s4 ?4 _5 @) U: k% } {# ~$ b src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。5 k: a9 z/ q3 |% l/ Q+ j, P3 I
erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪 @9 h6 H1 G" e" z
blur (src_e, blured, Size (3,3));//3*3内核降噪
/ K$ C6 _- {4 p' u! y5 c+ { imshow("腐蚀和降噪后的图片", blured); //显示图片
+ `& H* Y1 H& r4 ]( G: t; o4 C int width=blured.rows; //图像的行列
4 {( @% }1 J/ Y& V. V int height=blured.cols; //图像的列数量
3 p8 R. U, ^9 _9 z cout<<width<<endl; //显示行列的具体像素6 p# x: G* B8 U( T& t. o
cout<<height<<endl;4 c' X- ^& p. e
int a[500][1]; //定义整型数组,后面的1应该可以不要的1 \* m$ _/ G, C" N" i3 r: h5 T5 o
int b[500]; //设置一维数组,用于判断曲线的切线斜率
8 X" e! k, Q O$ ^1 X+ v G
* O2 f+ t' }( K/ l; ^# k /// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
/ A% ]7 x% t5 y; O% E4 V' L cvtColor( blured, src_gray, CV_RGB2GRAY );2 R) D, i7 Y, h; ?& ^$ b
" ^2 h8 V; S0 l) R$ c7 | /// 创建一个窗口显示图片
, `6 |0 c6 o! A( _' v# x) j namedWindow( window_name, CV_WINDOW_AUTOSIZE );
3 \, s f+ q# @- @0 b" t; i+ B
2 b. s. g+ d' R e- _ /// 创建滑动条来控制阈值& I' c3 J8 p7 U; V% ^
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);: o0 e4 L3 o5 I0 `1 f8 e
* y/ }& T- ]" U# P, {- G& H
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
3 h1 S+ L! g3 g- l' W) S! I+ ]6 W4 c; P. G. _' _! K
/// 初始化自定义的阈值函数' G$ i- T1 d$ S/ }- g2 I
Threshold_Demo( 0, 0 );1 g! u, g0 X' O6 k/ U- |7 C) W
" p8 T; _& D- [1 Y, `. Q) e0 T' Z* I // Mat img=src; //暂时无用
# {9 D& H- Q* |' Z2 {) F //imshow("转化之后图片",dst);
; ]5 X I0 U( N+ m- Z
4 V$ i& t' _. c& ^6 n2 j5 H7 ` //遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较3 ]9 C! B! v5 {. r
9 e$ O# |/ Q6 R7 ]1 `
//Mat BW = imread(imgName);
7 b4 S% r/ Q N) L; A//int value = BW.at<uchar>(191, 51);
; U9 X, K, P. { int width1=dst.rows; //处理之后图像的行列
+ ~, ^3 Y* N+ d/ b9 d int height1=dst.cols; //处理之后图像的列数量; Q3 \$ {+ E& I, j+ j
9 b! p6 {. _9 F- u+ [2 q
for (int i=0 ; i<height1; i++) //从第一行开始 应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖9 A, S( O0 n- ]' z, x5 [) Q
{
& }- Q$ B+ P% d for (int j = 0; j < width1; j++) //从第一行的第一列开始1 w9 o3 e* i# b7 m# a% p3 d
{5 r# D7 f, ~& W
//int index = i * width + j;
2 P6 Y1 I7 |3 G int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值3 D. W- n8 U2 n9 ~; _3 M4 A0 L3 r7 M
//if; //像素值# s! @, u) T: ?+ I* C
//int data = (int)dst.data[index];0 M& f: ] i$ F/ X: |- B5 K
if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃9 G+ J7 j ~1 e4 Z
{ ( d4 O$ `3 D6 H9 ~ b5 N7 \
a[i][1]=j; //数组值等于列数,便于后期对比# C. Z& s! i& c9 b4 K0 C
//cout<<i<<" --- "<<j<<endl; //i为行数
! \/ w# E8 L3 }/ M$ J% B //cout<<i<<" -坐标-- "<<a[i][1]<<endl;
' _3 f3 q* L% w* ]' X1 z( O% | if (i>1)
& }( e( y/ n5 \* t5 x( P. @4 i { //11+ q3 A& C( m, r/ R3 \4 g$ S: N8 f+ ~( l
if (a[i-1][1]<a[i][1]) //如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说8 y0 t2 b6 G2 X u8 \
//明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)
! O& e- n$ P$ ` {
3 F/ B: m. ]; h8 ^% p b[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。0 C9 E' D: h+ E0 _' R( F
}
" s |7 k- P3 @/ j% p# b$ x# l else if (a[i-1][1]>=a[i][1]) / T6 l- T6 v2 k8 V' w! j$ I4 e0 f
{
, Y2 X- L& x: b2 f* A4 I3 }2 e b[i]=1;5 z/ A4 t7 s4 c+ q5 h' t
}
2 a2 T6 l6 i) H3 y3 ^: D6 E7 C, V9 X# m8 n/ E
cout<<i<<" -标识符-- "<<b[i]<<endl;
% T: q3 `& R- u) W //cout<<j<<endl; //j为列数
o- D0 A, d$ }& k: F } //119 e/ ]! O- K: O; u' t _7 E" I; b
$ y5 |' h& u2 G+ _ [' E1 F
# E- p8 o8 Z& N" c9 i break;
" E2 |% Y4 e) z Q! d- {" d% j }, x" C9 B: p; E; c& H+ a) e8 G4 J( {
}. c. S4 \7 B/ W& w& z
}. U9 s% X% n: P" g) W2 e
//开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)$ f8 N) [5 j6 p( t0 u3 `6 ?" d
for (int i=0 ; i<height1; i++) //对数组b进行遍历,检查是否存在误判的问题
& _ K/ d( C% o$ T' t8 i" t- h //寻找拐点,找到用于判断的后段曲线的拐点- ]0 G- v2 o/ i7 \4 [- ~
//对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线/ f0 b2 |: M& _* S1 x
8 a5 R! q' E1 Y7 j- T
) L* v# R4 d- ^8 ]/ t
5 q c7 f0 x* |0 F% s
// int width=dst.rows; //图像的行列3 N2 J" E Q P% z$ i# ]
//int height=dst.cols; //图像的列数量2 {/ z' j, |" ~1 y
cout<<width<<endl; //显示行列的具体像素4 c" U6 F) O6 Q- J6 ]
cout<<height<<endl;$ \. o8 k1 H8 N- W$ E
//for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析: b- Z2 f3 P4 n& F) x
, @6 k' d7 z$ R- E3 u+ L: u
// 等待用户按键。如果是ESC健则退出等待过程。" _+ O X. ^, D
while (true). N, e, H1 T9 {5 P! j
{
+ g) n+ R( |* G int c;
7 J3 b N) m- `- U2 H c = waitKey( 20 );
7 {3 E! \$ R( ^0 h0 p) J2 z6 c, l if( (char)c == 27 )8 h! Q; D: Z3 ]: p
{ break; }
% Q" o5 K6 i& a1 S }0 J; g& F* X& |2 n# y
9 p) t6 ^, q: Q- t}! o# q4 ?& Z$ y- X+ V% z
4 M& W. z" {8 { S; ^. u
% V2 M6 e0 T% B9 ]) y: i' ?/**( @& N) x- D* U8 [
* @自定义的阈值函数( g+ y2 ^3 n: I7 m6 a4 n A) Z
*/
0 x$ \# g3 Q. K5 svoid Threshold_Demo( int, void* )
8 [ ~/ F. k3 d2 E! C{# a, Y. ~4 }+ s" @9 A
/* 0: 二进制阈值
; s3 }2 P8 ]! u3 n. E! X K; Z/ X 1: 反二进制阈值
8 H. W$ c# }' z 2: 截断阈值
s; N0 D9 a$ Z( |% R0 N3 O 3: 0阈值0 a/ Q( s/ }/ C+ a) X3 I5 A- p7 ]4 Y
4: 反0阈值
' I$ e3 h& B1 V/ c, W */
! M2 A/ m* R1 `1 j" H/ X
' f$ b6 [) W/ W9 U6 e6 [ threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );& Y% O9 h8 X+ ^" C: ]- r
$ n# }. K" i8 p
imshow( window_name, dst );& r; c7 n ~6 l4 s- m5 Z- j
}5 M; ~5 G8 @2 A8 I
5 s2 P1 f8 i j4 j1 h- H4 `% a @- a6 t0 L
* j' `! G3 x* k8 ~1 U% _
$ w( i$ P& j8 p" T3 D7 E; r8 V. w1 j1 W, e' h
/*6 b; h( z* u8 |; E4 q+ V
void main()
) K/ J X. I" O, V+ T: k4 B, i{
) C ^2 h9 r/ y2 U 7 u$ E3 R4 v- r' p- V- G4 g$ Y2 C) q
//读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图
! }7 `1 Q& S/ \. _ $ B. G2 A/ \+ e# n6 j. ~
//Mat img = imread("fruits.jpg");
: U# s; j9 g [ Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
# X3 d* e5 {+ f+ B4 n imshow("灰度图", img);- b% h3 |! W6 y0 i) [- o
//确定图像的尺寸,行列,
, S1 f9 S- }7 E; d% ~9 O* @ int width=img.rows; //图片的变量名加上行列,就是行列的数据/ N. {6 v$ H3 B4 @- l0 v
int height=img.cols;
+ [6 v+ G0 C, z1 ` cout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是358
. O/ t( Z- |5 n% J5 T+ e cout << height << endl;0 }9 V. n8 Y) y+ D
//定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
; t2 X" G3 a1 u2 c1 N9 |2 w* [& L) | int a[358][1]; //确定一个358的二维数组
4 r' H( j+ ~: h: m! a
3 \5 O2 A0 M) z2 Z9 D0 }1 t$ ^//int height = backImg.rows; //backImg是图片变量名) _ [/ z8 B+ M! `
//int width = backImg.cols;6 [( L5 ~ Y1 N" L) F! e( J4 s
for (int i = 0; i < height; i++)
4 K, y. b8 z! L9 Q {
* {1 a0 O- W( B# C* x3 j for (int j = 0; j < width; j++)6 Q7 [$ U8 M" w# k
{7 P) T% o& L) {! |
int index = i * width + j;% [$ t# `: T E5 D. M6 q$ j
//像素值
V) w" W: e. b/ E3 R! ^" U int data = (int)img.data[index];
& _- m2 [* N. {4 h8 t }
) r; a) e& J# h2 }5 { }# I) x% M/ h' I
waitKey();
4 D* b0 P' H, d& L7 Q( T}
( ?# Z6 N/ X& r# W' c' b*/ |
|