美文网首页
c++ opencv矩形检测

c++ opencv矩形检测

作者: 一路向后 | 来源:发表于2022-10-13 22:01 被阅读0次

    1.源码实现

    #include <iostream>
    #include <vector>
    #include <math.h>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    double angle(const Point &pt1, const Point &pt2, const Point &pt0)
    {
        double dx1 = pt1.x - pt0.x;
        double dy1 = pt1.y - pt0.y;
        double dx2 = pt2.x - pt0.x;
        double dy2 = pt2.y - pt0.y;
    
        return (dx1*dx2 + dy1*dy2) / sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
    }
    
    void findSquares(const Mat &image, Mat &out)
    {
        Mat src,dst, gray_one, gray;
        vector<vector<Point>> squares;
        vector<vector<Point>> squares2;
        vector<Point> centers;
        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;
        int thresh = 50, N = 5;
    
        squares.clear();
     
        src = image.clone();
        out = image.clone();
    
        gray_one = Mat(src.size(), CV_8U);
    
        //滤波增强边缘检测
        medianBlur(src, dst, 9);
        dst = src;
    
        //在图像的每个颜色通道中查找矩形
        for (int c = 0; c < image.channels(); c++)
        {
            int ch[] = {c, 0};
     
            //通道分离
            mixChannels(&dst, 1, &gray_one, 1, ch, 1);
     
            //尝试几个阈值
            for(int l = 0; l < N; l++)
            {
                //用canny()提取边缘
                if(l == 0)
                {
                    //检测边缘
                    Canny(gray_one, gray, 5, thresh, 5);
    
                    //膨?
                    dilate(gray, gray, Mat(), Point(-1, -1));
                    //imshow("dilate", gray);
                }
                else
                {
                    gray = gray_one >= (l + 1) * 255 / N;
                }
    
                //轮廓查找
                findContours(gray, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
    
                vector<Point> approx;
       
                //检测所找到的轮廓
                for(size_t i = 0; i < contours.size(); i++)
                {
                    //使用图像轮廓点进行多边形拟合
                    approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
    
                    //计算轮廓面积后,得到矩形4个顶点
                    if(approx.size() == 4 &&fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx)))
                    {
                        double maxCosine = 0;
     
                        for(int j = 2; j < 5; j++)
                        {
                            //求轮廓边缘之间角度的最大余弦
                            double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
                            maxCosine = MAX(maxCosine, cosine);
                        }
    
                        if(maxCosine < 0.3)
                        {
                            squares.push_back(approx);
                        }
                    }
                }
            }
        }
    
        //cout << squares.size() << endl;
        int k = 0;
    
        for(size_t i = 0; i < squares.size(); i++)
        {
            const Point* p = &squares[i][0];
            Point center((squares[i][0].x+squares[i][1].x+squares[i][2].x+squares[i][3].x)/4.0, (squares[i][0].y+squares[i][1].y+squares[i][2].y+squares[i][3].y)/4.0);
            int n = (int)squares[i].size();
            bool flag = false;
    
            //cout << "(" << center.x << ", ";
            //cout << center.y << ")" << endl;
    
            for(int j=0; j<centers.size(); j++)
            {
                if((centers[j].x - center.x)*(centers[j].x - center.x) + (centers[j].y - center.y)*(centers[j].y - center.y) < 16)
                {
                    flag = true;
    
                    int max1 = 0;
                    int max2 = 0;
                    int max3 = 0;
                    int max4 = 0;
    
                    for(int u=0; u<4; u++)
                    {
                        if(squares[i][u].x - centers[j].x < 0)
                        {
                            max1 = centers[j].x - squares[i][u].x > max1 ? centers[j].x - squares[i][u].x : max1;
                        }
                        else
                        {
                            max1 = squares[i][u].x - centers[j].x > max1 ? squares[i][u].x - centers[j].x : max1;
                        }
    
                        if(squares[i][u].y - centers[j].y < 0)
                        {
                            max3 = centers[j].y - squares[i][u].y > max3 ? centers[j].y - squares[i][u].y : max3;
                        }
                        else
                        {
                            max3 = squares[i][u].y - squares[i][u].y > max3 ? squares[i][u].y - squares[i][u].y : max3;
                        }
                    }
    
                    for(int u=0; u<4; u++)
                    {
                        if(squares2[j][u].x - centers[j].x < 0)
                        {
                            max2 = centers[j].x - squares2[j][u].x > max1 ? centers[j].x - squares2[j][u].x : max2;
                        }
                        else
                        {
                            max2 = squares2[j][u].x - centers[j].x > max2 ? squares2[j][u].x - centers[j].x : max2;
                        }
    
                        if(squares2[j][u].y - centers[j].y < 0)
                        {
                            max4 = centers[j].y - squares2[j][u].y > max1 ? centers[j].y - squares2[j][u].y : max4;
                        }
                        else
                        {
                            max4 = squares2[j][u].y - centers[j].y > max4 ? squares2[j][u].y - centers[j].y : max4;
                        }
                    }
    
                    max1 = max1 > max2 ? max1 : max2;
                    max3 = max3 > max4 ? max3 : max4;
    
                    squares2[j][0] = Point(centers[j].x-max1, centers[j].y-max3);
                    squares2[j][1] = Point(centers[j].x+max1, centers[j].y-max3);
                    squares2[j][2] = Point(centers[j].x+max1, centers[j].y+max3);
                    squares2[j][3] = Point(centers[j].x-max1, centers[j].y+max3);
    
                    break;
                }
            }
    
            if(!flag)
            {
                squares2.push_back(squares[i]);
                centers.push_back(center);
    
                if(p->x > 3 && p->y > 3)
                {
                    cout << "center: " << center << endl;
    
                    k++;
    
                    //polylines(out, &p, &n, 1, true, Scalar(0, 0, 255), 2, LINE_AA);
                }
            }
        }
    
        for(int j=0; j<squares2.size(); j++)
        {
            const Point *p = &squares2[j][0];
            int n = (int)squares2[j].size();
    
            polylines(out, &p, &n, 1, true, Scalar(0, 0, 255), 1, LINE_AA);
        }
    
        cout << "square number: " << k << endl;
    }
    
    int main()
    {
        Mat src, dst;
    
        src = imread("7.png");
    
        findSquares(src, dst);
    
        imwrite("8.png", dst);
    
        return 0;
    }
    

    2.编译源码

    $ g++ -o squares squares.cpp -std=c++11 -I/usr/local/opencv3/include -L/usr/local/opencv3/lib -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -Wl,-rpath=/usr/local/opencv3/lib
    

    3.原图及检测结果

    7.png
    8.png

    相关文章

      网友评论

          本文标题:c++ opencv矩形检测

          本文链接:https://www.haomeiwen.com/subject/xccqzrtx.html