半稳健的报纸栏目提取

时间:2015-12-10 20:02:23

标签: c++ opencv

这是我的第一个openCV程序,如果我对某些基本的计算机视觉概念一无所知,请原谅。

更新:由于sturkmen

的回答,请查看底部的新代码/新问题

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

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

我目前的做法如下:

  1. 应用反向二进制阈值

  2. 扩张图像并找到轮廓

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

  4. 这已经确定

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

    所以,问题在于列表的“迷你”部分"在图像中没有被可靠地拾取(最好的例子是最右边一列中没有boundingRect的那个)。

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

    1)组合作为垂直邻居的boundingRect来捕获列。包含可能的边缘情况。

    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;
    

    }

    原始图片:

    更新了代码

    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);
    

    新结果:

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

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

1 个答案:

答案 0 :(得分: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;
}

Test Image enter image description here

我知道它是不完整的,但我希望你能理解方法,并通过过滤rects来找到所需的七个rect来完成它,或者我将很快完成代码。

编辑:代码可能有点脏,但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;
}

enter image description here