【问题标题】:How to detect whole rectangle in a frame如何检测框架中的整个矩形
【发布时间】:2016-10-22 01:18:59
【问题描述】:

我使用的是 OpenCV4Android 版本 2.4.11,我正在尝试检测从相机检索到的帧中的矩形。我在这个网站上提到了一些问题,它们很有帮助。但我目前面临的问题是 当我尝试检测中间有浅色的物体时,如下面的原始图像所示,在这种情况下,检测算法不会检测到整个物体,而是检测到它的暗部分,如标题部分中的图像所示下文中的“已处理”。

下面发布的代码指示了我遵循的步骤以及我用于检测帧中对象的阈值。

请告诉我为什么没有检测到整个对象以及我可以做些什么来检测整个对象而不仅仅是它的一部分

代码

    //step 1
    this.mMatGray = new Mat();
    Imgproc.cvtColor(this.mMatInputFrame, this.mMatGray, Imgproc.COLOR_BGR2GRAY);
    //step 2
    this.mMatEdges = new Mat();
    Imgproc.blur(this.mMatGray, this.mMatEdges, new Size(7, 7));//7,7
    //step 3
    Imgproc.Canny(this.mMatEdges, this.mMatEdges, 128, 128*2, 5, true);//..,..,2,900,7,true
    //step 4
    dilated = new Mat();
    Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(3, 3));
    Imgproc.dilate(mMatEdges, dilated, dilateElement);

     ArrayList<MatOfPoint> contours = new ArrayList<>();
    hierachy = new Mat();
    Imgproc.findContours(dilated, contours, hierachy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

    MatOfPoint2f approxCurve = new MatOfPoint2f();
    if (contours.size() > 0) {
        for (int i = 0; i < contours.size(); i++) {

            MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(i).toArray());
            double approxDistance = Imgproc.arcLength(contour2f, true) * .02;//.02
            Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
            MatOfPoint points = new MatOfPoint(approxCurve.toArray());

            if (points.total() >= 4 && Imgproc.isContourConvex(points) && Math.abs(Imgproc.contourArea(points)) >= 40000 && Math.abs(Imgproc.contourArea(points)) <= 150000) {
                Rect boundingRect = Imgproc.boundingRect(points);
                RotatedRect minAreaRect = Imgproc.minAreaRect(contour2f);
                Point[] rectPoints = new Point[4];
                minAreaRect.points(rectPoints);
                Rect minAreaAsRect = minAreaRect.boundingRect();

                //to draw the minAreaRect
                for( int j = 0; j < 4; j++ ) {
                    Core.line(mMatInputFrame, rectPoints[j], rectPoints[(j+1)%4], new Scalar(255,0,0));
                }
                Core.putText(mMatInputFrame, "MinAreaRect", new Point(10, 30), 1,1 , new Scalar(255,0,0),2);
                Core.putText(mMatInputFrame, "Width: " + minAreaAsRect.width , new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-100), 1,1 , new Scalar(255,0,0),2);
                Core.putText(mMatInputFrame, "Height: " + minAreaAsRect.height, new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-80), 1,1 , new Scalar(255,0,0),2);
                Core.putText(mMatInputFrame, "Area: " + minAreaAsRect.area(), new Point(minAreaAsRect.tl().x, minAreaAsRect.tl().y-60), 1,1 , new Scalar(255,0,0),2);

                //drawing the contour
                Imgproc.drawContours(mMatInputFrame,  contours, i, new Scalar(0,0,0),2);

                //drawing the boundingRect
                Core.rectangle(mMatInputFrame, boundingRect.tl(), boundingRect.br(), new Scalar(0, 255, 0), 1, 1, 0);
                Core.putText(mMatInputFrame, "BoundingRect", new Point(10, 60), 1,1 , new Scalar(0,255,0),2);
                Core.putText(mMatInputFrame, "Width: " + boundingRect.width , new Point(boundingRect.br().x-100, boundingRect.tl().y-100), 1,1 , new Scalar(0,255,0),2);
                Core.putText(mMatInputFrame, "Height: " + boundingRect.height, new Point(boundingRect.br().x-100, boundingRect.tl().y-80), 1,1 , new Scalar(0,255,0),2);
                Core.putText(mMatInputFrame, "Area: " + Imgproc.contourArea(points), new Point(boundingRect.br().x-100, boundingRect.tl().y-60), 1,1 , new Scalar(0,255,0),2);
            }
        }
    }

原图

处理后的图像

【问题讨论】:

    标签: opencv image-processing object-detection opencv4android


    【解决方案1】:

    我已经用 C++ 实现了。 API 是相同的,因此您可以轻松移植到 android。我用过 Opencv 2.4.8 。请检查实施。希望代码说明做了什么:

    #include <iostream>
    #include <string>
    #include "opencv/highgui.h"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/objdetect/objdetect.hpp"
    
    using namespace std;
    using namespace cv;
    
    
    Mat GetKernel(int erosion_size)
    {
           Mat element = getStructuringElement(cv::MORPH_CROSS,
                  cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1),
                  cv::Point(erosion_size, erosion_size) );
    
           return element;
    }
    int main()
    {
        Mat img = imread("C:/Users/dell2/Desktop/j6B3A.png",0);//loading gray scale image
        Mat imgC = imread("C:/Users/dell2/Desktop/j6B3A.png",1);
        GaussianBlur(img,img,Size(7,7),1.5,1.5);
    
        Mat dimg;
        adaptiveThreshold(img,dimg,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,17,1);
    
    
    
           dilate(dimg,img,GetKernel(2)); 
           erode(img,dimg,GetKernel(2)); 
           erode(dimg,img,GetKernel(1)); 
    
    
           dimg = img;
    
        //*
         vector<vector<Point>> contours; // Vector for storing contour
        vector<Vec4i> hierarchy;
    
        findContours( dimg, contours, hierarchy,CV_RETR_TREE , CV_CHAIN_APPROX_NONE ); // Find the contours in the image
    
         double largest_area = 0;
         int largest_contour_index = 0;
         Rect bounding_rect;
    
         for( int i = 0; i< contours.size(); i++ ) // iterate through each contour. 
          {
           double a=contourArea( contours[i],false);  //  Find the area of contour
           if(a>largest_area){
           largest_area=a;
           largest_contour_index=i;                //Store the index of largest contour
           bounding_rect=boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
           }
    
          }
    
         drawContours( imgC, contours, largest_contour_index, Scalar(255,0,0), 2, 8, hierarchy, 0, Point() );
        rectangle(imgC, bounding_rect,  Scalar(0,255,0),2, 8,0);  
     /**/
    
        //imshow("display",dimg);
        imshow("display2",imgC);
        waitKey(0);
        return 0;
    }
    

    产生的输出:

    如有必要,您可以微调阈值。

    【讨论】:

    • 谢谢..你能告诉我为什么你使用“侵蚀然后dailate然后侵蚀”吗??
    • 你认为如果我使用 Canny 边缘检测器我不会得到相同的结果吗??
    • 我没试过,但我想如果你像我一样使用dilate/erode,你可以得到类似的结果。
    猜你喜欢
    • 1970-01-01
    • 2016-04-05
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 2012-06-09
    • 1970-01-01
    相关资源
    最近更新 更多