Opencv 最小外接矩形合并拼接

前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的

如图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;
}

原文地址:https://www.cnblogs.com/dzzy/p/9267995.html

时间: 2024-09-29 15:41:20

Opencv 最小外接矩形合并拼接的相关文章

opencv学习之路(26)、轮廓查找与绘制(五)——最小外接矩形

一.简介 二.轮廓最小外接矩形的绘制 1 #include "opencv2/opencv.hpp" 2 using namespace cv; 3 4 void main() 5 { 6 //轮廓最小外接矩形的绘制 7 Mat srcImg = imread("E://00.png"); 8 Mat dstImg = srcImg.clone(); 9 cvtColor(srcImg, srcImg, CV_BGR2GRAY); 10 threshold(srcI

26、【opencv入门】轮廓查找与绘制(4)——正外接矩形

一.简介 1.使用特定形状的轮廓包围 在实际应用中, 经常会有将检测到的轮廓用多边形表示出来的需求, 提取包围轮廓的多边形也方便我们做进一步分析, 轮廓包围主要有一下几种: 轮廓外接矩形.轮廓最小外接矩形(旋转).轮廓最小包围圆形.轮廓拟合椭圆.轮廓逼近多边形曲线 2.轮廓外接矩形 --- boundingRect() 1 CV_EXPORTS_W Rect boundingRect(InputArray points); points: 输入的二维点集, 可以填Mat类型或std::vecto

opencv学习之路(25)、轮廓查找与绘制(四)——正外接矩形

一.简介 二.外接矩形的查找绘制 1 #include "opencv2/opencv.hpp" 2 using namespace cv; 3 void main() 4 { 5 //外接矩形的查找绘制 6 Mat srcImg =imread("E://12.jpg"); 7 imshow("src",srcImg); 8 Mat dstImg = srcImg.clone(); //原图备份 9 cvtColor(srcImg, srcIm

OpenCv 使用vector&lt;Point&gt;画出轮廓外接矩形

Hai 1 IplImage* printrect(IplImage *contourim) 2 { 3 4 IplImage *rectim=cvCreateImage(cvGetSize(contourim), IPL_DEPTH_8U, 3); 5 int flag=1; 6 vector<Point> points; 7 for(;contourSeq!=NULL;contourSeq=contourSeq->h_next) 8 { 9 10 11 for(int i=0;i&l

Opencv-python 找到图像轮廓并绘制,cv2.findContours()函数,求轮廓外接矩形,cv2.boundingrect()

一.查找图像轮廓 opencv-python中查找图像轮廓的API为:findContours函数 该函数接受二值图作为参数,根据参数,可查找物体外轮廓.内外轮廓,保存轮廓点.压缩等等... 如:contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) def findContours(image, mode, method, contours=None, hierarchy=None

对opencv MeanShift 融合矩形框的改进

OPENCV 中的代码改进,当然要根据自己的实际情况来,OPENCV 中行人检测有两种矩形框的融合算法,这里只对meanshift 方法做改进 如果有更好的方法,希望可以跟我讲下. 对于去除重合部分,我也写了改进,看懂了可以加到自己程序中. 为什么要做局部MeanShift? 图1.全局MeanShift 如图所示:两幅图像距离较近且有多个矩形框,全局MeanShift融合后可能会造成这种结果 而如果用局部融合就能避免这种情况. /*-------------------------------

2015 百度之星 1006 矩形面积 最小点覆盖矩形

矩形面积 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acdream.info/problem?pid=1754 Description 小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少. Input 第一行一个正整数 T,代表测试数据组数(1≤T≤20),接下来 T 组测试数据. 每组测试数据占若干行,第一行一个正整数 N(1≤N<≤1000),代表矩形的数量.接下来 N

matlab练习程序(最小包围矩形)

又是计算几何,我感觉最近对计算几何上瘾了. 当然,工作上也会用一些,不过工作上一般直接调用boost的geometry库. 上次写过最小包围圆,这次是最小包围矩形,要比最小包围圆复杂些. 最小包围矩形可不一定是个直立的矩形,也可能像下图一样是倾斜的. 求法如下: 1.求多边形凸包,这里凸包直接调用系统函数了,细节可以参考这里,虽然当时写的不怎么样. 2.将凸包两个相邻的点连线作为矩形一条边. 3.寻找凸包上距离已得到的边最远的点,过该点做平行线,得到矩形第二条边. 4.将凸包上点向已求得的边投影

OpenCV两张图片的合并

转载请注明出处!!!http://blog.csdn.net/zhonghuan1992 OpenCV两张图片的合并 原理: 两张图片合并,想想图片是用一个个像素点来存储,每个像素点有他的值.那么合并,无非就是像素点值得合并,使用的公式可以就是给两张图片分别一个权值,然后求和.向下面这个公式: 的值位于0至1之间 OpenCV实现: 那么我们在openCV内怎么实现呢?在openCV中,有一个addWeighted函数,函数具体调用可以看这里. 读取完两个要合并的图片后,(注意,这里合并的图片必