前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的
如图1是一个信号的雨图,被矩形框分割成了多个小框:
需要合并矩形框达到的效果:
主要思想:
扫描两次最小外接矩形,第一次扫描出的矩形是图一的小矩形,遍历vector指定一个合并最大距离(假设是80),达到指定距离使用画矩形函数将这两个矩形占据的组合区域染成实心矩形。
第二次扫描直接扫描之前画的实心矩形图确定最终边框
过程图 膨胀处理和像素翻转:
代码:
#include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" #include "iostream" #include "cmath" using namespace std; using namespace cv;int Distance(Rect rect1,Rect rect2) { // 用于判断rect1在rect2的第三象限里 用于反转X轴用 bool isInversion; // 保存两个比较的点 Point point1; Point point2; // 判断 rect1 在rect2的上面还是下面 也就是说是在第一、二象限还是在三四象限 if(rect1.y<rect2.y) { // 判断rect1 在rect2的左边还是右边 也就是说是在 一象限还是二象限 isInversion= rect1.x<rect2.x; if(isInversion ) { // 取rect1的右上点 point1 = Point(rect1.x+rect1.width,rect1.y+rect1.height); // 取rect2的左下点 point2 = Point(rect2.x,rect2.y); }else { // 取rect1的左上点 point1 = Point(rect1.x,rect1.y+rect1.height); // 取rect2的右下点 point2 = Point(rect2.x+rect2.width,rect2.y); } }else { // 判断rect1 在rect2的左边还是右边 也就是说是在 三象限还是四象限 isInversion = rect1.x>rect2.x; if(isInversion) { // 取rect2的右上点 point1 = Point(rect2.x+rect2.width,rect2.y+rect2.height); // 取rect1的左下点 point2 = Point(rect1.x,rect1.y); }else { // 取rect2的左上点 point1 = Point(rect2.x,rect2.y+rect2.height); // 取rect1的右下点 point2 = Point(rect1.x+rect1.width,rect1.y); } } // 做向量减法 Point dPoint = point2 -point1; // 如果反转x轴 dPoint.x = isInversion? dPoint.x:-dPoint.x; // 如果这个向量在第三象限里 那么这两个矩形相交 返回-1 if(dPoint.x<0&& dPoint.y<0) return -1; // 如果x<0 返回y if(dPoint.x<0) return dPoint.y; // 如果y小于0 返回x if(dPoint.y<0) return dPoint.x; // 返回这个向量的长度 return 2333; } Mat change(Mat src) { int cPointR,cPointG,cPointB,cPoint; for(int i=0; i<src.rows; i++) { for(int j=0; j<src.cols; j++) { cPointB=src.at<Vec3b>(i,j)[0]=src.at<Vec3b>(i,j)[0]; cPointG=src.at<Vec3b>(i,j)[1]=src.at<Vec3b>(i,j)[1]; cPointR=src.at<Vec3b>(i,j)[2]=src.at<Vec3b>(i,j)[2]; if(cPointR>250||cPointG>250||cPointB>250) { src.at<Vec3b>(i,j)[0]=0; src.at<Vec3b>(i,j)[1]=0; src.at<Vec3b>(i,j)[2]=0; } else { src.at<Vec3b>(i,j)[0]=255; src.at<Vec3b>(i,j)[1]=255; src.at<Vec3b>(i,j)[2]=255; } cPointB=src.at<Vec3b>(i,j)[0]=src.at<Vec3b>(i,j)[0]; cPointG=src.at<Vec3b>(i,j)[1]=src.at<Vec3b>(i,j)[1]; cPointR=src.at<Vec3b>(i,j)[2]=src.at<Vec3b>(i,j)[2]; //cout<<"("<<cPointB<<","<<cPointG<<","<<cPointR<<")"<<" "; } //cout<<endl; } return src; } //imageOut 原图 ; dilation_dst膨胀图 ;imageSource单通道灰度图 ; imageTemp白图 int main(int argc,char *argv[]) { //freopen("stdout.txt","w",stdout); ///读图 读入一个3通道彩图 Mat imageOut=imread(argv[1],1); //读入一个3通道彩图 Mat grayImage;cvtColor(imageOut,grayImage,CV_BGR2GRAY); //存一个灰度图 //imshow("3通道彩图",imageOut); Mat imageTemp=imread("C:\Users\Administrator\Desktop\Rec\temp.png",1); //读一个大小一样的白图 ///腐蚀去噪处理 Mat erosion_dst,temp; int erosion_size=20; Mat element = getStructuringElement( MORPH_RECT,Size( 2*erosion_size + 1, 2*erosion_size+1 ), Point( erosion_size, erosion_size ) ); //腐蚀去噪处理参数 erode( imageOut,erosion_dst , element );//腐蚀去噪处理 //imshow( "腐蚀去噪处理", erosion_dst ); imwrite("C:\Users\Administrator\Desktop\Rec\erosion_dst.png", erosion_dst); ///像素变换 Mat change_dst=change(erosion_dst); //imshow( "像素变换", change_dst ); imwrite("C:\Users\Administrator\Desktop\Rec\change_dst.png", change_dst); ///单通道灰度图 Mat imageSource; cvtColor(change_dst,imageSource,CV_BGR2GRAY); //转换为单通道灰度图 //imshow("单通道灰度图",imageSource); ///接下来对imageSource单通道灰度图做处理 Mat image; blur(imageSource,image,Size(3,3)); threshold(image,image,0,255,CV_THRESH_OTSU); //imshow("image",image); //imwrite("C:\Users\Administrator\Desktop\Rec\myimage.png", image); ///寻找最外层轮廓 vector<vector<Point> > contours0; vector<Vec4i> hierarchy0; findContours(image,contours0,hierarchy0,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point()); //imshow("最外层轮廓",image); ///连接矩形区域/////////////////////////////////////////////////////////////////// //Mat RECtest=imread("C:\Users\Administrator\Desktop\Rec\temp.png",0); cout<<contours0.size()<<endl; for(int i=0; i<contours0.size()-1; i++) { RotatedRect rect_i=minAreaRect(contours0[i]); Point2f P_i[4]; rect_i.points(P_i); rectangle(image,Point(P_i[2].x,P_i[2].y),Point(P_i[0].x,P_i[0].y),Scalar(255,255,255),-1,1); for(int j=i+1; j<contours0.size(); j++) { RotatedRect rect_j=minAreaRect(contours0[j]); Point2f P_j[4]; rect_j.points(P_j); double recArea_i=contourArea(contours0[i]); double recArea_j=contourArea(contours0[j]); //cout<<(P_i[3].x-P_i[2].x)*(P_i[1].y-P_i[2].y)<<" -> "<<(P_j[3].x-P_j[2].x)*(P_j[1].y-P_j[2].y)<<" "; Rect r_j = rect_j.boundingRect(); Rect r_i = rect_i.boundingRect(); //cout<<recArea_i<<" -> "<<recArea_j<<" "<<Distance(r_i,r_j)<<" "; if(Distance(r_i,r_j)<=100) { int minx=min(P_i[2].x,P_j[2].x); int maxx=max(P_i[3].x,P_j[3].x); int miny=min(P_i[2].y,P_j[2].y); int maxy=max(P_i[0].y,P_j[0].y); rectangle(image,Point(minx,miny),Point(maxx,maxy),Scalar(255,255,255),-1,1);//画实心矩形 //rectangle(RECtest,Point(minx,miny),Point(maxx,maxy),Scalar(0,0,0),-1,1); //cout<<minx<<","<<miny<<" "<<maxx<<","<<maxy<<endl; //line(image,P_i[2],P_j[0],Scalar(0,0,0),1); //画线 //line(RECtest,P_i[2],P_j[0],Scalar(0,0,0),1); //cout<<"yes"; } //cout<<endl; /*rect_i=rect_j; for(int k=0;k<=3;k++) { P_i[k].x=P_j[k].x; P_i[k].y=P_j[k].y; }*/ } //cout<<"---------------------------------------------------"<<endl; } //imwrite("C:\Users\Administrator\Desktop\Rec\RECtest.png", RECtest); /////////////////////////////////////////////////////////////////// /* */ /////////////////////////////////////////////////////////////////// //imshow("实心矩形",image); //imwrite("C:\Users\Administrator\Desktop\Rec\images.png", image); vector<vector<Point> > contours; vector<Vec4i> hierarchy; findContours(image,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point()); Mat imageContours=Mat::zeros(image.size(),CV_8UC1); //最小外接矩形画布 for(int i=0; i<contours.size(); i++) { ///绘制轮廓 drawContours(imageContours,contours,i,Scalar(0,0,0),1,8,hierarchy); ///绘制轮廓的最小外结矩形 RotatedRect rect=minAreaRect(contours[i]); Point2f P[4]; rect.points(P); int minx=min(P[1].x,P[2].x); int maxx=max(P[3].x,P[0].x); int miny=min(P[2].y,P[3].y); int maxy=max(P[1].y,P[0].y); rectangle(grayImage,Point(minx,miny),Point(maxx,maxy),Scalar(0,0,0),1,1);//二值图绘线 rectangle(imageOut,Point(minx,miny),Point(maxx,maxy),Scalar(0,0,0),1,1);//原图绘线 rectangle(imageTemp,Point(minx,miny),Point(maxx,maxy),Scalar(0,0,0),1,1);//白图 } imwrite("C:\Users\Administrator\Desktop\Rec\new1.png", grayImage); imwrite("C:\Users\Administrator\Desktop\Rec\new2.png", imageOut); imwrite("C:\Users\Administrator\Desktop\Rec\new3.png", imageTemp); waitKey(0); return 0; }