zoukankan      html  css  js  c++  java
  • Opencv 改进的外接矩形合并拼接方法

    上一篇中的方法存在的问题是矩形框不够精确,而且效果不能达到要求

    这里使用凸包检测的方法,并将原来膨胀系数由20缩小到5,达到了更好的效果

    效果图:

    效果图:

    代码:

    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    using namespace cv;
    using namespace std;
    //设置全局参数
    Mat srcImage, srcGray;
    int thresh = 100;
    int max_thresh = 255;
    RNG rng(12345);
    Mat thresh_callback(int, void*)
    {
        Mat srcTemp = srcImage.clone();
        Mat threMat;
        //轮廓检测参数
        vector<vector<Point> > contours;
        vector<Vec4i> hierarchy;
        //阈值化操作
        threshold(srcGray, threMat, thresh, 255, THRESH_BINARY);
        //轮廓检测
        findContours(threMat, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
        //凸包及缺陷检测参数
        vector<vector<Point> > pointHull(contours.size());
        vector<vector<int> > intHull(contours.size());
        vector<vector<Vec4i> > hullDefect(contours.size());
        for (size_t i = 0; i < contours.size(); i++)
        {
            //Point类型凸包检测
            convexHull(Mat(contours[i]), pointHull[i], false);
            //int 类型凸包检测
            convexHull(Mat(contours[i]), intHull[i], false);
            //凸包缺陷检测
            convexityDefects(Mat(contours[i]), intHull[i], hullDefect[i]);
        }
        //绘制凸包及缺陷检测
        Mat drawing = Mat::zeros(threMat.size(), CV_8UC3);
        for (size_t i = 0; i < contours.size(); i++)
        {
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            drawContours(drawing, contours, i, Scalar(255,255,255), -1, 8, vector<Vec4i>(), 0, Point());
            drawContours(drawing, pointHull, i, Scalar(255,255,255), -1, 8, vector<Vec4i>(), 0, Point());
            //绘制缺陷
            size_t count = contours[i].size();
            if (count < 300)
                continue;
            //设置凸包缺陷迭代器
            vector<Vec4i>::iterator iterDefects = hullDefect[i].begin();
            //遍历得到4个特征量
            while (iterDefects != hullDefect[i].end())
            {
                Vec4i& v = (*iterDefects);
                //起始位置
                int startidx = v[0];
                Point ptStart(contours[i][startidx]);
                //终止位置
                int endidx = v[1];
                Point ptEnd(contours[i][endidx]);
                //内凸壳最远的点缺陷
                int faridx = v[2];
                Point ptFar(contours[i][faridx]);
                //凸点之间的最远点
                int depth = v[3] / 256;
                //绘制相应的线与圆检测结果
                if (depth > 20 && depth < 80)
                {
                    line(drawing, ptStart, ptFar, CV_RGB(255,255,255), 2);
                    line(drawing, ptEnd, ptFar, CV_RGB(255,255,255), 2);
                }
                iterDefects++;
            }
        }
        return drawing;
    }
    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];
            }
        }
        return src;
    }
    ///矩形测距
    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 abs(sqrt((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y)));
    }
    int main()
    {
        //freopen("stdout.txt","w",stdout);
        ///读图
        //srcImage = imread("C:\Users\Administrator\Desktop\1-gl300c.png",1);
        //srcImage = imread("C:\Users\Administrator\Desktop\2-P330D.png",1);
        srcImage = imread("C:\Users\Administrator\Desktop\3-spark.png",1);
        Mat outImage=srcImage;
        if (!srcImage.data)
            return -1;
    
        ///腐蚀去噪处理
        Mat erosion_dst,temp;
        int erosion_size=5;
        Mat element = getStructuringElement( MORPH_RECT,Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                                             Point( erosion_size, erosion_size ) ); //腐蚀去噪处理参数
        erode( srcImage,erosion_dst, element ); //腐蚀去噪处理
        //imshow( "腐蚀去噪处理", erosion_dst );
    
        ///像素变换
        Mat change_dst=change(erosion_dst);
        srcImage=erosion_dst;
    
        ///转灰度图
        cvtColor(srcImage, srcGray, CV_BGR2GRAY);
        blur(srcGray, srcGray, Size(3, 3));
    
        ///凸包检测
        Mat image=thresh_callback(0, 0);
        //imwrite("C:\Users\Administrator\Desktop\image.png", image);
    
        ///转单通道灰度图
        Mat imageSource;
        cvtColor(image,imageSource,CV_BGR2GRAY);
        blur(imageSource,image,Size(3,3));
        threshold(image,image,0,255,CV_THRESH_OTSU);
    
        ///寻找最外层轮廓
        vector<vector<Point> > contours0;
        vector<Vec4i> hierarchy0;
        findContours(image,contours0,hierarchy0,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());
        cout<<contours0.size()<<endl;
    
        ///连接矩形区域
        for(int i=0; i<contours0.size(); i++)
        {
            RotatedRect rect_i=minAreaRect(contours0[i]);
            Point2f P_i[4];
            rect_i.points(P_i);
            int lable=0;
            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[1].x<<","<<P_i[1].y<<")  ("<<P_i[3].x<<","<<P_i[3].y<<") --> ("<<P_j[1].x<<","<<P_j[1].y<<")  ("<<P_j[3].x<<","<<P_j[3].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&&(recArea_i<2500&&recArea_j<2500))
                {
                    lable=1;
                    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);//画实心矩形
                    //cout<<"yes";
                }
                //cout<<endl;
            }
            //cout<<"---------------------------------------------------"<<endl;
            if(lable==0&&contourArea(contours0[i])<110)
                rectangle(image,Point(P_i[1].x,P_i[1].y),Point(P_i[3].x,P_i[3].y),Scalar(0,0,0),-1,1);
            else
                rectangle(image,Point(P_i[1].x,P_i[1].y),Point(P_i[3].x,P_i[3].y),Scalar(255,255,255),-1,1);
        }
        //imwrite("C:\Users\Administrator\Desktop\image2.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)+3;
            int maxx=max(P[3].x,P[0].x)-3;
            int miny=min(P[2].y,P[3].y)+3;
            int maxy=max(P[1].y,P[0].y)-3;
            rectangle(outImage,Point(minx,miny),Point(maxx,maxy),Scalar(0,0,0),2,1);//二值图绘线
    
        }
        imwrite("C:\Users\Administrator\Desktop\image.png", outImage);
    
        waitKey(0);
        return 0;
    }
  • 相关阅读:
    css资料汇总
    typescript 点滴
    vue-cli3点滴
    item2的使用方法推介
    rfc文档
    websocket
    g2
    常用的正则积累
    Vue-20190623点滴
    写一个webpackLoader
  • 原文地址:https://www.cnblogs.com/dzzy/p/9284690.html
Copyright © 2011-2022 走看看