具有散乱字符的图像的倾斜角度检测
Skew angle detection on a image with scattered characters
我一直在关注 this tutorial 以获得图像的倾斜角度。当字符有点分散在目标图像上时,HoughLinesP 似乎很难找到线条。
这是我的输入图像:
这是 HoughLinesP 找到的行:
它并没有真正得到大部分台词,对我来说原因似乎很明显。这是因为我已将 minLineWidth 设置为 (size.width / 2.f)。关键是因为它发现的几行结果证明倾斜角度也是错误的。 (在本例中为 -3.15825,当它应该接近 0.5 时)
我试图腐蚀我的输入文件以使角色靠得更近,在这种情况下似乎可行,但我认为这不是类似情况的最佳方法。
这是我腐蚀的输入图像:
这是 HoughLinesP 找到的行:
这次它发现了 -0.2185 度的倾斜角度,这是我所期望的,但另一方面它正在失去线与线之间的垂直 space,在我看来这不是一个好主意事物。
有没有另一种方法可以对这种图像进行预处理,使houghLinesP对散乱的字符有更好的效果?
这是我使用的源代码:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
static cv::Scalar randomColor( cv::RNG& rng )
{
int icolor = (unsigned) rng;
return cv::Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}
void rotate(cv::Mat& src, double angle, cv::Mat& dst)
{
int len = std::max(src.cols, src.rows);
cv::Point2f pt(len/2., len/2.);
cv::Mat r = cv::getRotationMatrix2D(pt, angle, 1.0);
cv::warpAffine(src, dst, r, cv::Size(len, len));
}
double compute_skew(cv::Mat& src)
{
// Random number generator
cv::RNG rng( 0xFFFFFFFF );
cv::Size size = src.size();
cv::bitwise_not(src, src);
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(src, lines, 1, CV_PI/180, 100, size.width / 2.f, 20);
cv::Mat disp_lines(size, CV_8UC3, 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]), randomColor(rng));
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 << angle * 180 / CV_PI << std::endl;
cv::imshow("HoughLinesP", disp_lines);
cv::waitKey(0);
return angle * 180 / CV_PI;
}
int main()
{
// Load in grayscale.
cv::Mat img = cv::imread("IMG_TESTE.jpg", 0);
cv::Mat rotated;
double angle = compute_skew(img);
rotate(img, angle, rotated);
//Show image
cv::imshow("Rotated", rotated);
cv::waitKey(0);
}
干杯
我建议先找到单独的组件(即线条和字母),例如使用 cv::threshold
和 cv::findContours
。
然后,您可以删除窄的单个组件(即字母)。例如,您可以使用 cv::floodFill
来执行此操作。这应该只给您留下线条。
实际上,去掉字母可能会为 Hough 变换提供更容易的输入。
尝试将字符组检测为块,然后找到这些块的轮廓。下面我使用模糊、形态学开运算和阈值运算完成了它。
Mat im = imread("yCK4t.jpg", 0);
Mat blurred;
GaussianBlur(im, blurred, Size(5, 5), 2, 2);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
Mat morph;
morphologyEx(blurred, morph, CV_MOP_OPEN, kernel);
Mat bw;
threshold(morph, bw, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
Mat cont = Mat::zeros(im.rows, im.cols, CV_8U);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
{
drawContours(cont, contours, idx, Scalar(255, 255, 255), 1);
}
然后对轮廓图像使用霍夫线变换。
使用累加器阈值 80,我得到以下导致角度为 -3.81 的线。这是高的,因为离群线几乎是垂直的。使用这种方法,除了少数异常值外,大多数线将具有相似的角度值。检测并丢弃异常值将为您提供更好的角度近似值。
HoughLinesP(cont, lines, 1, CV_PI/180, 80, size.width / 4.0f, size.width / 8.0f);
我一直在关注 this tutorial 以获得图像的倾斜角度。当字符有点分散在目标图像上时,HoughLinesP 似乎很难找到线条。
这是我的输入图像:
这是 HoughLinesP 找到的行:
它并没有真正得到大部分台词,对我来说原因似乎很明显。这是因为我已将 minLineWidth 设置为 (size.width / 2.f)。关键是因为它发现的几行结果证明倾斜角度也是错误的。 (在本例中为 -3.15825,当它应该接近 0.5 时)
我试图腐蚀我的输入文件以使角色靠得更近,在这种情况下似乎可行,但我认为这不是类似情况的最佳方法。
这是我腐蚀的输入图像:
这是 HoughLinesP 找到的行:
这次它发现了 -0.2185 度的倾斜角度,这是我所期望的,但另一方面它正在失去线与线之间的垂直 space,在我看来这不是一个好主意事物。
有没有另一种方法可以对这种图像进行预处理,使houghLinesP对散乱的字符有更好的效果?
这是我使用的源代码:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
static cv::Scalar randomColor( cv::RNG& rng )
{
int icolor = (unsigned) rng;
return cv::Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}
void rotate(cv::Mat& src, double angle, cv::Mat& dst)
{
int len = std::max(src.cols, src.rows);
cv::Point2f pt(len/2., len/2.);
cv::Mat r = cv::getRotationMatrix2D(pt, angle, 1.0);
cv::warpAffine(src, dst, r, cv::Size(len, len));
}
double compute_skew(cv::Mat& src)
{
// Random number generator
cv::RNG rng( 0xFFFFFFFF );
cv::Size size = src.size();
cv::bitwise_not(src, src);
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(src, lines, 1, CV_PI/180, 100, size.width / 2.f, 20);
cv::Mat disp_lines(size, CV_8UC3, 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]), randomColor(rng));
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 << angle * 180 / CV_PI << std::endl;
cv::imshow("HoughLinesP", disp_lines);
cv::waitKey(0);
return angle * 180 / CV_PI;
}
int main()
{
// Load in grayscale.
cv::Mat img = cv::imread("IMG_TESTE.jpg", 0);
cv::Mat rotated;
double angle = compute_skew(img);
rotate(img, angle, rotated);
//Show image
cv::imshow("Rotated", rotated);
cv::waitKey(0);
}
干杯
我建议先找到单独的组件(即线条和字母),例如使用 cv::threshold
和 cv::findContours
。
然后,您可以删除窄的单个组件(即字母)。例如,您可以使用 cv::floodFill
来执行此操作。这应该只给您留下线条。
实际上,去掉字母可能会为 Hough 变换提供更容易的输入。
尝试将字符组检测为块,然后找到这些块的轮廓。下面我使用模糊、形态学开运算和阈值运算完成了它。
Mat im = imread("yCK4t.jpg", 0);
Mat blurred;
GaussianBlur(im, blurred, Size(5, 5), 2, 2);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
Mat morph;
morphologyEx(blurred, morph, CV_MOP_OPEN, kernel);
Mat bw;
threshold(morph, bw, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
Mat cont = Mat::zeros(im.rows, im.cols, CV_8U);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
{
drawContours(cont, contours, idx, Scalar(255, 255, 255), 1);
}
然后对轮廓图像使用霍夫线变换。 使用累加器阈值 80,我得到以下导致角度为 -3.81 的线。这是高的,因为离群线几乎是垂直的。使用这种方法,除了少数异常值外,大多数线将具有相似的角度值。检测并丢弃异常值将为您提供更好的角度近似值。
HoughLinesP(cont, lines, 1, CV_PI/180, 80, size.width / 4.0f, size.width / 8.0f);