StevenKyleLee原创:http://blog.csdn.net/stevenkylelee/article/details/6973471
转载请注明
最近接到一个任务:去除图像中的噪点。
图片是从扫描仪扫描进来的,色彩只有黑白二值。因为是从书本上扫描,而书本上的纸张有背景色,
所以导致扫描的图片会出现一大片离散的噪点。为什么要去除噪点呢?因为噪点会干扰OCR程序对文字图片的识别。
一张有噪点的、扫描进来的黑白原图如下:
如何去除噪点呢?
观察了好一段时间,发现,凡是一个汉字的都是一大片相连的黑色像素。而噪点都是较小块的黑色像素。
是否可以通过判断黑色像素块的大小(相连的黑色像素数)来确定是一个汉字,还是一块噪点呢?
感觉这个方法应该可行,实现起来不算太难,也没涉及多少图像处理的算法和知识
于是乎,就试着动手吧。。。
先梳理一下思路:把整个位图(可看成是一个二维数组)认为是一个图(数据结构中的图的概念),
相邻的同色像素点之间有通路,用深度或广度优先搜索,取得所有的连通分量。
(类似水滴或染色算法,染色就是把曾经走过的路径着色标记起来,而我用hash表记录曾经走过的轨迹。)
如果连通分量的大小低于某个值,就认为它是一个离散的噪点,然后用背景色抹掉这个噪点。
当然,这样做是建立在“组成中文字的一个连通分量很大,而离散噪点通常很小”的假设上。
如何把一个位图看成是一个图呢?对于相邻的同色像素点,我想了2个规则。如下图:
目前来说我选择规则1,既是上下左右可能有通路,而斜边不存在通路
一个下午,程序就写出来了。效果还可以。上面扫描原图的大部分噪点都能去除了。
但对于一些字的边缘的毛刺 和 一些大块的只有小部分相连的噪点 还不能去除。
想了下,又多加了2个函数:我称之为:水平、垂直切割吧。
这2个函数的作用,就是从水平或者垂直方向尝试“切断”线段,有一个切割参数,表示可以切断的线段大小。
比如:切割大小为1,就是一条只有1像素粗细的垂直线段会被水平切割函数“切断”,
其实“切断”就是把被能切断的像素设置为背景色。
在执行判断连通分量大小去块的操作之前,先执行水平、垂直切割,
这样一些与字只有一个像素相连的噪点小块,就会被“切断”了。从而被下一步的判断连通分量的操作给去掉
上面扫描原图经过我的程序处理后的效果如下:
由于代码也不太短,所以,这里我就只分享下自己的思路了,
我的程序的源代码和一些样本图下载地址如下,还请不吝高手多多指教啊!(代码中也写了一个自己的腐蚀算法):
http://download.csdn.net/detail/stevenkylelee/3798884
我个人觉得在帖子中帖代码,还不如把整个源代码工程上传。
1.节省版面。2.方便别人调试、查看。