python - 按比例向上/向外生长

标签 python opencv scale contour

我有一个小脚本 (GitHub) (基于 this answer )检测白色背景上的物体。该脚本工作正常并检测到对象。例如,这张图片:

original image

变成这样:

contours on image

然后我裁剪了 boundingRect(红色的)。

我将对这张图片做进一步的操作。例如,我将只裁剪轮廓而不是矩形裁剪。 (无论如何,这些都是需要面对的进一步问题。)

我现在想做的是扩大/扩大轮廓(绿色的)。我不确定在这种情况下规模和增长是否意味着同一件事,因为当我想到规模时,通常只有一个原点/ anchor 。随着增长,它是相对于边缘的。我想要这样的东西(在 Photoshop 中创建):

grow example

因此,在我检测到物体/找到轮廓之后,我想按某个值/比率增加它,这样我就有一些空间/像素可以修改,而不会影响物体。我该怎么做?

提到的脚本:

# drop an image on this script file
img_path = Path(sys.argv[1])

# open image with Pillow and convert it to RGB if the image is CMYK
img = Image.open(str(img_path))
if img.mode == "CMYK":
    img = ImageCms.profileToProfile(img, "Color Profiles\\USWebCoatedSWOP.icc", "Color Profiles\\sRGB_Color_Space_Profile.icm", outputMode="RGB")

img      = cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2BGR)
gray     = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)[1]
kernel   = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morphed  = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)
contours = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
contour  = sorted(contours, key=cv2.contourArea)[-1]

x, y, w, h = cv2.boundingRect(contour)

final = cv2.drawContours(img, contours, -1, (0,255,0), 2)
cv2.rectangle(final, (x,y), (x+w,y+h), (0,0,255), 2)

cv2.imshow("final", final)
cv2.waitKey(0)
cv2.destroyAllWindows()

此处张贴的图片已按比例缩小以保持问题简短。原始图像和脚本可以在提到的(第一段)GitHub 页面上找到。

最佳答案

感谢 HansHirse 的建议(使用形态学膨胀),我设法让它工作了。

img_path = Path(sys.argv[1])

def cmyk_to_rgb(cmyk_img):
    img = Image.open(cmyk_img)
    if img.mode == "CMYK":
        img = ImageCms.profileToProfile(img, "Color Profiles\\USWebCoatedSWOP.icc", "Color Profiles\\sRGB_Color_Space_Profile.icm", outputMode="RGB")
    return cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2BGR)

def cv_threshold(img, thresh=128, maxval=255, type=cv2.THRESH_BINARY):
    if len(img.shape) == 3:
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    threshed = cv2.threshold(img, thresh, maxval, type)[1]
    return threshed

def find_contours(img, to_gray=None):
    kernel   = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
    morphed  = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    contours = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    return contours[-2]

def mask_from_contours(ref_img, contours):
    mask = numpy.zeros(ref_img.shape, numpy.uint8)
    mask = cv2.drawContours(mask, contours, -1, (255,255,255), -1)
    return cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)

def dilate_mask(mask, kernel_size=10):
    kernel  = numpy.ones((kernel_size,kernel_size), numpy.uint8)
    dilated = cv2.dilate(mask, kernel, iterations=1)
    return dilated

def draw_contours(src_img, contours):
    canvas = cv2.drawContours(src_img.copy(), contours, -1, (0,255,0), 2)
    x, y, w, h = cv2.boundingRect(contours[-1])
    cv2.rectangle(canvas, (x,y), (x+w,y+h), (0,0,255), 2)
    return canvas

orig_img      = cmyk_to_rgb(str(img_path))
orig_threshed = cv_threshold(orig_img, 240, type=cv2.THRESH_BINARY_INV)
orig_contours = find_contours(orig_threshed)
orig_mask     = mask_from_contours(orig_img, orig_contours)
orig_output   = draw_contours(orig_img, orig_contours)

dilated_mask     = dilate_mask(orig_mask, 50)
dilated_contours = find_contours(dilated_mask)
dilated_output   = draw_contours(orig_img, dilated_contours)

cv2.imshow("orig_output", orig_output)
cv2.imshow("dilated_output", dilated_output)

cv2.waitKey(0)
cv2.destroyAllWindows()

我相信代码已经足够自解释了。示例输出:

outputs

可以在 show_dilated_contours.py 找到完整的脚本(再次)

更新
作为奖励,后来我想平滑轮廓。我遇到过这个 blog post其中作者讨论了如何平滑形状的边缘(在 Photoshop 中)。这个想法非常简单,也可以应用在 OpenCV 中来平滑轮廓。步骤是:

  1. 根据轮廓(或形状)创建蒙版
  2. 模糊蒙版
  3. 阈值模糊蒙版(现在,我们有一个比步骤 1 中的蒙版更平滑的蒙版)
  4. 在模糊 + 阈值图像上再次找到轮廓。由于蒙版/形状更平滑,我们将获得更平滑的轮廓。

示例代码和输出:

# ... continuing previos code

# pass 1
smooth_mask_blurred   = cv2.GaussianBlur(dilated_mask, (21,21), 0)
smooth_mask_threshed1 = cv_threshold(smooth_mask_blurred)

# pass 2
smooth_mask_blurred   = cv2.GaussianBlur(smooth_mask_threshed1, (21,21), 0)
smooth_mask_threshed2 = cv_threshold(smooth_mask_blurred)

# find contours from smoothened mask
smooth_mask_contours = find_contours(smooth_mask_threshed2)
# draw the contours on the original image
smooth_mask_output   = draw_contours(orig_img, smooth_mask_contours)

cv2.imshow("dilated_output", dilated_output)
cv2.imshow("smooth_mask_output", smooth_mask_output)

smoother output

完整代码在 show_smooth_contours.py .

关于python - 按比例向上/向外生长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55948254/

相关文章:

python - 带有 Python 错误的 OpenCV - binary_op 中的断言失败((mask.type()== CV_8UC1 || mask.type()== CV_8SC1))

javascript - 如何将 Canvas 的像素大小加倍?

python - AWS Lambda python 库函数错误

python - 为什么不同的字符串在 Python 中具有相同的 ID?

python - 无法从 Cloud9 python 应用程序连接到 MySQL 数据库(托管在 arvixe 中)

c# - EMGU CV 图像人脸识别

python - Pandas 中的日期滞后

c++ - 使用opencv跟踪多个人体头部

c# - 如何通过 rs232 与秤通信

sprite - 在 p5.js 中放大时 Sprite 模糊