半稳健的报纸柱提取

Tré*_*iel 7 c++ opencv

这是我的第一个openCV程序,如果我对某些基本的计算机视觉概念一无所知,那就宽恕吧.

更新:由于sturkmen的回答,请查看底部的新代码/新问题

我正在努力将一大堆图像"数字化",就像附加的图像一样,作为一个项目.所有图像都来自同一来源.最终目标是将提取的文本块传递给tesseract,即OCR库.

(源代码在底部) 我将解释我当前的方法,然后陈述我的问题.

我目前的做法如下:

  1. 应用反二进制阈值

  2. 扩张图像并找到轮廓

  3. boundingRect从每个轮廓创建一个,然后过滤最小和最大尺寸

这工作正常

我期望的最终结果是boundingRect每列周围有一个.因此,对于提供的图片,其中有七个.

因此,问题在于图像中的列表"迷你部分"未被可靠地拾取(最好的例子是最右边的列中没有boundingRect围绕它的那个).

我可以想到两个可能的解决方案(以便不是一个开放式/意见类型的问题),但如果你知道一个更好的解决方案,请分享它!

1)组合boundingRect垂直邻居的s来捕获列.包含可能的边缘情况故障.

2)找到一种不同的方法来处理图像,然后再找到轮廓.根据我的研究,运行长度平滑算法看起来很有前景?

所以我的问题是,哪种方法最好?我忽略了一个更好的解决方案吗?我在这个部门缺乏经验,所以没有任何建议太小.

谢谢阅读!

#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
    Mat image = imread(path_to_file);
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    Mat fin;
    double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
    //size impacts dilation
    Mat kernel =  getStructuringElement(MORPH_CROSS, Size(2, 4));
    Mat dilated;
    dilate(fin, dilated, kernel, Point(-1,-1), 6);
    imwrite("testbw.png",dilated);
    Mat hierarchy;
    vector<vector<Point> >contours;
    findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

    //potentially sort by x
    for (const auto& c : contours)
    {
         //       x     y
        //columns 850 x 5400
        Rect r = boundingRect(c);
        if (r.height > 3000 || r.width > 875)
            continue;
        if (r.height < 100 || r.width < 500)
            continue;

        rectangle(image, r, Scalar(255, 0, 255), 2); //made thicker
    }
    imwrite("test.png", image);

    waitKey(0);
    return 0;
Run Code Online (Sandbox Code Playgroud)

}

原始图片:

更新的代码

int main(int argc, char* argv[])
{
    Mat image = imread(path_to_file);
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    Mat fin;
    double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);

    Mat kernel =  getStructuringElement(MORPH_CROSS, Size(2, 4));
    Mat dilated;
    dilate(fin, dilated, kernel, Point(-1,-1), 6);
    vector<Vec4i> hierarchy;
    vector<vector<Point> >contours;
    findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

    vector<Rect> rects;
    Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);

    for (const auto& c : contours)
    {
        //        x     y
        //columns 850 x 5400
        Rect r = boundingRect(c);
        if (r.height > 5500 || r.width > 875)
            continue;
        if (r.height < 300 || r.width < 500)
            continue;

        big_rect = big_rect | r; // here we will find bounding box of all Rects
        rects.push_back( r ); // stores rects 
    }

    for ( size_t i = 0; i < rects.size(); i++ )
    {
        // sets y and height of all rects 
        //cout << rects[i].x << endl;
        rects[i].y = big_rect.y;
        rects[i].height = big_rect.height;
    }

    //groupRectangles(rects, 1); DIDN'T WORK

    for ( size_t i = 0; i < rects.size(); i++ )
    {
        rectangle(image, rects[i], Scalar(255, 0, 255), 2);
    }
    imshow("test", image);
Run Code Online (Sandbox Code Playgroud)

新结果:

新问题:boundingRect每列周围有很多s(你可能无法通过查看图片来判断).这是一个问题,因为我想制作每列的子图像,例如Mat ROI = image(rects[i]),它将比所需的7个图像渲染得多.

新问题:如何将每列的多个矩形合并为一个?我见过openCV groupRectangles,但它无法正常工作.

stu*_*men 1

只是为了展示我尝试更改您的代码的方法,如下所示。

#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
    Mat image = imread(argv[1]);
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    Mat fin;
    double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
    //size impacts dilation
    Mat kernel =  getStructuringElement(MORPH_CROSS, Size(2, 4));
    Mat dilated;
    dilate(fin, dilated, kernel, Point(-1,-1), 1);
    imwrite("testbw.png",dilated);
    Mat hierarchy;
    vector<vector<Point> >contours;
    findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

    vector<Rect> rects;
    Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);
    //potentially sort by x
    for (const auto& c : contours)
    {
        //       x     y
        //columns 850 x 5400
        Rect r = boundingRect(c);
        if (r.height > 3000 || r.width > 875)
            continue;
        if (r.height < 10 || r.width < 10) // changed for test small image
            continue;

        big_rect = big_rect | r; // here we will find bounding box of all Rects
        rects.push_back( r ); // stores rects 
    }

    for ( size_t i = 0; i < rects.size(); i++ )
    {
        // sets y and height of all rects 
        rects[i].y = big_rect.y;
        rects[i].height = big_rect.height;
    }

    for ( size_t i = 0; i < rects.size(); i++ )
    {
        rectangle(image, rects[i], Scalar(255, 0, 255), 2);
    }

    imshow("result", image);

    waitKey(0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

测试图像 在此输入图像描述

我知道它不完整,但我希望您能理解该方法并通过过滤矩形以找到所需的七个矩形来完成它,否则我将很快完成代码。

编辑:代码可能有点脏,但vector<Rect> final_rects只包含您需要的矩形。

#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

using namespace cv;
using namespace std;

struct sorter_func
{
    bool operator ()( Rect a, Rect b )
    {
        return a.x < b.x;
    }
};

int main(int argc, char* argv[])
{
    Mat image = imread(argv[1]);
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    Mat fin;
    double thresh = threshold(gray, fin, 160, 255, THRESH_BINARY_INV);
    //size impacts dilation
    Mat kernel =  getStructuringElement(MORPH_CROSS, Size(2, 4));
    Mat dilated;
    dilate(fin, dilated, kernel, Point(-1,-1), 1);
    imwrite("testbw.png",dilated);
    Mat hierarchy;
    vector<vector<Point> >contours;
    findContours(dilated, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

    vector<Rect> rects;
    Rect big_rect = Rect(image.cols/2,image.rows/2,1,1);
    //potentially sort by x
    for (const auto& c : contours)
    {
        //       x     y
        //columns 850 x 5400
        Rect r = boundingRect(c);
        if (r.height > 3000 || r.width > 875)
            continue;
        if (r.height < 10 || r.width < 10) // changed for test small image
            continue;

        big_rect = big_rect | r; // here we will find bounding box of all Rects
        rects.push_back( r ); // stores rects
    }

    for ( size_t i = 0; i < rects.size(); i++ )
    {
        // sets y and height of all rects
        rects[i].y = big_rect.y;
        rects[i].height = big_rect.height;
    }

    std::sort(rects.begin(), rects.end(), sorter_func());

    for ( size_t i = 1; i < rects.size(); i++ )
    {
        Rect big_rect = rects[i-1] | rects[i];
        if( big_rect.width < rects[i-1].width + rects[i].width )
        {
            rects[i-1] = Rect();
            rects[i] = big_rect;
        }
    }

    vector<Rect> final_rects;
    for ( size_t i = 1; i < rects.size(); i++ )
    {
        if( rects[i].width > 0 )
        {
            rectangle(image, rects[i], Scalar(rand()&255,rand()&255,rand()&255), 2);
            final_rects.push_back( rects[i] );
            cerr << final_rects.size() << endl;
        }
    }
    imshow("result", image);
    waitKey(0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述