OpenCV之光学字符识别--文本分割算法(十一)

一,预处理,对图像进行阀值处理,消除所有颜色信息。

Mat binarize(Mat input)
	{
		Mat binaryImage;
		cvtColor(input, input, COLOR_BGR2GRAY);
		threshold(input, binaryImage, 0, 255, THRESH_OTSU);
	
		//Count the number of black and white pixels
		int white = countNonZero(binaryImage);
		int black = binaryImage.size().area() - white;
	
		//If the image is mostly white (white background), invert it
		return white < black ? binaryImage : ~binaryImage;
	}

Otsu方法使类间方差最大化。

二,文本分割,
1,使用连通分量分析:搜索图像中连贯的像素组。
第一步创建连贯区域,使用扩张形态学算子,膨胀让图像元素更厚。
首先创建形态学3x3交叉内核,以上内核应用5次膨胀,将所有字母粘合在一起。
第二步识别段落块,执行连通组件分析查找与段落对应的块。
检索外部轮廓并使用简单近似。
第三步确定每个轮廓的最小旋转边界矩形。
矩形宽高小于20个像素丢弃,宽高比小于2,同时需要考虑旋转的边界框。

vector<RotatedRect> findTextAreas(Mat input) {
	auto kernel = getStructuringElement(MORPH_CROSS, Size(3,3));
	Mat dilated;
	dilate(input, dilated, kernel, cv::Point(-1, -1), 5);

	vector<vector<Point>> contours;
	findContours(dilated, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	
	vector<RotatedRect> areas;
	for (const auto& contour : contours) 
	{	
		auto box = minAreaRect(contour);
		if (box.size.width < 20 || box.size.height < 20)
			continue;
		double proportion = box.angle < -45.0 ?
			box.size.height / box.size.width : 
			box.size.width / box.size.height;
		if (proportion < 2) 
			continue;
		areas.push_back(box);
	}
	return areas;
}

2,使用分类器搜索以前训练过的字母纹理图案:对诸如Haralick特征等纹理特征,经常使用小波变换。下一篇介绍。

三,文本提取和偏斜调整

Mat deskewAndCrop(Mat input, const RotatedRect& box)
{
	double angle = box.angle;	
	auto size = box.size;

	//Adjust the box angle
   if (angle < -45.0) 
	{
        angle += 90.0;
        std::swap(size.width, size.height);		
	}
	
	//Rotate the text according to the angle
	auto transform = getRotationMatrix2D(box.center, angle, 1.0);
	Mat rotated;
	warpAffine(input, rotated, transform, input.size(), INTER_CUBIC);

	//Crop the result
	Mat cropped;
	getRectSubPix(rotated, size, box.center, cropped);
	copyMakeBorder(cropped,cropped,10,10,10,10,BORDER_CONSTANT,Scalar(0));
	return cropped;
}

角度小于-45度时文本垂直,旋转角度增加90度,切换宽度和高度。

//描述旋转的2D仿射变换矩阵
Mat getRotationMatrix2D( Point2f center, double angle, double scale );
//旋转自身
void warpAffine( InputArray src, OutputArray dst,
                              InputArray M, Size dsize,
                              int flags = INTER_LINEAR,
                              int borderMode = BORDER_CONSTANT,
                              const Scalar& borderValue = Scalar());

flags表示图像应如何插值,BICUBIC_INTERPOLATION提高质量,默认值为LINEAR_INTERPOLATION。
borderMode边框模式。
Scalar边框颜色。

//裁剪边界框的矩形区域
void getRectSubPix( InputArray image, Size patchSize,
                                 Point2f center, OutputArray patch, int patchType = -1 );
//图像周围添加边框
void copyMakeBorder(InputArray src, OutputArray dst,
                                 int top, int bottom, int left, int right,
                                 int borderType, const Scalar& value = Scalar() );

分类阶段需要在文本周围留出边缘。
整体调用

int main(int argc, char* argv[])
{
	auto ticket = binarize(imread("ticket.png"));
	auto regions = findTextAreas(ticket);

	int count = 0;
	for (const auto& region : regions) {
		auto cropped = deskewAndCrop(ticket, region);
		stringstream ss;
		ss << "Cropped text " << count++;
		imshow(ss.str(), cropped);
	}
	waitKey(0);
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值