c++ opencv矩形检测

2022-10-13  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读