# IdentificationOfDigitalTube **Repository Path**: sandalphon/IdentificationOfDigitalTube ## Basic Information - **Project Name**: IdentificationOfDigitalTube - **Description**: 使用穿线法识别数码管 - **Primary Language**: C++ - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2020-07-31 - **Last Updated**: 2024-08-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一、感想 ## 1.图像预处理迭代 版本1:考虑获得给数字轮廓识别的图像时,是随便挑选阈值的,所以图像就很糟糕。 版本2:通过直接放大图像观察具体的RGB数值分布,就能得到一个特定的颜色通道和阈值。 ## 2.图像形态学运算迭代 版本1:随便选择一种形态学运算,得到的效果并不是很好,要么有干扰白点,要么就是数字之间粘连,要么数码管之间的缝隙还存在 版本2:先开运算去除白点,再闭运算进行消除数码管之间的缝隙(为了整体轮廓识别) ## 3.图像轮廓识别迭代 > 版本1: 利用九个数字轮廓识别是从下层一层层往上的特性,识别中间三个 ```cpp vector >::iterator lt; for(lt=g_contours.begin()+3;lt版本2: 发现如果a、f、g亮的这样的数码管之间没有连接的干扰数字会造成一个数字被认为是不同的轮廓。 从而九个数字有超过九个轮廓,g_rect就会多出3个。 同时我们的数码管板的特性是上层会出现错误的数字(即有断层的数字),中间是好的0-9(即没有断层),下层是好的数字的镜像(即没有断层) 所以轮廓的多出只会出现在上层 因而将轮廓for循环的终止条件改变一下,保证只循环3次。 ```cpp int s=0; vector >::iterator lt; for(lt=g_contours.begin()+3;s<3;lt++,s++) ``` > 版本3: 我们发现有时候识别的结果不是很好,所以就无法满足触发条件。 但我们注意到我们的小车识别时大致静止的,所以可以采用上次识别的三个数字的位置。 ## 4.图像数字排序迭代 > 版本1 因为轮廓识别时,虽然是从下层往上层,每层都识别完后才移动,但同层之间的识别没有顺序。 所以我们需要对提取的三个轮廓进行排序,排序根据左上角的坐标进行排序。 > 版本2 容器自定义排序:前期自己的排序有时会出现指针偏移现象而失败,后期采用sort()函数,自定义排序方式,效果好还简单。 ## 5.处理视频迭代 > 版本1 只是修改了g_srcImage的读取方式,从图像转变为视频。 > 版本2 出现了如果一开始没有对准图像就报错的现象。原因是因为没对准,所以轮廓识别的结果为0个,所以g_rect为空,所以需要设置触发条件```if(contours.size()>=9)``` 同理,以防万一,给排序也设置一下触发条件```if(g_rect.size()==3)``` > 版本3 数字不要太过频繁地输出,同样结果的话,那输出的数字就不变 # 二、最终版本 ## 1.滤波 ### (1)测试代码 https://blog.csdn.net/sandalphon4869/article/details/94725601 只要换一下图片就ok ### (2)结论 选择高斯滤波更好,Size值为5. 随便过滤一下,值不用太高,不要也行。 ```GaussianBlur(g_srcImage,g_srcImage,Size(5,5),0.0);``` ## 2.颜色分离和二值化 ## (1)观察颜色 一直鼠标滑轮拉的话可以看到颜色RGB的分布,可以观察要关注的物体的颜色和其余区域的颜色。这样就能通过观察得到选择特定的颜色通道和阈值。 比如:这里数码管的绿色通道就很好,阈值200就很好区分。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190707171854316.gif) ## (2)结论 我们的摄像头结果对绿色和蓝色通道的分离很好,我们选择绿色的,阈值为200. ```cpp #include #include #include using namespace std; using namespace cv; #define W_BLUR "Blur" #define W_GREEN "Green" #define W_GREENTHRESHOLD "GreenThreshold" Mat g_srcImage; Mat g_srcImageBlur; Mat g_dstImageGreen; Mat g_dstImageGreenThreshold; int g_Blur=11; int g_dstImageGreenThresholdValue=200; void mySplit() { vector channels; split(g_srcImageBlur,channels); //绿色通道 g_dstImageGreen=channels.at(1); namedWindow(W_GREEN,WINDOW_NORMAL); imshow(W_GREEN,g_dstImageGreen); } void myThreshold() { g_dstImageGreen.copyTo(g_dstImageGreenThreshold); //阈值 g_dstImageGreenThreshold=g_dstImageGreenThreshold>g_dstImageGreenThresholdValue; namedWindow(W_GREENTHRESHOLD,WINDOW_NORMAL); imshow(W_GREENTHRESHOLD,g_dstImageGreenThreshold); } int main() { g_srcImage=imread("N.jpg"); namedWindow("[src]",WINDOW_NORMAL); imshow("[src]",g_srcImage); g_srcImageBlur=g_srcImage.clone(); GaussianBlur(g_srcImage,g_srcImageBlur,Size(g_Blur,g_Blur),0.0); namedWindow(W_BLUR,WINDOW_NORMAL); imshow(W_BLUR,g_srcImageBlur); //split channels mySplit(); //threshold=200 myThreshold(); waitKey(); return 0; } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190709114615108.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) ## 3.形态学运算 开运算、闭运算的核的值Size()根据相机的分辨率来调,分辨率高的图片就大些,低的图片就小些。 ```cpp void myMorphology() { Mat midImage; //开运算:处理白点 Mat kernelOpen=getStructuringElement(MORPH_RECT,Size(g_dstImageOpenValue,g_dstImageOpenValue)); morphologyEx(g_dstImageGreenThreshold,midImage,MORPH_OPEN,kernelOpen); //处理数码管之间的缝隙 Mat kernelClose=getStructuringElement(MORPH_RECT,Size(g_dstImageCloseValue,g_dstImageCloseValue)); morphologyEx(midImage,g_dstImageMorphology,MORPH_CLOSE,kernelClose); namedWindow(W_MORPHOLOGY,WINDOW_NORMAL); imshow(W_MORPHOLOGY,g_dstImageMorphology); } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190707194813809.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) ## 4.数字轮廓识别 ### (1)初代代码 ```cpp void myContours() { vector > contours; vector t_rect; findContours(g_dstImageMorphology,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageContours=g_srcImage.clone(); vector >::iterator It; namedWindow(W_CONTOURS,WINDOW_NORMAL); for(It = contours.begin();It > contours; vector t_rect; findContours(g_dstImageMorphology,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageContours=g_srcImage.clone(); vector >::iterator It; namedWindow(W_CONTOURS,WINDOW_NORMAL); if(contours.size()>=9) { int s=0; //只能预防最上层的数字出现断层,不能预防最下层的数字出现断层 for(It = contours.begin()+3;s<3;It++,s++) { //画出可包围数字的最小矩形 Rect rect = boundingRect(*It); rectangle(dstImageContours,rect,Scalar::all(255),20); t_rect.push_back(rect); } imshow(W_CONTOURS,dstImageContours); } //如果不是三个轮廓,那么就不会清除,容器内还是上次的数据 if(t_rect.size()==3) { g_rect.assign(t_rect.begin(),t_rect.end()); } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190707195624169.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) ## 4.数字识别和截取 因为3中的轮廓识别是随机顺序,所以我们如果想过989的确定顺序,那么就得排序。 排序根据矩形的左上角横坐标来判断先后 ```cpp void myNumberSort() { sort(g_rect.begin(),g_rect.end(),comp); for(int i=0;i<3;i++) { Mat ROI=g_dstImageMorphology(Rect(g_rect.at(i))); g_dstImageNumber[i]=ROI.clone(); } namedWindow(W_NUMBER1,WINDOW_NORMAL); imshow(W_NUMBER1,g_dstImageNumber[0]); namedWindow(W_NUMBER2,WINDOW_NORMAL); imshow(W_NUMBER2,g_dstImageNumber[1]); namedWindow(W_NUMBER3,WINDOW_NORMAL); imshow(W_NUMBER3,g_dstImageNumber[2]); } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/201907072008311.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) ## 5.数字识别(穿线法) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190707214239696.png) ```cpp //识别中间行的单个数字,识别中间行只需要调用三次,传入不同的参数 void myDiscern(Mat n) { //1的图像,使用穿线会是8。应该从它的尺寸入手,高远大于宽,这里我们选取3倍比. if(3*n.cols(i); if(iy_one_third&&i(y_one_third); //f if(j(y_two_third); //e if(j #include #include using namespace std; using namespace cv; #define W_BLUR "Blur" #define W_GREEN "Green" #define W_GREENTHRESHOLD "GreenThreshold" #define W_MORPHOLOGY "Morphology" #define W_CONTOURS "Contours" #define W_NUMBER1 "Number1" #define W_NUMBER2 "Number2" #define W_NUMBER3 "Number3" Mat g_srcImage; Mat g_srcImageBlur; Mat g_dstImageGreen; Mat g_dstImageGreenThreshold; Mat g_dstImageMorphology; Mat g_dstImageNumber[3]; int g_Blur=5; int g_dstImageGreenThresholdValue=200; int g_dstImageOpenValue=7; int g_dstImageCloseValue=8; vector g_rect; void mySplit() { vector channels; split(g_srcImageBlur,channels); g_dstImageGreen=channels.at(1); namedWindow(W_GREEN,WINDOW_NORMAL); imshow(W_GREEN,g_dstImageGreen); } void myThreshold() { //deep copy g_dstImageGreen.copyTo(g_dstImageGreenThreshold); //Threshold g_dstImageGreenThreshold=g_dstImageGreenThreshold>g_dstImageGreenThresholdValue; namedWindow(W_GREENTHRESHOLD,WINDOW_NORMAL); imshow(W_GREENTHRESHOLD,g_dstImageGreenThreshold); } void myMorphology() { Mat midImage; Mat kernelOpen=getStructuringElement(MORPH_RECT,Size(g_dstImageOpenValue,g_dstImageOpenValue)); morphologyEx(g_dstImageGreenThreshold,midImage,MORPH_OPEN,kernelOpen); Mat kernelClose=getStructuringElement(MORPH_RECT,Size(g_dstImageCloseValue,g_dstImageCloseValue)); morphologyEx(midImage,g_dstImageMorphology,MORPH_CLOSE,kernelClose); namedWindow(W_MORPHOLOGY,WINDOW_NORMAL); imshow(W_MORPHOLOGY,g_dstImageMorphology); } void myContours() { vector > contours; vector t_rect; findContours(g_dstImageMorphology,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageContours=g_srcImage.clone(); vector >::iterator It; namedWindow(W_CONTOURS,WINDOW_NORMAL); if(contours.size()>=9) { int s=0; //只能预防最上层的数字出现断层,不能预防最下层的数字出现断层 for(It = contours.begin()+3;s<3;It++,s++) { //画出可包围数字的最小矩形 Rect rect = boundingRect(*It); rectangle(dstImageContours,rect,Scalar(193,0,0),10); t_rect.push_back(rect); } imshow(W_CONTOURS,dstImageContours); } if(t_rect.size()==3) { g_rect.assign(t_rect.begin(),t_rect.end()); } } bool comp(const Rect &a, const Rect &b){ return a.x< b.x; } void myNumberSort() { sort(g_rect.begin(),g_rect.end(),comp); for(int i=0;i<3;i++) { Mat ROI=g_dstImageMorphology(Rect(g_rect.at(i))); g_dstImageNumber[i]=ROI.clone(); } namedWindow(W_NUMBER1,WINDOW_NORMAL); imshow(W_NUMBER1,g_dstImageNumber[0]); namedWindow(W_NUMBER2,WINDOW_NORMAL); imshow(W_NUMBER2,g_dstImageNumber[1]); namedWindow(W_NUMBER3,WINDOW_NORMAL); imshow(W_NUMBER3,g_dstImageNumber[2]); } void myDiscern(Mat n) { if(3*n.cols(i); if(iy_one_third&&i(y_one_third); if(j(y_two_third); if(j g_rect;```需要清零,保证每次读帧都是新的中间的三个数字。 同样的话,那输出的数字就不变 代码下载:https://download.csdn.net/download/sandalphon4869/11310232 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190707212845350.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) ```cpp #include #include #include using namespace std; using namespace cv; #define W_BLUR "Blur" #define W_GREEN "Green" #define W_GREENTHRESHOLD "GreenThreshold" #define W_MORPHOLOGY "Morphology" #define W_CONTOURS "Contours" #define W_NUMBER1 "Number1" #define W_NUMBER2 "Number2" #define W_NUMBER3 "Number3" Mat g_srcImage; Mat g_srcImageBlur; Mat g_dstImageGreen; Mat g_dstImageGreenThreshold; Mat g_dstImageMorphology; Mat g_dstImageNumber[3]; int g_Blur=5; int g_dstImageGreenThresholdValue=200; int g_dstImageOpenValue=7; int g_dstImageCloseValue=8; char g_number[4]={'z','e','r'}; vector g_rect; void mySplit() { vector channels; split(g_srcImageBlur,channels); g_dstImageGreen=channels.at(1); // namedWindow(W_GREEN,WINDOW_NORMAL); // imshow(W_GREEN,g_dstImageGreen); } void myThreshold() { //deep copy g_dstImageGreen.copyTo(g_dstImageGreenThreshold); //Threshold g_dstImageGreenThreshold=g_dstImageGreenThreshold>g_dstImageGreenThresholdValue; // namedWindow(W_GREENTHRESHOLD,WINDOW_NORMAL); // imshow(W_GREENTHRESHOLD,g_dstImageGreenThreshold); } void myMorphology() { Mat midImage; Mat kernelOpen=getStructuringElement(MORPH_RECT,Size(g_dstImageOpenValue,g_dstImageOpenValue)); morphologyEx(g_dstImageGreenThreshold,midImage,MORPH_OPEN,kernelOpen); Mat kernelClose=getStructuringElement(MORPH_RECT,Size(g_dstImageCloseValue,g_dstImageCloseValue)); morphologyEx(midImage,g_dstImageMorphology,MORPH_CLOSE,kernelClose); namedWindow(W_MORPHOLOGY,WINDOW_NORMAL); imshow(W_MORPHOLOGY,g_dstImageMorphology); } void myContours() { vector > contours; vector t_rect; findContours(g_dstImageMorphology,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageContours=g_srcImage.clone(); vector >::iterator It; namedWindow(W_CONTOURS,WINDOW_NORMAL); if(contours.size()>=9) { int s=0; //只能预防最上层的数字出现断层,不能预防最下层的数字出现断层 for(It = contours.begin()+3;s<3;It++,s++) { //画出可包围数字的最小矩形 Rect rect = boundingRect(*It); rectangle(dstImageContours,rect,Scalar(193,0,0),10); t_rect.push_back(rect); } imshow(W_CONTOURS,dstImageContours); } if(t_rect.size()==3) { g_rect.assign(t_rect.begin(),t_rect.end()); } } bool comp(const Rect &a, const Rect &b){ return a.x< b.x; } void myNumberSort() { sort(g_rect.begin(),g_rect.end(),comp); for(int i=0;i<3;i++) { Mat ROI=g_dstImageMorphology(Rect(g_rect.at(i))); g_dstImageNumber[i]=ROI.clone(); } namedWindow(W_NUMBER1,WINDOW_NORMAL); imshow(W_NUMBER1,g_dstImageNumber[0]); namedWindow(W_NUMBER2,WINDOW_NORMAL); imshow(W_NUMBER2,g_dstImageNumber[1]); namedWindow(W_NUMBER3,WINDOW_NORMAL); imshow(W_NUMBER3,g_dstImageNumber[2]); } char myDiscern(Mat n) { if(3*n.cols(i); if(iy_one_third&&i(y_one_third); if(j(y_two_third); if(j>g_srcImage; namedWindow("[Video]",WINDOW_NORMAL); imshow("[Video]",g_srcImage); g_srcImageBlur=g_srcImage.clone(); GaussianBlur(g_srcImage,g_srcImageBlur,Size(g_Blur,g_Blur),0.0); // namedWindow(W_BLUR,WINDOW_NORMAL); // imshow(W_BLUR,g_srcImageBlur); //split channels mySplit(); //threshold=160 myThreshold(); //clear small white and connection breakpoint myMorphology(); //draw contours myContours(); if(g_rect.size()==3) { //sort numbers myNumberSort(); //discern number char t_number[3]; for(int i=0;i<3;i++) { t_number[i]=myDiscern(g_dstImageNumber[i]); if(t_number[i]=='e') { t_number[0]='e'; break; } } //第一次的时候,将识别出的t_number赋给g_number if(g_number[0]=='z' && t_number[0]!='e') { for(int i=0;i<3;i++) { g_number[i]=t_number[i]; cout< using namespace cv; using namespace std; int main() { Mat srcImage=imread("S1.jpg"); //dstImage必须创建,要不然无法访问。 //这里的CV_8UC1表示单通道图 Mat dstImage=Mat::zeros(srcImage.size(),CV_8UC1); //遍历方式是从上往下遍历每一行 for(int i=0;i200,G<150,B<150 if(srcImage.at(i,j)[0]<150 && srcImage.at(i,j)[1]<150 && srcImage.at(i,j)[2]>200) { //dstImage是单通道图,所以用uchar dstImage.at(i,j)=255; } } } namedWindow("BGR",WINDOW_NORMAL); imshow("BGR",dstImage); waitKey(); return 0; } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190709230630386.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190709230153320.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NhbmRhbHBob240ODY5,size_16,color_FFFFFF,t_70) 颜色分离与访问像素:https://blog.csdn.net/sandalphon4869/article/details/94713547 ## 2.外轮廓识别圈出ROI ```if(contours.size()>=1)```是为了鲁棒性,在没有摄像头还没有对准数码管的时候。 ```cpp void myROI() { Mat dstImageROI=Mat::zeros(g_srcImageBlur.size(),CV_8UC1); for(int i=0;i(i,j)[0]<100 && g_srcImageBlur.at(i,j)[1]<100 && g_srcImageBlur.at(i,j)[2]>150) { dstImageROI.at(i,j)=255; } } } Mat kernel=getStructuringElement(MORPH_RECT,Size(g_ROIOpen,g_ROIOpen)); morphologyEx(dstImageROI,dstImageROI,MORPH_OPEN,kernel); namedWindow(W_BGR,WINDOW_NORMAL); imshow(W_BGR,dstImageROI); vector > contours; vector rect; findContours(dstImageROI,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageROIContours=g_srcImage.clone(); namedWindow(W_ROI,WINDOW_NORMAL); if(contours.size()>=1) { //画出可包围数字的最小矩形 Rect t_rect = boundingRect(dstImageROI); rect.push_back(t_rect); g_ROITest=true; } //开始没有对准数码管自然没有轮廓 else { g_ROITest=false; return; } rectangle(dstImageROIContours,rect[0],Scalar(193,0,0),10); imshow(W_ROI,dstImageROIContours); g_srcImageROI=g_srcImageBlur(Rect(rect[0])); // cout<<"MyROI:OK"< result; //让等于0次的数输入到result中,让等于1次...直到result中统计到三个数 for(int i=0;result.size()<3;i++) { for(int j=0;j<10;j++) { if(numbertimes[j]==i) { result.push_back(j); } if(result.size()==3) break; } } cout<<"[result]="< #include #include using namespace std; using namespace cv; #define W_BLUR "Blur" #define W_BGR "BGR" #define W_ROI "ROI" #define W_GREEN "Green" #define W_GREENTHRESHOLD "GreenThreshold" #define W_MORPHOLOGY "Morphology" #define W_CONTOURS "Contours" #define W_NUMBER1 "Number1" #define W_NUMBER2 "Number2" #define W_NUMBER3 "Number3" Mat g_srcImage; Mat g_srcImageBlur; Mat g_srcImageROI; Mat g_dstImageGreen; Mat g_dstImageGreenThreshold; Mat g_dstImageMorphology; Mat g_dstImageNumber[3]; int g_Blur=5; int g_ROIOpen=5; int g_dstImageGreenThresholdValue=200; int g_dstImageOpenValue=1; int g_dstImageCloseValue=5; int g_timeInterval=10; char g_number[4]={'z','e','r'}; bool g_ROITest=false; vector g_rect; void myROI() { Mat dstImageROI=Mat::zeros(g_srcImageBlur.size(),CV_8UC1); for(int i=0;i(i,j)[0]<100 && g_srcImageBlur.at(i,j)[1]<100 && g_srcImageBlur.at(i,j)[2]>150) { dstImageROI.at(i,j)=255; } } } Mat kernel=getStructuringElement(MORPH_RECT,Size(g_ROIOpen,g_ROIOpen)); morphologyEx(dstImageROI,dstImageROI,MORPH_OPEN,kernel); namedWindow(W_BGR,WINDOW_NORMAL); imshow(W_BGR,dstImageROI); vector > contours; vector rect; findContours(dstImageROI,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageROIContours=g_srcImage.clone(); namedWindow(W_ROI,WINDOW_NORMAL); if(contours.size()>=1) { //画出可包围数字的最小矩形 Rect t_rect = boundingRect(dstImageROI); rect.push_back(t_rect); g_ROITest=true; } //开始没有对准数码管自然没有轮廓 else { g_ROITest=false; return; } rectangle(dstImageROIContours,rect[0],Scalar(193,0,0),10); imshow(W_ROI,dstImageROIContours); g_srcImageROI=g_srcImageBlur(Rect(rect[0])); // cout<<"MyROI:OK"< channels; split(g_srcImageROI,channels); g_dstImageGreen=channels.at(1); // namedWindow(W_GREEN,WINDOW_NORMAL); // imshow(W_GREEN,g_dstImageGreen); // cout<<"MySplit:OK"<g_dstImageGreenThresholdValue; // namedWindow(W_GREENTHRESHOLD,WINDOW_NORMAL); // imshow(W_GREENTHRESHOLD,g_dstImageGreenThreshold); // cout<<"MyThreshold:OK"< > contours; vector t_rect; findContours(g_dstImageMorphology,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE); Mat dstImageContours=g_srcImageROI.clone(); vector >::iterator It; namedWindow(W_CONTOURS,WINDOW_NORMAL); if(contours.size()>=9) { int s=0; //只能预防最上层的数字出现断层,不能预防最下层的数字出现断层 for(It = contours.begin()+3;s<3;It++,s++) { //画出可包围数字的最小矩形 Rect rect = boundingRect(*It); rectangle(dstImageContours,rect,Scalar(193,0,0),10); t_rect.push_back(rect); } imshow(W_CONTOURS,dstImageContours); } if(t_rect.size()==3) { g_rect.assign(t_rect.begin(),t_rect.end()); } // cout<<"MyContours:OK"<(i); if(iy_one_third&&i(y_one_third); if(j(y_two_third); if(j(getTickCount()); bool timeTrigger=false; int numbertimes[10]={0,0,0,0,0,0,0,0,0,0}; while(1) { capture>>g_srcImage; namedWindow("[Video]",WINDOW_NORMAL); imshow("[Video]",g_srcImage); g_srcImageBlur=g_srcImage.clone(); GaussianBlur(g_srcImage,g_srcImageBlur,Size(g_Blur,g_Blur),0.0); // namedWindow(W_BLUR,WINDOW_NORMAL); // imshow(W_BLUR,g_srcImageBlur); //ROI myROI(); if(g_ROITest==false) { //视频循环不能没有间隔,必须有waitKey waitKey(1); continue; } //split channels mySplit(); //threshold=160 myThreshold(); //clear small white and connection breakpoint myMorphology(); //draw contours myContours(); int time=int((getTickCount()-time0)/getTickFrequency()); //如果轮廓识别到三个数字 if(g_rect.size()==3) { bool contoursTest=true; //如果ROI的数字超过了g_dstImageMorphology的范围 for(int i=0;i<3;i++) { if((g_rect[i].x+g_rect[i].width)>g_dstImageMorphology.cols||(g_rect[i].y+g_rect[i].height)>g_dstImageMorphology.rows) { contoursTest=false; } } if(!contoursTest) continue; //sort numbers myNumberSort(); //discern number char t_number[3]; //如果有一个数字识别不出来,那么就t_number[0]标记为'e' for(int i=0;i<3;i++) { t_number[i]=myDiscern(g_dstImageNumber[i]); if(t_number[i]=='e') { t_number[0]='e'; break; } } //第一次的时候,将识别出的t_number赋给g_number if(g_number[0]=='z' && t_number[0]!='e') { for(int i=0;i<3;i++) { g_number[i]=t_number[i]; cout< result; //让等于0次的数输入到result中,让等于1次...直到result中统计到三个数 for(int i=0;result.size()<3;i++) { for(int j=0;j<10;j++) { if(numbertimes[j]==i) { result.push_back(j); } if(result.size()==3) break; } } cout<<"[result]="<