进行文字分割时,有多种方法,对与不同情况可以分别处理。
问题1:如何进行文字分割?
答:对于文字是一般正规(不同行的文字一样高,每一行内部文字大致一样宽)的文本的情况。
这里给出了一种方法。
1)对图像二值化
2)对二值化之后的图像进行水平方向投影(找到不同行)
3)利用2)得到的结果对二值化图像切割,然后对每一行进行垂直方向的投影(找到每一行内的不同文字)
4)利用 2)和3)得到的结果画出方框。
本文是与这里的方法对应的C++实现,在这里使用C#实现的。
本文尽量对所使用到的代码进行相近的解释。
- 先读取图片
Mat img = imread(IMG_PATH);
if (img.empty())
{
cerr<<"can not read image"<<endl;
}
imshow("original image", img);
显示结果:
- 第一步:1)对图像二值化
// step 1) 对图像二值化,这里因为使用 otsu 必须是单通道,
//所以先将图像变成 单通道的图像
Mat gray_img;
cvtColor(img,gray_img,CV_BGR2GRAY,1);
Mat binary_img;
threshold(gray_img,binary_img,90,255,THRESH_OTSU);
binary_img = 255 - binary_img;
imshow("binary image by otsu", binary_img);
- 第二步:step 2) 对二值化之后的图像进行水平方向投影(找到不同行)
Mat hist_ver;
reduce(binary_img/255,hist_ver,1,CV_REDUCE_SUM,CV_32S);
int width = 5;
int totaln = max(hist_ver.rows,hist_ver.cols);
Mat locations = Mat::zeros(3,totaln,CV_32S);
int count = 0;
Find_begin_end_len(hist_ver,locations,count,width);
问题:reduce()是什么意思呢?
答:reduce()是,将图像,沿着某个方向,做某种“降维”
这里的意思是,将图像沿着横轴做“求和”运算,最后得到的是一个一维向量。
问题:Find_begin_end_len()是什么鬼呢?
答:自己定义的一个函数,找到直方图中相连区域的开始与结束部分的位置。
问题:这个函数的想法是什么呢?
答:输入:一个表示直方图的向量h_vec;
输出:矩阵locations
第一行 | 第二行 | 第三行 |
---|---|---|
开始的位置 | 结束的位置 | 这一段不为零的直方图的长度 |
begin | end | len |
代码如下:
void Find_begin_end_len(Mat h_vec,Mat& locations,int& count, int width){
// locations 为 3*N 大小的 全零的 Mat,
// 经过这个函数处理之后