2017-02-16 271 views
18

噪音我在这里有一个图像与表。在右边的列中的背景充满了噪音OpenCV的 - 去除图像

如何与噪音检测领域?我只想在有噪音的部件上应用某种过滤器,因为我需要对其进行OCR,任何类型的过滤器都会降低总体识别度。

什么样的过滤器最适合去除背景噪音图片?

至于说我需要做OCR图像

enter image description here

+1

您可能想要删除您样本图像“个人”的信息。 – cwap

+1

你能告诉文档图像中的语言吗? – thewaywewere

+1

其丹麦..... – clarkk

回答

7

我在OpenCV中尝试了一些过滤器/操作,它似乎工作得很好。

第1步:扩张图像 -

kernel = np.ones((5, 5), np.uint8) 
cv2.dilate(img, kernel, iterations = 1) 

Dilated Image

正如你看到的,噪声消失,但角色很轻,所以我被侵蚀的形象。

第2步:侵蚀图像 -

kernel = np.ones((5, 5), np.uint8) 
cv2.erode(img, kernel, iterations = 1) 

Eroded dilated image

正如你所看到的,噪声却走了另列的一些字符被打破。我建议只在嘈杂的列上运行这些操作。您可能想要使用HoughLines来查找最后一列。然后,您只能提取该列,运行扩张+侵蚀并将其替换为原始图像中的相应列。 此外,扩张+侵蚀实际上是一种称为结束的操作。这个你可以直接调用使用 -

cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) 

由于@Ermlg建议,medianBlur以3内核还奇妙的作品。

cv2.medianBlur(img, 3) 

Median Blur

可供选择的步骤

正如你可以看到所有这些过滤器工作,但它是,如果你只在噪声是部分实现这些过滤器更好。要做到这一点,使用以下命令:

edges = cv2.Canny(img, 50, 150, apertureSize = 3) // img is gray here 
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, 1000, 50) // last two arguments are minimum line length and max gap between two lines respectively. 
for line in lines: 
    for x1, y1, x2, y2 in line: 
     print x1, y1 
// This gives the start coordinates for all the lines. You should take the x value which is between (0.75 * w, w) where w is the width of the entire image. This will give you essentially **(x1, y1) = (1896, 766)** 

然后,您可以提取这部分只喜欢:

extract = img[y1:h, x1:w] // w, h are width and height of the image 

Extracted image

然后,在此图像中实现滤波器(中位数或关闭) 。去除噪点后,您需要将此滤波图像替换为原始图像中的模糊部分。 图像[Y1:H,X1:W] =中值

这是C++直接:

extract.copyTo(img, new Rect(x1, y1, w - x1, h - y1)) 

最终结果与替代方法

Final Result 希望它能帮助!

+0

你有一个代码示例,可以用噪声检测的最后一列..像你说的你自己。无论你申请什么过滤器 - 文本将始终难以辨认。所以我只想与噪音 – clarkk

+1

适用于图像的部分过滤器是我做的,给我一段时间和我会将其添加到答案中。 –

+2

添加了检测最后一列的方法。让我知道它是否回答你的问题。 –

3

上据我所知中值滤波是降低噪音的最佳解决方案。我会建议使用3x3窗口的中值过滤器。请参阅功能cv::medianBlur()

但是在使用OCR同时使用任何噪音过滤时要小心。它可能导致识别准确度降低。

另外我会建议尝试使用一对函数(cv :: erode()和cv :: dilate())。但我不敢保证它会最好的解决方案,然后cv :: medianBlur()与窗口3x3。

+0

如果噪音过滤可能导致糟糕的OCR,你能检测到噪声所在的区域(如果有噪声),只能在那里使用滤波器? – clarkk

+0

@clarkk分离人物的噪音和精细结构并不容易。但在你的情况下,我认为这不是一个问题,因为与噪音相比字体足够大。 – ErmIg

2

我会去中位模糊(可能是5 * 5内核)。

如果您打算应用OCR图像。我会建议您以下几点:

  1. 使用中值滤波器过滤图像。
  2. 在已过滤的图像中查找轮廓,只会得到文本轮廓(称它们为F)。
  3. 在原始图像中找到轮廓(称它们为O)。
  4. O中的所有等高线与F中的任意等值线相交。

更快的解决方案:

  1. 找到原始图像中的轮廓。
  2. 根据尺寸对它们进行过滤。
-2

尝试像这样阈值化图像。确保你的src灰度。这种方法将只保留强度在150和255之间的像素。

threshold(src, output, 150, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 

当您试图取消灰色像素时,您可能想要反转图像。手术后,再次将其反转以获得您想要的结果。

+0

如果您在输入图像中的像素仔细看,你会看到,这里的输入已经是二值图像,与像素无论是在0或255 – Antonio

4

我的解决方案是基于阈值,以4个步骤得到结果图像。通过OpenCV 3.2.0

  1. 读取图像。
  2. 应用GaussianBlur()来平滑图像,尤其是灰色区域。
  3. 遮罩图像以将文本更改为白色,其余为黑色。
  4. 将蒙面图像翻转为白色的黑色文字。

该代码在Python 2.7。它可以很容易地更改为C++

import numpy as np 
import cv2 
import matplotlib.pyplot as plt 
%matplotlib inline 

# read Danish doc image 
img = cv2.imread('./imagesStackoverflow/danish_invoice.png') 

# apply GaussianBlur to smooth image 
blur = cv2.GaussianBlur(img,(5,3), 1) 

# threshhold gray region to white (255,255, 255) and sets the rest to black(0,0,0) 
mask=cv2.inRange(blur,(0,0,0),(150,150,150)) 

# invert the image to have text black-in-white 
res = 255 - mask 

plt.figure(1) 
plt.subplot(121), plt.imshow(img[:,:,::-1]), plt.title('original') 
plt.subplot(122), plt.imshow(blur, cmap='gray'), plt.title('blurred') 
plt.figure(2) 
plt.subplot(121), plt.imshow(mask, cmap='gray'), plt.title('masked') 
plt.subplot(122), plt.imshow(res, cmap='gray'), plt.title('result') 
plt.show() 

以下是通过代码绘制图片供参考。

enter image description here

这里是在2197 X 3218像素结果图像

enter image description here

+0

这仍然应用过滤器的整体形象上。我需要只用噪音 – clarkk

+0

@clarkk确定适用零件​​上的过滤器的解决方案。噪音区域是否固定并已知?像附加的样本图像一样?如果没有,还有更多的样本文件要显示? – thewaywewere

1

如果您非常担心去除可能会损害您的OCR检测像素。不添加人工制品,尽可能使其纯粹。然后你应该创建一个blob过滤器。并删除任何小于n像素左右的斑点。

不打算编写代码,但我知道这很好,因为我自己使用这个,虽然我不使用openCV(我写了我自己的多线程blobfilter超速的原因)。抱歉,但我不能在这里分享我的代码。只是描述如何去做。

1

如果处理时间不是问题,在这种情况下,一个非常有效的方法将计算所有黑色连通分量,并去除那些小于几个像素的分量。它会去除所有嘈杂的点(除了接触有效的组件),但保留所有字符和文档结构(线等)。

要使用的函数将是connectedComponentWithStats(在您可能需要生成负像之前,threshold函数将在此情况下起作用),绘制白色矩形,其中找到小的连接组件。实际上,这种方法可以用来查找字符,将字符定义为给定最小和最大尺寸的连通分量,并且在给定范围内具有纵横比。

+0

我之前消化了 – user3800527

+0

@ user3800527没错,我错过了。我的回答为opencv实现添加了一些提示。 – Antonio

0

我已经面临同样的问题,并得到了最好的解决方案。 将源图像转换为灰度图像并应用fastNIMeanDenoising函数然后应用阈值

这样 - fastNlMeansDenoising(gray,dst,3.0,21,7); 阈值(dst,finaldst,150,255,THRESH_BINARY);

也使用可以调整门槛accorsing你的背景噪音图像。 EG-阈值(DST,finaldst,200255,THRESH_BINARY);

注意 - 如果您的列线得到了删除...您可以采取的列线屏蔽来自源图像,并且可以适用于使用像AND,OR,XOR位操作去噪导致图像。