使用OpenCV查找图像上的数字边界框

时间:2015-12-17 18:01:55

标签: java c++ opencv bounding-box

我试图在下面3张图片的中间找到数字的边界框。

这是我尝试使用的3张示例卡片。

Card 1

Card 2

Card 3

我使用的代码基于(几乎完整副本)第一个答案here中提供的代码,虽然转换为Java(C ++中的答案很好)并且添加了大小的参数要合并的轮廓(在我的代码中定义为sizeHorizo​​nal和sizeVertical),这是我在下面的图片中玩的两个参数。

MatOfPoint2f approxCurve = new MatOfPoint2f();

Mat imgMAT = new Mat();
Utils.bitmapToMat(bmp32, imgMAT);

Mat grad = new Mat();

Imgproc.cvtColor(imgMAT, grad, Imgproc.COLOR_BGR2GRAY);

Mat img_sobel = new Mat();
Mat img_threshold = new Mat();

Imgproc.Sobel(grad, img_sobel, CvType.CV_8U, 1, 0, 3, 1, 0, Core.BORDER_DEFAULT);

Imgproc.threshold(img_sobel, img_threshold, 0, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY);

Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(sizeHorizontal, sizeVertical));

Imgproc.morphologyEx(img_threshold, img_threshold, Imgproc.MORPH_CLOSE, element);

Imgproc.cvtColor(imgMAT, imgMAT, Imgproc.COLOR_BGR2GRAY);


List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(img_threshold, contours, new Mat(), Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE, new org.opencv.core.Point(0, 0));

for (int i = 0; i < contours.size(); i++) {

    //Convert contours(i) from MatOfPoint to MatOfPoint2f
    MatOfPoint2f contour2f = new MatOfPoint2f( contours.get(i).toArray() );

    //Processing on mMOP2f1 which is in type MatOfPoint2f
    double approxDistance = Imgproc.arcLength(contour2f, true)*0.02;
    Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);

    //Convert back to MatOfPoint
    MatOfPoint points = new MatOfPoint( approxCurve.toArray() );

    // Get bounding rect of contour
    org.opencv.core.Rect rect = Imgproc.boundingRect(points);

    Imgproc.rectangle(imgMAT, rect.tl(), rect.br(), new Scalar(0, 255, 0), 2);
}

我有单独的数字部分轮廓,但我找不到一种方法来隔离我想要的轮廓。这里是使用尺寸输入参数绘制轮廓的区域。正如你可以看到的第二张图片,这是完全按照我想要的方式工作,并且轮廓整个数字,而不是每个部分。

1:大小参数输入:17,5

enter image description here

2:大小参数输入:23,7

enter image description here

3:大小参数输入:23,13

enter image description here

所以,我需要帮助的事情:

  1. 隔离中间的四个轮廓并找到将这些轮廓合并在一起的方法
  2. 我考虑过采用与给定宽高比相匹配的轮廓并裁剪到包含所有这些轮廓线的边界框,但还有其他周围轮廓具有相似的比例。

    1. 找到一种自动选择正确尺寸参数的方法(因为每种卡类型需要不同的参数来隔离数字)
    2. 如果没有尝试所有3个尺寸的输入并查看给出预期轮廓的内容,我可以使用流行的颜色作为卡片类型的指示器,然后使用此卡片类型的参数。但是,任何其他建议都会有所帮助,因为我觉得有更好的方法可以做到这一点。

      非常感谢!

1 个答案:

答案 0 :(得分:2)

enter image description here

在我繁忙的日程中,我可以帮助你灭绝一些。请找到下面的代码,它将帮助您获得前两张图片。为第三张图像微调。只需使用形态学操作即可获得所需的输出。

//#include "stdafx.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include "tchar.h"
using namespace cv;
using namespace std;

#define INPUT_FILE              "p.jpg"
#define OUTPUT_FOLDER_PATH      string("")

int _tmain(int argc, _TCHAR* argv[])
{
    Mat large = imread(INPUT_FILE);
    Mat rgb;
    // downsample and use it for processing
    pyrDown(large, rgb);
    Mat small;
    cvtColor(rgb, small, CV_BGR2GRAY);
    // morphological gradient
    Mat grad;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(2, 2));
    Mat morphKernel1 = getStructuringElement(MORPH_ELLIPSE, Size(1, 1));
    morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
    // binarize
    Mat bw;
    threshold(grad, bw, 5.0, 50.0, THRESH_BINARY | THRESH_OTSU);
    // connect horizontally oriented regions
    Mat connected;
    morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
    morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
    morphologyEx(bw, connected, MORPH_OPEN, morphKernel1);
    morphologyEx(connected, connected, MORPH_CLOSE, morphKernel);
    morphologyEx(connected, connected, MORPH_CLOSE, morphKernel);
     morphologyEx(connected, connected, MORPH_CLOSE, morphKernel);
    // find contours
    Mat mask = Mat::zeros(bw.size(), CV_8UC1);
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    // filter contours
    int y=0;
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
    {
        Rect rect = boundingRect(contours[idx]);
        Mat maskROI(mask, rect);
        maskROI = Scalar(0, 0, 0);
        // fill the contour
        drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);

        double a=contourArea( contours[idx],false);
                    if(a> 575)

        {
            rectangle(rgb, rect, Scalar(0, 255, 0), 2);
            y++;
        }
        imshow("Result1",rgb);
    }
    cout<<" The number of elements"<<y<< endl; 
    imshow("Result",mask);
    imwrite(OUTPUT_FOLDER_PATH + string("rgb.jpg"), rgb);
    waitKey(0);
    return 0;
}