opencv 如何固定图像的颜色以获得更好的阈值分割效果?

9fkzdhlc  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(132)

我尝试使用下面的代码在下面的图像original image中设置手的阈值:

img = cv2.GaussianBlur(crop_img,(25,25),0)
    img_YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
    #skin color range for hsv color space 
    YCrCb_mask = cv2.inRange(img_YCrCb, (0, 135, 85), (255,180,135)) 
    YCrCb_mask = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_CLOSE, np.ones((3,3), np.uint8))
    thresh = cv2.morphologyEx(YCrCb_mask, cv2.MORPH_OPEN, np.ones((3,3), np.uint8))
    #morphological operation to close -in the vertical direction- the gaps due to accessories 
    morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 31)))

它在其余测试用例上运行良好,但在上图中给出了以下结果:thresholded image
如何更好地对图像进行阈值处理以阈值处理所有手指?或者如何检查不均匀的照明并修复它?

fjaof16o

fjaof16o1#

看起来你的方法在颜色接近黑色的地方失败了,因为它不能可靠地从黑色中提取色调。我注意到在那些区域使用边缘检测器效果更好。在这种情况下,我将尝试使用adaptiveThreshold。它本身不是边缘检测器,但它像边缘检测器一样工作,并能抵抗亮度变化。
首先模糊,获取模糊的灰度并对其进行自适应阈值设置:

blur = cv2.GaussianBlur(img, (25, 25), 0)
blur_gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
blur_adaptive = cv2.adaptiveThreshold(blur_gray, 255, 
    cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 51, 0)

正如你所看到的,它确实显示了边缘在哪里。你可能需要使用足够大的核来可靠地分离(在这个例子中是51)。唯一的问题是,它对开放空间中的噪声很敏感。
为了去除这些噪声,我们可以从边缘进行泛色填充,这也是为什么我们在自适应阈值化之前进行模糊处理,这样这些噪声或多或少是相关的。

flooded = blur_adaptive.copy()
for x in range(flooded.shape[1]):
    if flooded[0, x] == 0:
        break
cv2.floodFill(flooded, None, (x, 0), 255)
# invert flooded and make it bool
flooded = flooded < 255

虽然还有些噪音,但我们可以稍后再处理。现在让我们把你的面具和我们得到的合并起来。

img_YCrCb = cv2.cvtColor(blur, cv2.COLOR_BGR2YCrCb)
#skin color range for hsv color space 
YCrCb_mask = cv2.inRange(img_YCrCb, (0, 135, 85), (255,180,135))
# make YCrCb_mask bool
YCrCb_mask = YCrCb_mask > 0

combined = np.bitwise_or(YCrCb_mask, flooded)

不错。口罩可以互相弥补不足。我们可以通过消除小轮廓来清除残留的噪音。它也会填充封闭的空隙。

contours, _ = cv2.findContours(combined.astype(np.uint8), 
    cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
area_threshold = 200
large_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > area_threshold]
cleaned = np.zeros(combined.shape, dtype=np.uint8)
cv2.drawContours(cleaned,  large_contours, -1, 255, thickness=cv2.FILLED)

和morph-close来连接片段(如果有):

morph = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, 
    cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 31)))

这里还有一些工作要做,但看起来比以前好多了。

**警告!**自适应阈值处理(大内核)、形态学闭合(大内核)和轮廓检测对于大图像来说是昂贵的操作。有一些技术可以降低成本(比如在操作之前进行下采样),但它们超出了本文的范围。

编辑奖金内容:这是另一张图片,你张贴之前,由这个管道处理。

相关问题