OpenCV - 去除图像中的噪点

时间:2017-02-16 11:15:43

标签: c++ opencv image-processing noise-reduction

我在这里有一张桌子的图像..在右边的列中,背景充满了噪音

如何检测有噪音的区域?我只想对有噪声的部件应用某种滤波器,因为我需要对它进行OCR,任何类型的滤波器都会降低整体识别度

哪种滤镜最适合去除图像中的背景噪音?

如上所述我需要在图像上进行OCR

enter image description here

9 个答案:

答案 0 :(得分:9)

我在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建议的那样,内核为3的medianBlur也能很好地工作。

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 希望它有所帮助!

答案 1 :(得分:8)

我的解决方案是基于阈值处理,以4个步骤获得结果图像。

  1. OpenCV 3.2.0阅读图片。
  2. 应用GaussianBlur()以平滑图像,尤其是灰色区域。
  3. 屏蔽图像以将文本更改为白色,其余为黑色。
  4. 将蒙面图像反转为白色黑色文字。
  5. 代码位于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

答案 2 :(得分:3)

据我所知,中值滤波器是降低噪声的最佳解决方案。我建议使用3x3窗口的中值滤波器。见功能cv::medianBlur()

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

另外我建议尝试使用一对函数(cv :: erode()和cv :: dilate())。但我并不害羞,它最好解决cv :: medianBlur()窗口3x3。

答案 3 :(得分:2)

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

如果您打算将OCR应用于图像。我会告诉你以下内容:

  1. 使用中位数滤镜过滤图像。
  2. 在过滤后的图片中查找轮廓,您将只获得文字轮廓(称为 F )。
  3. 在原始图像中查找轮廓(将其称为 O )。
  4. 隔离 O 中与 F 中的任何轮廓相交的所有轮廓。
  5. 更快的解决方案:

    1. 在原始图像中查找轮廓。
    2. 根据尺寸过滤它们。

答案 4 :(得分:2)

结果:

enter image description here

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

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

要使用的函数是connectedComponentWithStats(在您可能需要生成负图像之前,threshold函数THRESH_BINARY_INV在这种情况下会起作用),绘制白色矩形小找到连接的组件。

实际上,此方法可用于查找字符,定义为给定最小和最大大小的连接组件,以及给定范围内的宽高比。

答案 7 :(得分:1)

我已经面临同样的问题并获得了最佳解决方案。 将源图像转换为灰度图像并应用 fastNlMeanDenoising 功能,然后应用阈值

像这样 - fastNlMeansDenoising(灰色,dst,3.0,21,7);             阈值(DST,finaldst,150255,THRESH_BINARY);

还可以根据您的背景噪点图像调整阈值。 eg- 阈值(dst,finaldst,200,255,THRESH_BINARY);

注意 - 如果您的列线被删除了......您可以从源图像中获取列线的掩码,并可以使用AND,OR,XOR等BITWISE操作应用于去噪的结果图像。

答案 8 :(得分:-2)

尝试对此图像进行阈值处理。确保您的src处于灰度级。该方法仅保留150到255强度之间的像素。

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

您可能想要在尝试否定灰色像素时反转图像。操作后,再次将其反转以获得所需的结果。