|
楼主 |
发表于 2021-1-2 09:20:48
|
显示全部楼层
#include<iostream>/ f5 @, o0 v" r" ~$ x; \
#include<opencv2/core/core.hpp>4 @, V) O5 C% P. R$ e( G$ G; A
#include<opencv2/highgui/highgui.hpp>
- j3 t7 b5 Q& Y) M* _8 i" P' p#include <opencv2/opencv.hpp>( h8 A4 Y' J- j( ]7 |- [% B% t# V
#include <opencv2/imgproc/imgproc.hpp>8 l G2 t' t+ |/ z9 `
#include <opencv2/imgproc/types_c.h>( I" f! M' K3 h
#include <stdlib.h>
/ a2 l! P a4 j9 }#include <stdio.h>% G5 N$ t! ^5 b# i* N t
#include <opencv2/highgui/highgui_c.h>
. U- \) x- t, [0 [, E0 o- ^#include <math.h>2 |; _7 L9 B( A3 B# g
//#include "iostream"
# Z9 t6 r, Z! }: P9 H//#include "cv.h"
' {9 K0 X( g, a7 ?- T9 I# E# D! |1 ]//#include "highgui.h"4 w, X0 T5 s) i8 V+ R
//#include "math.h"
4 |5 y1 u `, \% w, n) Fusing namespace cv; //命名空间CV9 e8 s7 j" a9 n8 O( T
using namespace std; //命名空间 std9 R: H0 U. `5 X' |# j
2 U/ }3 V, ^! f" F) U, b# Z
int threshold_value = 225; //启动程序时的阈值初始值,因为227能够完全提取轮廓,所以设置为225,实际上227也可以。* M0 l' p0 D6 `
int threshold_type = 3; //启动程序的时候阈值类型,默认的为不足部分取零
8 ]# g8 T1 T4 mint const max_value = 255;
( e, R1 o: t/ R4 L6 Yint const max_type = 4;
9 @4 X1 _- F# \int const max_BINARY_value = 255;
6 U# m( n* Y& Q) L
; T/ S0 M$ g, I CvFont font;8 q1 Z9 j d# K
uchar* ptr;
3 S% ]$ z) ^0 p0 F0 g char label[20];
2 ]2 J. `: \' n e0 E' k* r0 V char label2[20];
- S. {2 @: F3 h1 V0 M2 c1 J/ c& L, h) ^+ s0 ]
Mat src, blured, src_e, src_gray, dst; //类定义几个图片变量,dst是最后转化阈值之后的图片,src.gray是灰度图
8 q/ o4 l! r2 A //在C语言中“char*”是声明一个字符类型du的指针,定义数据类型,char可以定义字符zhi有变量、数组、指针。dao
5 z3 b4 H. X1 O( X" d5 O+ K( ~ //例如:char *string="I love C#!"
' v& D1 f" Q3 o8 f- U- O; q8 j //定义了一个字符指针变量string,用字符串常量"I love C#!",对它进行初始化。对字符指针变量初始化,实际上就是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。*/8 ^- b/ M" d* D, L
Mat element = getStructuringElement(MORPH_RECT, Size(5,5)); //用于腐蚀的参数
: M' z. P2 X% p2 P8 Rchar* window_name = "阈值演示程序20201121";! n; Q' }3 \- V* U* a3 V! h
char* trackbar_type = "类型: \n 0: 二值化 \n 1: 反二值化 \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; //
& F2 i0 ~: @2 N" w) I4 Y3 a: Qchar* trackbar_value = "数值";* g1 @# b+ y! G$ V
5 P m6 S6 D- y( K/// 自定义函数声明
9 D/ ?( v" |9 avoid Threshold_Demo( int, void* );
' L+ _9 |/ n" V" f; B1 P! C
! |3 Q0 u- v$ v+ w, N, [. `4 N/**2 v/ R* H/ J; B, z5 m
* @主函数$ |- J1 z( a, G V3 @ A3 m
*/. q0 A- D) }6 i' z
int main( int argc, char** argv )
g1 }8 z& u" K" w{
/ ]# K3 B- ?, \4 W2 m! x9 U6 Y /// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)! n) X n+ Y5 H9 p1 \2 ]7 t, l8 J$ g
src = imread("121.JPG", 1); //目前还未使用摄像头拍摄照片,暂时以直接读取文件的方式来测试。
3 O( Z0 m! C" }& J erode (src, src_e, element); //对图片进行腐蚀,参数可调,正常为9或者10,过大则造成轮廓过小,应该再进行降噪 G3 }' R3 s" {. h9 q2 A$ T
blur (src_e, blured, Size (3,3));//3*3内核降噪& B U8 V% E6 D0 Q
imshow("腐蚀和降噪后的图片", blured); //显示图片
4 p- e1 x5 ^: w7 y int width=blured.rows; //图像的行列
+ d; Q+ j( \2 M5 A& d' T4 k int height=blured.cols; //图像的列数量% r1 }( ?* l( j* x0 o- \
cout<<width<<endl; //显示行列的具体像素
4 E/ }1 X+ }/ `1 G0 A. i8 N) u cout<<height<<endl;
6 q& _3 ~0 z* R9 A int a[500][1]; //定义整型数组,后面的1应该可以不要的* J6 F: m6 J9 Z# W
int b[500]; //设置一维数组,用于判断曲线的切线斜率( ~6 j c! G. s+ X
+ n) _/ E1 A4 u, ~- x4 X, @# s
/// 将图片转换成灰度图片 Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对% Q6 Z( m/ @0 E! {; Q# S8 R0 G
cvtColor( blured, src_gray, CV_RGB2GRAY );
7 W/ W9 ]: l) r! w0 O8 }( J; u ]# J3 q8 y
/// 创建一个窗口显示图片
8 \; w2 t# f$ z& ` namedWindow( window_name, CV_WINDOW_AUTOSIZE );
% L5 G* }4 l- N8 u& `- y
) v: c0 D) w# f% K& t4 f5 F! W) G$ C /// 创建滑动条来控制阈值( ?) t; ]( W) j8 J, g
createTrackbar( trackbar_type, window_name, &threshold_type, max_type, Threshold_Demo);
( ?8 J" l+ Z' Q6 c% U+ m" q: C. L( _1 J2 ?
createTrackbar( trackbar_value, window_name, &threshold_value, max_value, Threshold_Demo); A- u, F& x+ w3 ?
- ]: x8 \( m. e /// 初始化自定义的阈值函数" Y9 S- B5 N, z7 u2 K
Threshold_Demo( 0, 0 );
' x& { P# }, w# {( Z v
D; y7 s% s4 s! `) P$ ] // Mat img=src; //暂时无用
. W3 k; u6 G1 i& W7 X1 [+ v //imshow("转化之后图片",dst);
: M$ C1 n0 x* y
$ l0 u! d: ~+ E( k; H S' g //遍历图片的每个像素点,当像素点的阈值大于227时,将最左侧的该像素地址保存在二维数组中,在该行之后的像素点抛弃,如果阈值低于227,则向下遍历至该行末,然后从下一行开始对像素进行比较
7 {. e1 ]! W, {4 [, T; i: \, l
: ?/ ^5 {2 J& R3 `//Mat BW = imread(imgName);# T8 l, `3 w+ j0 R: e( ~6 ^
//int value = BW.at<uchar>(191, 51);/ F, V8 V4 [ E1 I# g
int width1=dst.rows; //处理之后图像的行列
5 N0 `; j* e9 S% [ int height1=dst.cols; //处理之后图像的列数量
" l; X$ U& X7 s9 P* ]. o* Y k/ x' I2 V/ |2 f( x! X- s+ n
for (int i=0 ; i<height1; i++) //从第一行开始 应该从最后一行开始向上检索,这样可以减少计算量,一旦出现与之前曲线K值相反的方向,则确定是拐点,不用再考虑,但是要考虑出现切线斜率始终是减少的趋势,这种情况下往往是蒜尖* H7 l1 J9 a) p8 o) V* I5 E+ e
{- F; M C _' w2 n# [
for (int j = 0; j < width1; j++) //从第一行的第一列开始
" J3 L6 j- m1 s' ]/ Y9 q( _/ F8 b# ^ {1 q: ^: E4 s6 X" V/ L6 x
//int index = i * width + j;
0 e% b6 }) L0 ]+ N; w- o int value = dst.at<uchar>(i,j); //读取给定坐标处的像素值% E0 p0 o7 X$ J/ N3 ^) `1 ]
//if; //像素值& `! T/ O5 ]3 R" _. v5 k1 C
//int data = (int)dst.data[index];
& r8 \9 J4 `: u% U3 i3 t/ L" { if ( value >200) //如果像素值大于某个数值,则将其地址记录在数组内,且仅记录首像素,后面的舍弃# P$ m$ W' i6 B- w
{
X( F! d7 k( H& Y5 p a[i][1]=j; //数组值等于列数,便于后期对比
: Z/ m( d$ Y9 {9 k8 h6 E //cout<<i<<" --- "<<j<<endl; //i为行数# x4 j4 H9 P2 L& m* u, F2 K
//cout<<i<<" -坐标-- "<<a[i][1]<<endl;1 D' \! U& K( G! m" }% x
if (i>1) A' ]8 Z4 ~4 f; |' D7 s' F, U
{ //111 n& [2 {$ y( h |
if (a[i-1][1]<a[i][1]) //如果第一行中大于某个阈值的像素地址与下一行相比靠右,也就是列数比上一行要大,则说明该曲线向左侧倾斜,说* m5 c5 a4 s) M
//明是底部,如果曲线向右侧弯曲,则是蒜尖 (之所以用i-1,是因为总不能和没有像素的地址对比,所以必须向后取值)% {/ q' V. A& H6 _' u: S( e/ M
{
3 V# i$ o& D4 Y, l b[i]=0; //因此,当下一行的地址比上一行的地址小,则用1表示,如果下一行地址比上一行大,用0表示,1是蒜尾,0是蒜尖。% [! w7 W0 |2 _$ m
}
" d4 b1 X8 b5 M' S: p- U else if (a[i-1][1]>=a[i][1]) " H0 b5 W9 F4 `. k2 ` I G m
{0 J: B# D4 j" r4 ?
b[i]=1;. ]; O m5 ]7 B0 @4 G
}
4 u# v! H$ @$ R" i- `5 q: j x3 r) |7 U0 P
cout<<i<<" -标识符-- "<<b[i]<<endl; 6 Y) v" W5 _6 R- o' W+ J6 z9 V1 L, Q2 n' m
//cout<<j<<endl; //j为列数
4 T/ p, _4 ~7 |# V9 i4 j# `$ ]; o } //11
: j- L# v% c9 t; {" F, y f/ f ' `/ |: i0 e. M# M& L& h
* Z" w- {3 e; U1 S, h7 k% ?% c
break;
0 s$ {& c: ^: W }, }0 z3 } }/ { U, L3 A7 ~4 H2 F, u: X! K; B
}! c& c; f5 M! r- k
}
T3 U2 E5 F' G6 E/ [/ n- x //开始对b数组进行分析,确定是否为头尾(但是需要对曲线进行圆滑处理)" q9 ~! q, G0 l* u% \1 g$ m
for (int i=0 ; i<height1; i++) //对数组b进行遍历,检查是否存在误判的问题
w# p0 L$ W+ d( B- i //寻找拐点,找到用于判断的后段曲线的拐点
6 V) C* ^7 S7 X. ]5 | //对图形进行圆滑处理,除了最大的拐点之外,尽量不要出现折线# v4 S) n5 X3 d% Q
7 z9 B& _0 v# |- [
9 X( @+ c: v- O' }2 z4 }' g6 i8 O
/ k/ ^- L& o& r" N // int width=dst.rows; //图像的行列
2 l- V# o" Y2 T& e. c0 x //int height=dst.cols; //图像的列数量
; {" `" J! o8 F) O' C5 ]0 _ cout<<width<<endl; //显示行列的具体像素
9 x" H ^0 o, [ cout<<height<<endl;
5 M1 R( f, t1 u3 `" C //for (int i =height1-5 ; i>20; i--) //对收集的坐标数据进行分析* d. F4 K/ e: Q X" n: _! J0 t. [
9 h8 C9 ^ c4 ?2 D // 等待用户按键。如果是ESC健则退出等待过程。
+ B9 k6 P" _3 Q+ e while (true)
- g, E/ S- z- W3 K1 \' z {# T4 u3 m: O2 A& O+ @
int c;
# v5 y, \% ~* c# I* t6 Q. R+ N c = waitKey( 20 );8 p8 T& M& Y& d5 P% Z$ S
if( (char)c == 27 ). ~" L: P4 \7 ] x
{ break; }" v" S. ]2 X0 ~ P# _: w$ S
}
/ d; l/ ~& X; f3 P0 Q2 N9 _4 P) M6 U/ G1 X
}
- n1 T' Q* q7 [! x) N# J" w4 m4 g4 V+ x* g2 o
7 Z$ U2 z! F. i) B. _( V
/**
7 O" k6 }2 C, v6 h( [! t. t * @自定义的阈值函数0 |) t0 O6 w& A* } {. R+ v
*/) _8 F- i0 D. g/ h
void Threshold_Demo( int, void* )7 H |9 } V0 d1 ^% O; Y
{
: O, n4 ^* X. r8 D /* 0: 二进制阈值! b0 f, C$ O v; ?9 U& T5 j E
1: 反二进制阈值9 v) l2 h+ ^0 W$ V% u8 u1 H8 M
2: 截断阈值
( j" } x# B( k5 G- ] 3: 0阈值; ]6 u$ r$ j# k8 M# v
4: 反0阈值
# X" |" ?( Q6 X6 | */
; M: D& q9 M( B1 T" h, P7 E4 _. x$ `* g# W* R1 V- c2 j. M4 N7 W
threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );
$ R/ e$ D5 {" b; W6 t- |3 F$ x( B8 M3 L5 ~+ h+ O" k$ C9 N. v
imshow( window_name, dst );
+ _) m% \) W3 |3 x! ~5 q! N}
( f4 ?" Z/ C/ H) E* N8 X! L2 g; Z% i- R& y$ H9 ?
2 s# ^% \7 v/ z+ U3 D; T2 H- D* U5 N8 C' {
3 D2 {& x$ D0 B7 {5 F) M9 G8 x" T" Y; d& V
/*8 K8 {- d1 s. w' h/ R0 O
void main()6 e* a( }5 h( D" u1 r' e* }
{
" h: a* h7 Q; U% F% k. J# {
( A$ H$ \/ M1 b //读入彩色图像 单通道图像(CV_8UC1);CV 8位未指定的1通道的图像,backImg是单通道灰色图" m' j1 V* e: S3 ^: F
" j& A& ^/ H7 U0 { //Mat img = imread("fruits.jpg");: b1 n! Z9 @6 n9 b5 b
Mat img = imread("11.jpg", IMREAD_GRAYSCALE); //在读取图片的同时直接转化成灰度图, 下一步是要将像素亮度超过一定阈值的点提取出来,并找到该点的坐标,然后记录该点坐标,用于后期的比对4 C: l+ ~4 _. D9 t" A& ^' m
imshow("灰度图", img);
. j, n8 {$ ]) R5 M% E //确定图像的尺寸,行列,
2 N7 d# B$ N$ ^+ D int width=img.rows; //图片的变量名加上行列,就是行列的数据
[; v+ E& h1 N+ B" r t- A5 O int height=img.cols;- t) j& b o: F% x
cout << width << endl; //显示行列的数据 本图片已经用358的像素值裁剪了,所以形成的就是高宽都是358
6 K/ \$ ~ ^0 f% \ cout << height << endl;$ L. t( s1 \" F/ x
//定义一个二维数组,a[i][1],其行数等于图像行数,列数就一列,用于记录图片上像素的亮度超过某个阈值的像素所在的列数,用于下一步的对比。
% [. n) U& a* K: ?& G$ T6 D. n int a[358][1]; //确定一个358的二维数组2 z2 I7 Y. B+ x
$ J- m0 K8 ?: l R//int height = backImg.rows; //backImg是图片变量名
) U* Q% n' {5 W# y7 l: j5 A# z8 T7 R//int width = backImg.cols;
; X. k% |+ f* Y9 z) Afor (int i = 0; i < height; i++): _. U' T1 b* y. Q' P6 ~
{9 w: |4 o' ~ @9 Q# r& d; f
for (int j = 0; j < width; j++)
7 Z" S: C6 k E {4 F' v* x$ h' }+ e) |6 e1 w$ k
int index = i * width + j;1 c9 J! l- W [1 Z+ B7 h
//像素值/ Y& n4 J9 ]- s8 k7 n; p0 V- h
int data = (int)img.data[index];) n0 Q5 F" X6 _
}8 ~- s$ t6 f1 Z |* E
}
0 F- d' k# t+ k% ~) W" P waitKey();
8 Z% t- ~& `/ z5 d0 S}3 J3 _5 _- ]( s9 o5 k) q" m$ V
*/ |
|