很多时候我们获得的图像并不是正位的(比如我们拍摄的照片,由于手持姿势的不同,很难拍出刚好是正位的照片),而不是正位的图片要进行布局分析与文字识别是比较不方便的。所以在布局分析和文字识别之前我们需要对图像进行矫正。接下来的这篇文章我们就来介绍一下OpenCV的图像矫正算法并将其用于实战。
摘要
在机器视觉中,对于图像的处理有时候因为放置的原因导致ROI区域倾斜,这个时候我们会想办法把它纠正为正确的角度视角来,方便下一步的布局分析与文字识别,这个时候通过透视变换就可以取得比较好的裁剪效果。
本次实战,对于图像的矫正使用了两种矫正思路:
- 针对边缘比较明显的图像,使用基于轮廓提取的矫正算法。
- 针对边缘不明显,但是排列整齐的文本图像,使用了基于霍夫直线探测的矫正算法。
基于轮廓提取的矫正算法
整体思路:
- 图片灰度化,二值化
- 检测轮廓,并筛选出目标轮廓(通过横纵比或面积去除干扰轮廓)
- 获取目标轮廓的最小外接矩形
- 获取最小外接矩形的四顶点,并定义矫正图像后的四顶点
- 透视变换(四点变换)
opencv实现(分解步骤):
(一)图片灰度化,二值化(开运算,消除噪点)
Mat src = imread("D:/opencv练习图片/图片矫正.png");
imshow("原图片", src);
// 二值图像
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY_INV| THRESH_OTSU);
imshow("二值化", binary);
// 定义结构元素
Mat se = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(binary, binary, MORPH_OPEN, se);
imshow("开运算", binary);
注意:由于原图像背景是白色,因此二值化时候要用THRESH_BINARY_INV
(二)提取轮廓,筛选轮廓
// 寻找最大轮廓
vector<vector<Point>> contours;
findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
int index = -1;
int max = 0;
for (size_t i = 0; i < contours.size(); i++)
{
double area = contourArea(contours[i]);
if (area > max)
{
max = area;
index = i;
}
}
(三)求取最小外接矩形以及四顶点坐标,并定义变换后的四顶点坐标
// 寻找最小外接矩形
RotatedRect rect = minAreaRect(contours[index]);
Point2f srcpoint[4];//存放变换前四顶点
Point2f dstpoint[4];//存放变换后四顶点
rect.points(srcpoint);//获取最小外接矩形四顶点坐标
//显示顶点
for (size_t i = 0; i < 4; i++)
{
circle(src, srcpoint[i], 5, Scalar(0, 0, 255),-1);//-1表示填充
}
imshow("顶点坐标", src);
//获取外接矩形宽高
float width = rect.size.width;
float height = rect.size.height;
//定义矫正后四顶点
dstpoint[0]= Point2f(0, height);
dstpoint[1] = Point2f(0, 0);
dstpoint[2] = Point2f(width, 0);
dstpoint[3] = Point2f(width, height);