|
楼主 |
发表于 2021-1-2 09:20:48
|
显示全部楼层
#include<iostream>3 [ k" t- H& J* z
#include<opencv2/core/core.hpp>
4 {* \3 b6 l. U5 z3 p#include<opencv2/highgui/highgui.hpp>
+ d* z3 S* [/ n( K5 }5 y0 Q#include <opencv2/opencv.hpp>
& T j9 m( r* X1 |2 D% p! Q$ S#include <opencv2/imgproc/imgproc.hpp>
4 e- r) s2 U. ]* l! B9 B" j#include <opencv2/imgproc/types_c.h>, Y! l4 Y$ b3 V: c
#include <stdlib.h>1 Q% n: i2 K. O$ w
#include <stdio.h>- X4 E6 Z( l+ E! j2 c7 M
#include <opencv2/highgui/highgui_c.h>( x5 U* r- \) h- P
#include <math.h>- q) k) U0 h2 ~' H+ M& j1 g
//#include "iostream": P& K Z$ ]) g# ]& ~5 G
//#include "cv.h"' |, W0 x4 [1 @3 S; V2 n
//#include "highgui.h"$ p) G' E/ [8 ]% y5 t
//#include "math.h"8 l& D2 }; K, H; R9 S. A
using namespace cv; //命名空间CV& ~7 v, `" [' l* i8 R8 F& I
using namespace std; //命名空间 std
' H: }1 G$ X) A. U1 M+ f, w8 ^ _: J4 _9 k
int threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。) ^* ~6 m+ t4 j- d5 v8 @
int threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零$ h; C: Q H0 F3 P" Q
int const max_value = 255;
* s& H# E: A" J. H0 X+ J0 yint const max_type = 4;
" \# Y- P" v8 ^% Bint const max_BINARY_value = 255;) @6 ]% g- x7 z2 t' g& z: d$ c
% i; g+ u6 x3 F" w- G0 F3 g
CvFont font;
% K3 {, k0 V* K% z! _! [ uchar* ptr;
: `& S1 s( v- D+ C# U, p char label[20];. j( {% U% {5 y3 `% N
char label2[20];
1 q# P6 S% @- V& [) {* E! J4 l
Mat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图
+ E& R! r8 j/ v* z) |0 P! | //在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao3 D8 L/ v& `+ v' b8 i7 j3 j% C( p
//例如:char *string="I love C#!"
5 r, j) L& L8 e //定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/
* F6 ~. F# K3 x) PMat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数) t! E$ G4 `+ X, @
char* window_name = "阈值演示程序20201121";+ u) J' }: \4 b' g& Q0 w4 z' }
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
: S9 Q' o& _- e$ V+ z- ^4 Y m8 lchar* trackbar_value = "数值";4 Z! j* q/ z. X- J/ S
& F$ D. A/ j* s9 R! \# p- y# ^
/// 自定义函数声明! F1 a% }* n. R# p0 q
void Threshold_Demo( int, void* );
# d @% a. y7 e; W; p/ D& k3 m) U4 t6 e) }
/** h3 l7 ?/ D j' T
* @主函数
) ^5 C( V* ?# q" Y+ S# s */
, }$ `' }3 `9 Bint main( int argc, char** argv )6 r# r4 @9 A( E$ o u; x# N1 _
{
9 o3 F7 X5 `: ]( | /// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)
5 x4 ^' S$ w5 o src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。. U" ?6 o- e* c8 T1 @" B0 B- T
erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪
# M+ o4 V6 u9 X( o blur (src_e, blured, Size (3,3));//3*3内核降噪
( E% L* s0 c% Z- s imshow("腐蚀和降噪后的图片", blured); //显示图片
4 N0 X0 J x+ [; b3 t int width=blured.rows; //图像的行列
! U1 R, z' W' G5 o' N7 P6 v int height=blured.cols; //图像的列数量& g3 J! I: A; B, N
cout<<width<<endl; //显示行列的具体像素
% a( C2 s! Q; ?4 z cout<<height<<endl;
; u* ~: P5 M' u2 q9 a; k% ]' T2 q int a[500][1]; //定义整型数组,后面的1应该可以不要的
7 B' D( z0 B2 r8 J6 {3 @ | int b[500]; //设置一维数组,用于判断曲线的切线斜率8 d0 Z; h( L+ h
2 c+ z$ m3 J/ t7 N0 o9 L /// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
% E% T3 p) u% Z& X+ D/ |+ A cvtColor( blured, src_gray, CV_RGB2GRAY );; D' H% ]" ? }5 k
2 j4 f+ t. F$ _ /// 创建一个窗口显示图片4 O0 f( U! b0 u) n! W \
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
9 B1 T1 L4 z7 u1 C! A- W, j7 y* d: J+ k
/// 创建滑动条来控制阈值9 |7 y% o3 r, t/ A6 s; T
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
8 K% _! d0 z/ n, X k
% @" x+ s/ ]/ L/ U1 J$ N createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo);
/ {6 m* A' Y# ~
8 m0 j# Y" c1 f/ m+ z8 C /// 初始化自定义的阈值函数. H& j- e& y7 V
Threshold_Demo( 0, 0 );
* D( f' s q, B( |5 ~9 I7 c
- t! X1 i% ]2 v! ~. X' Z$ ^) D // Mat img=src; //暂时无用/ ]9 n. ?+ i, q
//imshow("转化之后图片",dst);+ O9 |. U, p% T9 O2 `
2 \$ d. x5 o7 W. W+ {1 I6 J7 ^% g //遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较1 L5 _5 G# y5 U% b8 C( ~
7 @% Y! f3 R7 L/ t5 F
//Mat BW = imread(imgName);
: X% {& K+ D6 n% M2 w//int value = BW.at<uchar>(191, 51);- A) C2 ~$ r; }2 Q( G: I' v# R8 }
int width1=dst.rows; //处理之后图像的行列
+ K0 n6 z& N' m* _ int height1=dst.cols; //处理之后图像的列数量
" X# u* f' W8 ?6 ]
. O* C! X; q5 ~; x3 ~/ ^3 b; {6 q. r for (int i=0 ; i<height1; i++) //从第一行开始 应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖4 ~. p. Z9 Z* ~5 h6 [
{
: y+ T) }2 E8 A7 v4 G2 t for (int j = 0; j < width1; j++) //从第一行的第一列开始
& V5 c: R6 @* A( @' @1 M( A {: j) U% P1 v% M+ s, S" c: ~" I+ [
//int index = i * width + j;
/ l6 b1 o2 e( ~5 @7 M1 E int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值/ k6 \2 I& Q. A5 a1 O
//if; //像素值
- b% l: M- [' s0 k //int data = (int)dst.data[index];
_. A/ r7 v. m$ w2 f if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃
/ A s, B6 m# F- L4 A7 @2 x0 g6 g {
1 L. S% `+ C# Z5 H; } a[i][1]=j; //数组值等于列数,便于后期对比( D# l0 y0 ]# Z/ o
//cout<<i<<" --- "<<j<<endl; //i为行数% ^ {& x' v- i# b
//cout<<i<<" -坐标-- "<<a[i][1]<<endl;
1 d% P8 h) c- A2 d: P. g: I if (i>1)
# i" e$ o$ J) V" B { //11# `2 D( [- }+ ?. U6 D
if (a[i-1][1]<a[i][1]) //如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说
8 E$ B1 H" s/ c5 j1 A+ t) q( I //明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)
/ W: c/ X" x4 Q0 M0 K7 P {
; X2 ~2 Z5 d# z, t* o8 C3 r! X8 N( S b[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。
t' v5 V1 ^# F# l. v6 W }# P3 d+ J! m. p! s6 u' g$ o8 w
else if (a[i-1][1]>=a[i][1]) : j/ n0 }) x' p& _7 r$ m( J& G, n
{5 _6 |! e9 u2 `) C& w- o& t* u! w
b[i]=1;- A7 P6 @1 d8 q2 D& V" ]
}
3 A* X4 g: v4 q1 O. b& N0 e/ D$ g3 W# I
cout<<i<<" -标识符-- "<<b[i]<<endl; 5 u( a% `! K) Q5 ^5 r; E7 d
//cout<<j<<endl; //j为列数% E/ n9 B. M! Y: T* }/ {
} //11
; ? L# |+ n9 k( v
' O. ^; c# m* ^' g" n, G7 z9 k1 f$ A- P9 [5 X# k
break; 3 I& x7 `9 E7 x. \: ?
}" L# N7 T2 H3 P0 `7 }, F% @" Y
}
O; E5 `8 g7 K }! D* E, q, x, B+ w
//开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)
3 V8 g7 F9 W- a for (int i=0 ; i<height1; i++) //对数组b进行遍历,检查是否存在误判的问题
* V* H/ B- m* f/ N2 J+ [/ I1 O% I //寻找拐点,找到用于判断的后段曲线的拐点. o# T* c# J; s
//对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线. A* V2 i; `& x8 a9 ~
, |, k5 y7 Z9 W6 i
( i) {, I, A8 w* D# I* Q! C7 D+ t% S @
2 {, C0 B1 V. e) E4 i% c& O // int width=dst.rows; //图像的行列; V, O9 P+ e8 G
//int height=dst.cols; //图像的列数量
( R1 L/ u. Z3 M# p9 z cout<<width<<endl; //显示行列的具体像素% z) Z. O; l5 [8 S, X4 g: I
cout<<height<<endl;2 O- N$ Z4 M# b! ? h
//for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析
" I4 ?' T( c4 C ]$ M& G5 N: x+ Z
3 V( r1 o7 V: p. _+ X6 U // 等待用户按键。如果是ESC健则退出等待过程。
: A" o; T9 G% ?' _* c% u while (true)
$ h, ^3 N1 E4 h" D+ v0 K {
) \9 q, h9 ?& a6 i! w5 d int c;* B0 L5 U6 f$ b: r7 a
c = waitKey( 20 );
( } q: J* m+ E; q) c8 L if( (char)c == 27 )1 n: c! u( q2 |& n, b
{ break; }& [6 I" ]! t8 J9 L# L1 d, U6 I2 z
}
7 }8 m4 _) @! [, {/ X4 f/ W; c: e- O7 ]; a6 f
}
2 k2 d' R: g8 G& w I' ]4 b) w# m& a1 a, {( T& Z
3 z S7 F9 \4 z& D/**
: D3 B1 p5 d3 P* {/ Z8 v/ [; F * @自定义的阈值函数$ M$ V$ i3 u% M
*/: Z5 D, U/ H% ~! S! N8 G6 w4 N, U
void Threshold_Demo( int, void* )
6 y+ J( n0 C- N" y; w{( N6 _4 G o* l) j" y8 l# A0 W
/* 0: 二进制阈值# _! ?& W! w0 s, Q
1: 反二进制阈值
7 u; k+ r# b V1 N5 E+ N i 2: 截断阈值
3 k- i; C" m* R( E# M' ^ 3: 0阈值
3 o( L7 i- O( e' H 4: 反0阈值 M4 x7 {& e" ~5 _- g
*/! s5 y2 I0 ^9 I$ Z$ H- u
. y% u, i% n0 b9 ~ threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );/ H, S: F5 k* x- C4 U9 s
b# A6 P% d) O- C6 }! i
imshow( window_name, dst );
8 q2 |* J; _) ~, }}3 c! c; ^/ D& c1 a. V
^# ^/ w3 A; x% Z. E6 M. r9 D
, c: Q/ Y' ]% G4 E) T3 [
" L: O7 L& X X3 Z
& N9 `/ Y' F& j5 s: ]7 h" K1 y1 v* O4 i2 i' p5 ], ]2 ~
/*
: E5 ]7 a; w8 v, I: g: ?3 r! p: xvoid main()1 C3 q! S+ F; N
{
. {6 H5 L% W+ w, l7 g- t
9 q# ^+ z/ S3 o( m n //读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图' v0 M3 z* e! E- ?4 @) d" x
. Z1 t8 ] w* Z, P //Mat img = imread("fruits.jpg");
0 ~ |1 C) _. ^2 Z Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对
. `5 i$ H5 e; w8 o: ~ imshow("灰度图", img);& m5 h6 t) E: ~6 o( {& _5 c
//确定图像的尺寸,行列,
6 f, ?5 K/ a4 b# U int width=img.rows; //图片的变量名加上行列,就是行列的数据
' s$ O- `+ g# I: j int height=img.cols;6 S7 }0 ~8 c3 z# h* ^# i
cout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是358
, P: z+ D! B6 @0 d cout << height << endl;9 Z Z& p8 k: |0 e! I1 Z
//定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
4 d( r% T) F/ q. U7 T int a[358][1]; //确定一个358的二维数组
+ J* n* `& B+ \0 E! b/ s# f# T/ I3 }3 G" x
//int height = backImg.rows; //backImg是图片变量名
4 U; A. v. k# L: h3 Z E//int width = backImg.cols;
3 Z* |! {/ ?- z% S' L5 Yfor (int i = 0; i < height; i++)
7 b# x0 J/ P- g% W" y1 |. I {
8 ~) p; A: j7 I8 w( v" { for (int j = 0; j < width; j++)3 l& [ o6 _0 S# O& z
{4 l% ~: c v( ~& {+ q
int index = i * width + j;
: j7 X6 g' G c3 z //像素值7 A2 F; O9 L5 K; w6 k% h
int data = (int)img.data[index];1 D- _4 m! ~: Q7 F! K' g' M
}7 g5 d4 y, @5 a: L2 _
}& l+ M/ s) Y( P$ y6 m
waitKey();
/ N* z' N* K: O0 \}
& Y8 g. C/ b' p6 m1 a' a3 M' P; Y*/ |
|