【问题标题】:Contour Identification using OpenCV使用 OpenCV 进行轮廓识别
【发布时间】:2019-03-15 05:01:26
【问题描述】:

我有图像中的对象集合。 检查示例输入图像here

我想找到每个对象的轮廓。 我正在按照以下方法使用 OpenCV2

识别轮廓
gray = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
edged = cv2.Canny(gray, 50, 100)
dilate= cv2.dilate(edged, None, iterations=1)
erode= cv2.erode(dilate, None, iterations=1)
cnts = cv2.findContours(erode, cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)

这是我为上述代码得到的轮廓输出:see output image

有没有更好的方法来识别图像中的对象?

【问题讨论】:

  • 您可以尝试superpixel segmentation 并选择具有colour histogram 类似于苹果“确定内部”的超像素,并拒绝具有类似于苹果“确定外部”的超像素,您可以大致检测到进行一些预处理和阈值处理。自动方式是GrabCut algorithm。为了获得更好的质量,请搜索用于对象语义分割的神经网络。
  • 例如,在我早期的一个项目中,我编写了一个应用程序,我可以通过鼠标手动选择/取消选择超像素来修复不正确的超像素分割,并保存生成的二进制掩码。在我有大约一百个真实示例(图像和二进制掩码)之后,我以图像作为输入和掩码作为输出训练了 pip2pix 神经网络

标签: python opencv computer-vision opencv-contour


【解决方案1】:

您在代码 sn-p 中错过了一个简单的步骤,cv2.findContours() 在二进制图像上效果最好,但您只是将灰度图像传递给cv2.findContours。我按照以下步骤从背景中分割出苹果:

第一步:分割出主要包含灰度像素的背景。

您可以在此处使用 HSV 颜色域,其中低饱和度值会将背景分割为:

img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV_FULL)

# Filter out low saturation values, which means gray-scale pixels(majorly in background)
bgd_mask = cv2.inRange(img_hsv, np.array([0, 0, 0]), np.array([255, 30, 255]))

第 2 步:对于漆黑的像素,饱和度值是突然的,所以我们分割了极端的黑色和白色像素:

# Get a mask for pitch black pixel values
black_pixels_mask = cv2.inRange(img_bgr, np.array([0, 0, 0]), np.array([70, 70, 70]))

# Get the mask for extreme white pixels.
white_pixels_mask = cv2.inRange(img_bgr, np.array([230, 230, 230]), np.array([255, 255, 255]))

第 3 步:合并这些掩码以获得 cv2.findContours 的最终掩码:

final_mask = cv2.max(bgd_mask, black_pixels_mask)
final_mask = cv2.min(final_mask, ~white_pixels_mask)
final_mask = ~final_mask

第 4 步:现在要填充孔洞,我们对图像进行腐蚀和膨胀:

final_mask = cv2.erode(final_mask, np.ones((3, 3), dtype=np.uint8))
final_mask = cv2.dilate(final_mask, np.ones((5, 5), dtype=np.uint8))

第 5 步:使用cv2.findContours() 获取轮廓并在区域上对其进行过滤以去除较小的轮廓:

# Now you can finally find contours.
im, contours, hierarchy = cv2.findContours(final_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

final_contours = []
for contour in contours:
    area = cv2.contourArea(contour)
    if area > 2000:
        final_contours.append(contour)

第 6 步:显示最终轮廓

这里是完整的代码sn-p:

import cv2
import numpy as np

img_bgr = cv2.imread("/home/anmol/Downloads/tWuTW.jpg")
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV_FULL)

# Filter out low saturation values, which means gray-scale pixels(majorly in background)
bgd_mask = cv2.inRange(img_hsv, np.array([0, 0, 0]), np.array([255, 30, 255]))

# Get a mask for pitch black pixel values
black_pixels_mask = cv2.inRange(img_bgr, np.array([0, 0, 0]), np.array([70, 70, 70]))

# Get the mask for extreme white pixels.
white_pixels_mask = cv2.inRange(img_bgr, np.array([230, 230, 230]), np.array([255, 255, 255]))

final_mask = cv2.max(bgd_mask, black_pixels_mask)
final_mask = cv2.min(final_mask, ~white_pixels_mask)
final_mask = ~final_mask

final_mask = cv2.erode(final_mask, np.ones((3, 3), dtype=np.uint8))
final_mask = cv2.dilate(final_mask, np.ones((5, 5), dtype=np.uint8))

# Now you can finally find contours.
im, contours, hierarchy = cv2.findContours(final_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

final_contours = []
for contour in contours:
    area = cv2.contourArea(contour)
    if area > 2000:
        final_contours.append(contour)


for i in xrange(len(final_contours)):
    img_bgr = cv2.drawContours(img_bgr, final_contours, i, np.array([50, 250, 50]), 4)


debug_img = img_bgr
debug_img = cv2.resize(debug_img, None, fx=0.3, fy=0.3)
cv2.imwrite("./out.png", debug_img)

【讨论】:

  • 感谢您的回答。我检查了另一张图像,但轮廓检测效果不佳。你能帮忙吗?对于参考检查输入和输出图像:imgur.com/a/jG4Wb4r
  • 我刚刚为您提供了一个起点,显然您需要尝试许多不同的图像才能获得此脚本的一些通用值,我只调整了给定图像的值。您可以从此处获取概念并根据需要调整值。主要内容是:由于您的背景是黑色的,因此请先尝试将其分割出来,而不是分割苹果。您也可以尝试使用其他颜色域,例如 YCrCb、LAB 等。
  • 感谢您的建议。我会尝试其他方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-15
  • 1970-01-01
  • 2012-11-09
  • 2012-07-12
  • 1970-01-01
  • 2016-03-27
  • 2011-09-13
相关资源
最近更新 更多