OpenCV实现基于傅里叶变换的旋转文本校订

代码html

        先给出代码,再详细解释一下过程:ios

 


过程
读取图片git

 

        srcImg.empty()用来判断是否成功读进图像,若是srcImg中没有数据,在后面的步骤会产生内存错误。
        因为处理的是文本,彩色信息不会提供额外帮助,因此要用CV_LOAD_IMAGE_GRAYSCALE代表以灰度形式读进图像。
        假定读取的图像以下:github

english-rotation

旋转原图像(可选)算法

 

        若是手头没有这样的倾斜图像,能够选择一张正放的文本图像,再把第12行#define DEGREE那行前的注释符号去掉。而后这部分代码就会把所给的图像旋转你规定的角度,再交给后面处理。app

图像延扩ide

 

        OpenCV中的DFT采用的是快速算法,这种算法要求图像的尺寸是二、3和5的倍数时处理速度最快。因此须要用getOptimalDFTSize()找到最适合的尺寸,而后用copyMakeBorder()填充多余的部分。这里是让原图像和扩大的图像左上角对齐。填充的颜色若是是纯色对变换结果的影响不会很大,后面寻找倾斜线的过程又会彻底忽略这一点影响。函数

DFT测试

 

        DFT要分别计算实部和虚部,把要处理的图像做为输入的实部、一个全零的图像做为输入的虚部。dft()输入和输出应该分别为单张图像,因此要先用merge()把实虚部图像合并,分别处于图像comImg的两个通道内。计算获得的实虚部仍然保存在comImg的两个通道内。ui

得到DFT图像

 

        通常都会用幅度图像来表示图像傅里叶的变换结果(傅里叶谱)。
        幅度的计算公式:magnitude = sqrt(Re(DFT)^2 + Im(DFT)^2)。
        因为幅度的变化范围很大,而通常图像亮度范围只有[0,255],容易形成一大片漆黑,只有几个点很亮。因此要用log函数把数值的范围缩小。

 

        dft()直接得到的结果中,低频部分位于四角,高频部分位于中间。习惯上会把图像作四等份,互相对调,使低频部分位于图像中心,也就是让频域原点位于中心。

 

fft-mag

        虽然用log()缩小了数据范围,但仍然不能保证数值都落在[0,255]以内,因此要先用normalize()规范化到[0,1]内,再用convertTo()把小数映射到[0,255]内的整数。结果保存在一幅单通道图像内:

 

english-mag

Hough直线检测
        从傅里叶谱能够明显地看到一条过中心点的倾斜直线。要想求出这个倾斜角,首先要在图像上找出这条直线。
        一个很方便的方法是采用霍夫(Hough)变换检测直线。

 

        Hough变换要求输入图像是二值的,因此要用threshold()把图像二值化。
        二值化的一种结果:

english-binary

 

        这一部分用HoughLines()检测图像中可能存在的直线,并把直线参数保存在向量组lines中,而后绘制出找到的直线。
        两个参数GRAY_THRESH和HOUGH_VOTE须要手动指定,不一样的图像须要设置不一样的参数,同一段文本旋转不一样的角度也须要不一样的参数。GRAY_THRESH越大,二值化的阈值就越高;HOUGH_VOTE越大,霍夫检测的投票数就越高(须要更多的共线点来肯定一条直线)。说白了,若是发现二值化图像中直线附近有不少散点,就要适当提升GRAY_THRESH;若是发现从二值图像的一条直线上检测到了几条角度相差很小的直线,就须要适当提升HOUGH_VOTE。咱们但愿获得的结果时恰好检测到三条直线(有时只能检测到一条直线,后面会给出一个例子)。
        检测到的直线:

english-line

计算倾斜角
        上面获得了三个角度,一个是0度,一个是90度,另外一个就是咱们所须要的倾斜角。要把这个角找出来,并且要考虑偏差。

 

        因为DFT的特色,只有输入图像是正方形时,检测到的角才是文本真正旋转的角度。但咱们的输入图像不必定是正方形的,因此要根据图像的长宽比改变这个角度。
        还有一个须要注意的细节,虽然HoughLines()输出的倾斜角在[0,180)之间,但在[0,90]和(90,180)之间这个角的含义是不一样的。请看图示:

 

hough-transformation

        当倾斜角大于90度时,(180-倾斜角)才是直线相对竖直方向的偏离角度。在OpenCV中,逆时针旋转,角度为正。要把图像转回去,这个角度就变成了(倾斜角-180)。
校订图像
        最后一步,固然是把图像转回去

 

 

        先用getRotationMatrix2D()得到一个2*3的仿射变换矩阵,再把这个矩阵输入warpAffine(),作一个单纯旋转的仿射变换。warpAffine()的最后一个参数Scalar(255,255,255)是把因为旋转产生的空白用白色填充。
        校订的结果:

english-correction


一个检测单条直线的例子
原始图像:

single-english-rotation

傅里叶谱:

single-english-mag

        只有一条明显的直线。还好仅有的这条直线正是咱们所须要的。
检测直线:

single-english-line

校订结果:

single-english-correction


对中文的效果
        咱们来试试看这段程序对中文的校订效果。
输入图像:

chinese-rotation

傅里叶谱:

chinese-mag

        能够发现有许多条平行的亮线,其中过频域原点的那条长度最长,最容易检测出来。
检测直线:

chinese-line

校订结果:

chinese-correction

        虽然中文和英文在文字上有很大的不一样,但字母(或者文字)的高度比较一致,使得行与行之间的分隔很明显。因此它们的频域特征是类似的。


对其余语言文字的效果
        我从IMDB.com摘取影片《教父》的英文介绍,而后用谷歌翻译成其余文字进行测试。
阿拉伯语

arabic-rotation

arabic-mag

arabic-line

一枚反例
老挝语:

lao-rotation

傅里叶谱:

lao-mag

一种二值化的结果:

lao-binary

直线检测:

lao-line

        这种文字的不少字母的上下方多了不少“笔画”(我不知道该怎么称呼那些小曲线),让行与行之间的分离变得不明显,使得频域特征变得不明显。
        虽然用肉眼能够看出傅里叶谱中存在一条倾斜的直线,但它的亮度过低,二值化过程很难排除噪声,致使直线检测会首先检出噪声产生的直线。这也是个人程序目前受限之处。须要增长一个过滤散点噪声的步骤以增长程序的适用范围。


参考:Discrete Fourier Transform — OpenCV 2.4.7.0 documentation

代码还能够在这里下载:https://github.com/johnhany/textRotCorrect

原文:http://johnhany.net/2013/11/dft-based-text-rotation-correction/

相关文章
相关标签/搜索