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

轮廓检测:减少opencv/python图像上的眩光,python,opencv,image-processing,Python,Opencv,Image Processing,我正在为下面的图像进行轮廓检测,但是由于闪电条件,在图像显示眩光的地方检测不完整。我试图删除它们,以获得更好的轮廓检测 这是原始图像 这是灰度+阈值图像,在该图像上运行cv2.connectedComponentsWithStats来检测对象。我已经把我需要减少暴露的区域围起来了。(因为我使用的是反向阈值二元INV过滤器,所以这些区域显示为黑色) 如下文所示,检测到的对象区域不完整,cv2.connectedComponentsWithStats不会检测到对象的完整区域 当然,在裁剪轮廓组

我正在为下面的图像进行轮廓检测,但是由于闪电条件,在图像显示眩光的地方检测不完整。我试图删除它们,以获得更好的轮廓检测

这是原始图像

这是灰度+阈值图像,在该图像上运行cv2.connectedComponentsWithStats来检测对象。我已经把我需要减少暴露的区域围起来了。(因为我使用的是反向阈值二元INV过滤器,所以这些区域显示为黑色)

如下文所示,检测到的对象区域不完整,cv2.connectedComponentsWithStats不会检测到对象的完整区域

当然,在裁剪轮廓组件上计算的轮廓本身也是错误的:

因此,轮廓本身当然是错误的:

以下是我迄今为止所做的工作:

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()
def getFilteredContours(图像,minAreaFilter=20000)->np.array:
ret=[]
ctrs,=cv2.findContours(图像,cv2.RETR\u树,cv2.CHAIN\u近似值\u无)
ctrs=已排序(ctrs,键=cv2.1,反向=真)
对于枚举中的i、c(CTR):
#计算每个轮廓的面积
面积=cv2。轮廓面积(c)
如果面积<最小面积过滤器:
打破
ret.append(c)
回程网
birdEye=cv2.imread(impath)
灰色=cv2.CVT颜色(鸟瞰,cv2.COLOR\u BGR2GRAY)
灰色=cv2.高斯模糊(灰色,(5,5,0)
threshImg=cv2.阈值(灰色,180255,cv2.THRESH\u BINARY\u INV)[1]
(数字标签、标签、统计信息、质心)=cv2.connectedComponentsWithStats(
阈值,4,cv2.CV_32S)
#然后对每个识别出的分量进行提取,得到轮廓
filteredix=getFilteredLabelIndex(统计)
对于filteredLabelId中的labelId:
组件掩码=(标签==i).astype(“uint8”)*255
ctrs,=cv2.findContours(图像,cv2.RETR\u树,cv2.CHAIN\u近似值\u无)
ctrs=已排序(ctrs,键=cv2.1,反向=真)
ctr=最大值(ctrs,键=cv2.轮廓面积)
cv2.绘制等高线(birdEye,[cntrs],-1,(255,0255),3)
cv2.imshow(“原始轮廓”,birdEye)
cv2.等待键(0)
cv2.destroyAllWindows()
欢迎提出任何建议

谢谢


Pat

我的建议是在cv2中使用膨胀和侵蚀功能(或关闭功能)

如果使用
cv2.deflate
功能,白色区域比现在大

相反,如果使用
cv2.correase
功能,白色区域比现在小

此迭代消除了黑色区域的噪声

闭合功能是先膨胀后侵蚀

参见
https://docs.opencv.org/master/d9/d61/tutorial_py_morphological_ops.html

您可以先使用填充背景

cv2.floodFill
应用您的示例图像可获得良好的效果。
结果很好,因为背景相对均匀。
floodFill
使用颜色信息,而其他算法仅使用亮度。
背景有轻微的亮度梯度,“泛光填充”算法处理得很好

您可以使用以下阶段:

  • 将所有(暗)值(例如低于10)替换为10-避免对象内部存在黑色像素的问题
  • 使用
    cv2.floodFill
    填充黑色背景。
    使用左上角作为“背景”种子颜色(假设像素[10,10]不在对象中)
  • 转换为灰度
  • 应用阈值-将零以上的所有像素转换为255
  • 使用“打开”(形态学操作)删除小的异常值
  • 找到轮廓线
代码示例:

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()

前台:

birdEye
输出:

轮廓检测功能将二值图像作为输入。你知道如何获得二值图像吗?是的,我确实更新了我的问题。我建议你看看漫射光,这样你的图像可以减少眩光。这看起来很棒,有没有办法平滑轮廓?它们看起来有点粗糙。你的图像右边和下方的寄生虫轮廓怎么样,我能过滤掉吗?嗯,这里有些奇怪,我按原样运行了你的代码,我的前景图像看起来不是黑色的。你错过什么了吗?奇怪。。。有时发布的图像会被修改。尝试从您的帖子下载图像,并将其用作输入。原始图像中的寄生虫轮廓为黑色。我们可以把它裁剪出来,也可以遮盖它。平滑边缘可能是一项挑战。形态学手术可能会有所帮助