前一篇畫出了最小外接矩形,但是有時候畫出來的矩形由於中間像素干擾或者是其他原因矩形框並不是真正想要的
如圖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; }
