从偏斜图像OpenCV中提取文本

时间:2015-12-01 13:51:48

标签: c++ opencv visual-studio-2013 tesseract

我是OpenCV的新手,我通过OpenCV看到了许多文本提取解决方案,但没有一个解决了我的问题。我正在使用visual studio 2013与tesseract OCR,C ++和OpenCV。

我的问题是从倾斜的图像中提取文本。这是一个我想要去偏斜的示例图像,我需要提取整个文本。 enter image description here

1 个答案:

答案 0 :(得分:2)

您可以看到本教程检测图像中的倾斜角度并进行处理。本教程完整地说明了如何解决您的问题:

http://felix.abecassis.me/2011/09/opencv-detect-skew-angle/

包括以下链接教程的主题:

使用OpenCV实现

首先,让我们声明一个函数compute_skew,它将图像的路径作为输入,并将检测到的角度输出到标准输出。 首先,我们加载图像并将其大小存储在变量中,非常简单。

void compute_skew(const char* filename)
{
   // Load in grayscale.
   cv::Mat src = cv::imread(filename, 0);
   cv::Size size = src.size();

在图像处理中,物体是白色的,背景是黑色的,我们则相反,我们需要反转图像的颜色:

cv::bitwise_not(src, src);

结果如下:

enter image description here

为了计算偏斜,我们必须在文本中找到直线。在文本行中,我们并排放置几个字母,因此应该通过在图像中找到长行的白色像素来形成线条。以下是一个例子:

enter image description here

当然,由于字符有高度,我们会从文本中找到每条实际行的几行。通过微调稍后使用的参数或使用预处理,我们可以减少行数。

那么,我们如何在图像中找到线条?我们使用一种称为Hough变换的强大数学工具。我不会深入研究数学细节,但Hough变换的主要思想是使用2D累加器来计算在图像中找到给定线的次数,扫描整个图像并通过投票系统确定了“最佳”线。 我们使用了标准霍夫变换(SHT)的更有效的变体,称为概率霍夫变换(PHT)。在OpenCV中,PHT以HoughLinesP的名称实现。

除了Hough变换的标准参数外,我们还有两个参数:

minLineLength - 最小行长度。短于此的线段将被拒绝。这是一个很好的工具,以修剪小的残余线。 maxLineGap - 链接它们的同一行上各点之间允许的最大间隙。 这对于多列文本可能很有趣,例如我们可以选择不链接来自不同文本列的行。 现在回到C ++,在OpenCV中,PHT存储线的端点,而SHT将线存储在极坐标(相对于原点)中。我们需要一个向量来存储所有端点:

std::vector<cv::Vec4i> lines;

我们现在准备好进行霍夫变换了:

cv::HoughLinesP(src, lines, 1, CV_PI/180, 100, size.width / 2.f, 20);

我们对ρ使用步长1,对θ使用π/ 180,阈值(最小投票数)为100。 minLineLength是width / 2,如果文本被很好地隔离,这不是一个不合理的假设。 maxLineGap是20,它似乎是间隙的合理值。

在剩下的代码中,我们使用atan2数学函数简单地计算每条线和水平线之间的角度,我们计算所有线的平均角度。 出于调试目的,我们还在一个名为disp_lines的新图像中绘制所有线条,并在新窗口中显示该图像。

    cv::Mat disp_lines(size, CV_8UC1, cv::Scalar(0, 0, 0));
    double angle = 0.;
    unsigned nb_lines = lines.size();
    for (unsigned i = 0; i < nb_lines; ++i)
    {
        cv::line(disp_lines, cv::Point(lines[i][0], lines[i][1]),
                 cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255, 0 ,0));
        angle += atan2((double)lines[i][3] - lines[i][1],
                       (double)lines[i][2] - lines[i][0]);
    }
    angle /= nb_lines; // mean angle, in radians.

    std::cout << "File " << filename << ": " << angle * 180 / CV_PI << std::endl;

    cv::imshow(filename, disp_lines);
    cv::waitKey(0);
    cv::destroyWindow(filename);
}

我们只需要一个main函数来调用几个图像上的compute_skew:

const char* files[] = { "m8.jpg", "m20.jpg", "p3.jpg", "p16.jpg", "p24.jpg"};

int main()
{
    unsigned nb_files = sizeof(files) / sizeof(const char*);
    for (unsigned i = 0; i < nb_files; ++i)
        compute_skew(files[i]);
}