如何使用opencv去除图像上的这些平行线噪声

2024-04-18 20:46:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我是opencv的新手,我正在尝试去除图像中的所有这些对角线平行线。 enter image description here

在一些侵蚀/膨胀之后,我尝试过使用HoughLinesP,但结果是poo(并且只保持接近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()

enter image description here

我在这里的想法是检测这些线,以便在以后删除它们,但我甚至不确定这是一个好方法


Tags: imglineelementcv2skeletonlinesx1x2
1条回答
网友
1楼 · 发布于 2024-04-18 20:46:23

我猜你是想弄到墙上的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

相关问题 更多 >