我是OpenCV的新手,我通过OpenCV看到了许多文本提取解决方案,但没有一个解决了我的问题。我正在使用visual studio 2013与tesseract OCR,C ++和OpenCV。
答案 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);
结果如下:
为了计算偏斜,我们必须在文本中找到直线。在文本行中,我们并排放置几个字母,因此应该通过在图像中找到长行的白色像素来形成线条。以下是一个例子:
当然,由于字符有高度,我们会从文本中找到每条实际行的几行。通过微调稍后使用的参数或使用预处理,我们可以减少行数。
那么,我们如何在图像中找到线条?我们使用一种称为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]);
}