C++ 从倾斜图像OpenCV中提取文本
我是OpenCV的新手,我见过许多通过OpenCV提取文本的解决方案,但没有一个解决了我的问题。我使用Visual Studio 2013与TestSerACT OCR、C++和OpenCV。< /P>C++ 从倾斜图像OpenCV中提取文本,c++,opencv,visual-studio-2013,tesseract,C++,Opencv,Visual Studio 2013,Tesseract,我是OpenCV的新手,我见过许多通过OpenCV提取文本的解决方案,但没有一个解决了我的问题。我使用Visual Studio 2013与TestSerACT OCR、C++和OpenCV。< /P> 我的问题是从倾斜的图像中提取文本。这里是一个示例图像,我想反扭曲,我需要提取整个文本 您可以查看本教程来检测图像中的倾斜角度并对其进行处理。本教程完全说明了如何解决您的问题: 包括以下链接教程的jist: 用OpenCV实现 首先,让我们声明一个函数compute_skew,它将图像的路径作为
我的问题是从倾斜的图像中提取文本。这里是一个示例图像,我想反扭曲,我需要提取整个文本 您可以查看本教程来检测图像中的倾斜角度并对其进行处理。本教程完全说明了如何解决您的问题: 包括以下链接教程的jist: 用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变换的主要思想是使用2D累加器来计算在图像中找到给定线条的次数,扫描整个图像,并通过投票系统识别“最佳”线条。
我们使用了标准霍夫变换(SHT)的一种更有效的变体,称为概率霍夫变换(PHT)。在OpenCV中,PHT以HoughLinesP的名称实现
除了Hough变换的标准参数外,我们还有两个附加参数:
minLineLength–最小线长度。短于该长度的线段将被拒绝。这是一个伟大的工具,以修剪出小残留线。
maxLineGap–同一直线上点之间链接点的最大允许间距。
这对于多列文本可能很有趣,例如,我们可以选择不链接来自不同文本列的行。
回到C++,在OpenCV中,PHT存储行的端点,而SHT-存储在极坐标(相对于原点)的行。我们需要一个向量来存储所有端点:
std::vector<cv::Vec4i> lines;
对于ρ,我们使用1的步长,对于θ,使用π/180,阈值(最小投票数)是100。
minLineLength是width/2,如果文本被很好地隔离,这不是一个不合理的假设。
maxLineGap是20,它似乎是一个音高值
在剩下的代码中,我们只需使用atan2数学函数计算每条线与水平线之间的角度,然后计算所有线的平均角度。
出于调试目的,我们还绘制了一个名为disp_line的新图像中的所有线条,并在一个新窗口中显示该图像
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);
}
cv::Mat disp_行(大小,cv_8UC1,cv::Scalar(0,0,0));
双角度=0。;
无符号nb_行=行。大小();
对于(无符号i=0;i 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);
}
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]);
}