【问题标题】:How can I remove these parallel lines noise on my image using opencv如何使用 opencv 去除图像上的这些平行线噪声
【发布时间】:2021-02-15 19:51:14
【问题描述】:

我是 opencv 的新手,我正在尝试删除所有这些对角平行线,它们在我的图像中是噪声。

在经过一些侵蚀/膨胀后,我尝试使用 HoughLinesP,但结果是便便(并且只保留了接近 135 度角的那个)。

    img = cv2.imread('images/dungeon.jpg')
    ret,img = cv2.threshold(img,180,255,0)

    element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
    eroded = cv2.erode(img,element)
    dilate = cv2.dilate(eroded, element)
    skeleton = cv2.subtract(img, dilate)
    gray = cv2.cvtColor(skeleton,cv2.COLOR_BGR2GRAY)

    minLineLength = 10

    lines = cv2.HoughLinesP(gray, 1, np.pi/180, 1, 10, 0.5)

    for line in lines:
        for x1,y1,x2,y2 in line:
            angle = math.atan2(y2-y1,x2-x1)
            if (angle > -0.1 and angle < 0.1):
                cv2.line(img,(x1,y1),(x2,y2),(0,255,0),1)


    cv2.imshow("result", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

我的想法是检测这些线条以便之后将其删除,但我什至不确定这是执行此操作的好方法。

【问题讨论】:

  • 您可以计算线条的角度/斜率并过滤它们(固定角度范围或可用角度和/或长度的直方图)。

标签: python opencv


【解决方案1】:

我猜你正试图获得墙壁的contours,对吧?这是主要使用空间过滤的解决方案的可能路径。您仍然需要清理结果才能到达您想要的位置。这个想法是尝试计算图像的平行线(高频噪声)的掩码,并计算(二进制)输入与此掩码之间的差异。这些是步骤:

  1. 将输入图像转换为灰度
  2. 应用高斯模糊来消除您试图消除的高频噪声
  3. 获取模糊图像的二值图像
  4. 应用区域过滤器去除所有非噪声,以获得噪声掩码
  5. 计算原始二进制掩码和噪声掩码之间的差异
  6. 清理差异图像
  7. 计算此图像的轮廓

让我们看看代码:

import cv2
import numpy as np

# Set image path
path = "C://opencvImages//"
fileName = "map.png"

# Read Input image
inputImage = cv2.imread(path+fileName)

# Convert BGR to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)

# Apply Gaussian Blur:
blurredImage = cv2.GaussianBlur(grayscaleImage, (3, 3), cv2.BORDER_DEFAULT)

# Threshold via Otsu:
_, binaryImage = cv2.threshold(blurredImage, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Save a copy of the binary mask
binaryCopy = cv2.cvtColor(binaryImage, cv2.COLOR_GRAY2BGR)

这是输出:

到目前为止,您已经得到了这个二进制掩码。到目前为止,该过程已经平滑了噪声,并在噪声所在的位置产生了厚厚的黑色斑点。同样,这个想法是生成一个可以减去该图像的噪声掩码。

让我们应用area filter 并尝试移除大的白色斑点,它们不是我们有兴趣保留的噪声。我将在最后定义函数,现在我只想介绍一个总体思路:

# Set the minimum pixels for the area filter:
minArea = 50000

# Perform an area filter on the binary blobs:
filteredImage = areaFilter(minArea, binaryImage)

过滤器将抑制高于最小阈值的每个白色斑点。值很大,因为在这种特殊情况下,我们只对保留黑色斑点感兴趣。结果如下:

我们有一个非常坚固的面具。让我们从我们之前创建的原始二进制掩码中减去它:

# Get the difference between the binary image and the mask:
imgDifference = binaryImage - filteredImage

这是我们得到的:

差异图像有一些小噪点。让我们再次应用area filter 来摆脱它。这次使用更传统的阈值:

# Set the minimum pixels for the area filter:
minArea = 20

# Perform an area filter on the binary blobs:
filteredImage = areaFilter(minArea, imgDifference)

酷。这是最终的面具:

只是为了完整性。让我们在这个输入上计算contours,这非常简单:

# Find the big contours/blobs on the filtered image:
contours, hierarchy = cv2.findContours(filteredImage, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

# Draw the contours on the mask image:
cv2.drawContours(binaryCopy, contours, -1, (0, 255, 0), 3)

让我们看看结果:

如您所见,它并不完美。但是,还有一些改进的空间,也许您可​​以对这个想法进行更多的改进以获得潜在的解决方案。下面是areaFilter函数的定义和实现:

def areaFilter(minArea, inputImage):

    # Perform an area filter on the binary blobs:
    componentsNumber, labeledImage, componentStats, componentCentroids = \
    cv2.connectedComponentsWithStats(inputImage, connectivity=4)

    # Get the indices/labels of the remaining components based on the area stat
    # (skip the background component at index 0)
    remainingComponentLabels = [i for i in range(1, componentsNumber) if componentStats[i][4] >= minArea]

    # Filter the labeled pixels based on the remaining labels,
    # assign pixel intensity to 255 (uint8) for the remaining pixels
    filteredImage = np.where(np.isin(labeledImage, remainingComponentLabels) == True, 255, 0).astype('uint8')

    return filteredImage

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 2021-09-05
    相关资源
    最近更新 更多