【问题标题】:OpenCV detect rectangle with the largest widthOpenCV检测宽度最大的矩形
【发布时间】:2017-11-10 20:50:40
【问题描述】:

我正在尝试从该图像中获取此矩形:

使用 OpenCV 找到了这个解决方案:

 private Bitmap findRectangle(Bitmap src) throws Exception {
        Mat imageMat = new Mat();
        Utils.bitmapToMat(src, imageMat);

        Mat imgSource=imageMat.clone();

        Imgproc.cvtColor(imgSource, imageMat, Imgproc.COLOR_BGR2GRAY);

        //find the contours
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(imageMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);

        Imgproc.Canny(imageMat,imageMat,0,255);
        Bitmap canny=Bitmap.createBitmap(imageMat.cols(),imageMat.rows(),Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(imageMat,canny);

        Imgproc.GaussianBlur(imageMat, imageMat, new  org.opencv.core.Size(1, 1), 2, 2);
        Bitmap blur=Bitmap.createBitmap(imageMat.cols(),imageMat.rows(),Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(imageMat,blur);

        MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point

        for (int idx = 0; idx < contours.size(); idx++) {
            temp_contour = contours.get(idx);
            //check if this contour is a square

            MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );

            int contourSize = (int)temp_contour.total();
            MatOfPoint2f approxCurve_temp = new MatOfPoint2f();
            Imgproc.approxPolyDP(new_mat, approxCurve_temp, contourSize*0.05, true);

            if (approxCurve_temp.total() == 4) {
                MatOfPoint points = new MatOfPoint( approxCurve_temp.toArray() );
                Rect rect = Imgproc.boundingRect(points);
                Imgproc.rectangle(imgSource, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height), new Scalar(255, 0, 0, 255), 3);

            }

        }
        Bitmap analyzed=Bitmap.createBitmap(imgSource.cols(),imgSource.rows(),Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(imgSource,analyzed);

        return analyzed;
    }

我得到的最好的是:

问题是矩形并不完美,也许找到里面的白色数字可能是最好的选择,但我对 OpenCV 了解不多。

原图:

【问题讨论】:

  • 如果您使用的是手机相机,您可以在拍照前在屏幕上制作矩形占位符。这可以提高您的检测准确性并消除第一级噪声。然后尝试在图像中找到最大的轮廓。希望对您有所帮助。

标签: java android opencv


【解决方案1】:

这是一个非常简单的 C++ 实现,它尝试搜索文本框。检测的准确性取决于三个参数:

thresh 值提供给cv::threshold 函数以将灰度图像转换为二进制。

高/宽比,因为文本框的高度相对小于宽度,以及文本框的面积

Mat img = imread("image.jpg",-1), gray, binary;

/*pre-processing steps*/
uchar thresh = 80;
cvtColor(img, gray, cv::COLOR_BGR2GRAY);
GaussianBlur(gray, gray, Size(7,7), 0);
// change the thresh value to fine tune this program for your images
threshold(gray, binary, thresh, 255, cv::THRESH_BINARY_INV);

/*contour searching*/
std::vector<std::vector<Point>> contours;
std::vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);

/*Filtering contours based on height/width ratio and bounding box area*/
std::vector<Rect> boxes;
double box_ratio = 0.3;
int box_area = 20000;

for(auto& cnt : contours)
{
    auto box = minAreaRect(cnt).boundingRect();
    // we are searching for a rectangle which a has relatively large area,
    // and the height is smaller than the width, so the
    // height/width ratio should be small. Change the these two values for fine tuning
    if((min(box.width,box.height)/double(max(box.width,box.height)) < box_ratio) && box.area() > box_area )
    {
        boxes.push_back(box);
    }

}

Mat txt_box = img(boxes.at(0));

【讨论】:

    【解决方案2】:

    这是java上几乎相同的解决方案:

    private Bitmap findRoi(Bitmap sourceBitmap) {
    
        Mat sourceMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CV_8UC3);
        Utils.bitmapToMat(sourceBitmap, sourceMat);
    
        Mat grayMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CV_8UC3);
        Imgproc.cvtColor(sourceMat, grayMat, Imgproc.COLOR_BGR2GRAY);
        Imgproc.threshold(grayMat, grayMat, 125, 200, Imgproc.THRESH_BINARY);
    
        // find contours
        List<MatOfPoint> whiteContours = new ArrayList<>();
        Rect largestRect = null;
        Imgproc.findContours(grayMat, whiteContours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
    
        // find appropriate bounding rectangles
        for (MatOfPoint contour : whiteContours) {
            RotatedRect boundingRect = Imgproc.minAreaRect(new MatOfPoint2f(contour.toArray()));
            double rectangleArea = boundingRect.size.area();
    
            // test min ROI area in pixels
            if (rectangleArea > 10000) {
                Point rotated_rect_points[] = new Point[4];
                boundingRect.points(rotated_rect_points);
                Rect rect = Imgproc.boundingRect(new MatOfPoint(rotated_rect_points));
    
                // test horizontal ROI orientation and aspect ratio
                if (rect.width > 3 * rect.height) {
                    if (largestRect == null) {
                        largestRect = rect;
                    } else {
                        if (rect.width > largestRect.width) {
                            largestRect = rect;
                        }
                    }
                }
            }
        }
    
        Mat roiMat = new Mat(sourceMat, largestRect);
    
        Bitmap bitmap = Bitmap.createBitmap(roiMat.cols(), roiMat.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(roiMat, bitmap);
        return bitmap;
    }
    

    此外,您还可以使用附加信息:右侧的红色数字位置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-23
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      相关资源
      最近更新 更多