简体   繁体   English

轮廓检测:减少图像 opencv/python 上的眩光

[英]contour detection: reduce glare on image opencv/python

I am working on contour detection for the image below, however due to the lightning condition, the detection is not complete where the image displays glares.我正在为下面的图像进行轮廓检测,但是由于闪电条件,在图像显示眩光的地方检测不完整。 I am trying to remove them in order to get a better contour detection.我正在尝试删除它们以获得更好的轮廓检测。

Here is the original image这是原始图像

有眩光的图像

And here is the grayed + thresholded image on which the cv2.connectedComponentsWithStats is ran to detect the objects.这是运行 cv2.connectedComponentsWithStats 以检测对象的灰色 + 阈值图像。 I have boxed the areas where I need to reduce exposure.我已将需要减少曝光的区域装箱。 (since I am using an inverse THRESH_BINARY_INV filter those areas appear black). (因为我使用的是反向 THRESH_BINARY_INV 过滤器,所以这些区域显示为黑色)。

灰色 + 阈值图像

As you can see hereafter the object detected areas are incomplete, the cv2.connectedComponentsWithStats will not detect the complete area for the object正如您在下文中看到的,object 检测到的区域不完整,cv2.connectedComponentsWithStats 不会检测到 object 的完整区域

对象区域

And then of course the contour itself which is calculated on the cropped outlined component is wrong as well:当然,在裁剪轮廓组件上计算的轮廓本身也是错误的:

裁剪轮廓

So of course the contour itself is wrong:所以当然轮廓本身是错误的:

由于眩光导致的错误轮廓

Here is what I have done so far:这是我到目前为止所做的:

def getFilteredContours(image, minAreaFilter=20000) -> np.array:
    ret = []
    ctrs,_ = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    ctrs = sorted(ctrs, key=cv2.contourArea, reverse=True)
    for i, c in enumerate(ctrs):
        # Calculate the area of each contour
        area = cv2.contourArea(c)
        if area < minAreaFilter:
            break
        ret.append(c)
    return ret

birdEye = cv2.imread(impath)

gray = cv2.cvtColor(birdEye, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
threshImg = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV)[1]
(numLabels, labels, stats, centroids) = cv2.connectedComponentsWithStats(
    threshImg, 4, cv2.CV_32S)

#then for each identified component we extract the component and get the contour

filteredIdx = getFilteredLabelIndex(stats)

for labelId in filteredLabelId:
    componentMask = (labels == i).astype("uint8") * 255
    ctrs, _ = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    ctrs = sorted(ctrs, key=cv2.contourArea, reverse=True)
    ctr = max(ctrs, key=cv2.contourArea)    
    cv2.drawContours(birdEye, [cntrs], -1, (255, 0, 255), 3)

cv2.imshow("original contour", birdEye)

cv2.waitKey(0)
cv2.destroyAllWindows()

Any suggestions would be welcome,欢迎大家提出意见,

Thanks谢谢

Pat

You may use floodFill for filling the background first.您可以先使用floodFill填充背景。

cv2.floodFill gives good result applying your sample image. cv2.floodFill应用您的示例图像给出了很好的结果。
Result is good because the background is relatively homogenous.结果很好,因为背景相对均匀。
floodFill uses the color information, opposed to other algorithms that use only the brightness. floodFill使用颜色信息,与其他仅使用亮度的算法相反。
The background has a slight brightness gradient that "flood fill" algorithm handles well.背景有轻微的亮度梯度,“洪水填充”算法处理得很好。

You may use the following stages:您可以使用以下阶段:

  • Replace all (dark) values (below 10 for example) with 10 - avoiding issues where there are black pixels inside an object.将所有(暗)值(例如低于 10)替换为 10 - 避免 object 内部存在黑色像素的问题。
  • Use cv2.floodFill for filling the background with black color.使用cv2.floodFill用黑色填充背景。
    Use the top left corner as a "background" seed color (assume pixel [10,10] is not in an object).使用左上角作为“背景”种子颜色(假设像素 [10,10] 不在对象中)。
  • Convert to Grayscale.转换为灰度。
  • Apply threshold - convert all pixels above zero to 255.应用阈值 - 将所有高于零的像素转换为 255。
  • Use opening (morphological operation) for removing small outliers.使用开放(形态学操作)去除小的异常值。
  • Find contours.寻找轮廓。

Code sample:代码示例:

import cv2
import numpy as np

birdEye = cv2.imread(r"C:\Rotem\tools.jpg")

# Replace all (dark) values below 10 with 10 - avoiding issues where there are black pixels inside an object
birdEye = np.maximum(birdEye, 10)

foreground = birdEye.copy()

seed = (10, 10)  # Use the top left corner as a "background" seed color (assume pixel [10,10] is not in an object).

# Use floodFill for filling the background with black color
cv2.floodFill(foreground, None, seedPoint=seed, newVal=(0, 0, 0), loDiff=(5, 5, 5, 5), upDiff=(5, 5, 5, 5))

# Convert to Grayscale
gray = cv2.cvtColor(foreground, cv2.COLOR_BGR2GRAY)

# Apply threshold
thresh = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)[1]

# Use opening for removing small outliers
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)))

# Find contours
cntrs, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# Draw contours
cv2.drawContours(birdEye, cntrs, -1, (255, 0, 255), 3)

# Show images for testing
cv2.imshow('foreground', foreground)
cv2.imshow('gray', gray)
cv2.imshow('thresh', thresh)
cv2.imshow('birdEye', birdEye)

cv2.waitKey()
cv2.destroyAllWindows()

foreground : foreground
前景

birdEye output:鸟眼birdEye
鸟眼输出

My suggestion is using dilation and erosion function(or closing function) in cv2.我的建议是在 cv2 中使用膨胀和腐蚀函数(或关闭函数)。

If you use cv2.dilate function, white area is bigger than now.如果你使用cv2.dilate function,白色区域比现在大。

Conversely, if you use cv2.erode function, white area is smaller than now.相反,如果你使用cv2.erode function,白色区域比现在小。

This iteration remove noise of black area.此迭代去除黑色区域的噪声。

Closing function is dilation followed by erosion.关闭 function 是先膨胀后腐蚀。

See https://docs.opencv.org/master/d9/d61/tutorial_py_morphological_ops.html请参阅https://docs.opencv.org/master/d9/d61/tutorial_py_morphological_ops.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM