【问题标题】:How to dilate a contour by a specific number of pixels (without iterating over every pixel)?如何将轮廓扩大特定数量的像素(不迭代每个像素)?
【发布时间】:2020-03-17 18:25:33
【问题描述】:

我正在编写一个 Python 脚本,用于将图像转换为 CNC 机器的 G 代码。 CNC 机床使用直径为 0.250 英寸的圆柱形钻头。我的脚本在图像中找到轮廓,然后将轮廓中的坐标转换为机器的方向。

这很好用,除了雕刻的形状比设计的部分小 0.125 英寸。钻头的中心直接在轮廓上,因此生成的形状太小了钻头直径的一半。

我想将每个轮廓放大 x 个像素。我想制作一个输出图像,其中源图像中的每个白色像素在输出中也是白色的图像,而且输入图像中白色像素的 x 个像素内的每个像素在输出图像中都应该是白色的。

这是我的源图片:

使用cv2.dilate() 扩张轮廓不会产生我正在寻找的结果,因为它往往会使圆边变成正方形。

img = cv2.dilate(img, (15,15), 5)

我尝试逐个像素地遍历图像,然后使用cv2.pointPolygontest(contour, (x,y), True) 测试到轮廓的距离。这行得通,但这个 hack 很慢。

import cv2
import numpy as np

def erode_contours_by_cutter_size(img, contours, cutter_size):
    # Create an output image
    outputImage = np.zeros_like(img)
    # Iterate through every pixel in the image
    for x in range(img.shape[0]):
        for y in range(img.shape[1]):
            # Check if the pixel is black
            if img[y,x] != 255:
                # Check if the distance from this pixel to a contour is smaller than the cutter size
                for contour in contours:
                    dist = cv2.pointPolygonTest(contour, (x,y), True)                    
                    if abs(dist) < cutter_size:
                        outputImage[y,x] = 255
    return outputImage

img = 255-cv2.imread('/home/stephen/Desktop/t2.png',0)
img = cv2.resize(img, (234,234))
cutter_size = 50
contours, _ = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
img = erode_contours_by_cutter_size(img, contours, cutter_size)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

这是输出图像:

【问题讨论】:

  • 尝试 distanceTransform 和阈值
  • 在这里支持nathancy的想法,试试吧!但是,还有另一个问题:您使用哪个 OpenCV 版本,img = cv2.dilate(img, 15, 5) 有效?第二个参数是默认的膨胀核(结构元素)。我检查了 OpenCV 4.x、3.4.x 和 2.4.x 上的文档,但似乎没有一个允许该代码。
  • @HansHirse 我使用的是 OpenCV 版本 '4.1.1',抱歉那行代码有错误。我在编辑中修复了它。

标签: python opencv contour


【解决方案1】:

这可能不是最干净的解决方案,但它很简单,适用于所有形状。通过一些额外的工作,您也可以将其用于模板内的切口。因此,它可能足以满足您的需求。

找到轮廓,在上面画一条白线,是钻头大小的 2 倍。现在使用插补图像的反转版本作为掩码,只留下路由路径 - 就像在输出图像中一样。相反,您还可以组合图像以创建更大的白色形状(如您的问题所述)。

结果:

代码:

import cv2
import numpy as np

bitsize = 100
# load image
img = cv2.imread('PluT1.png',0)
# create empty image
res = np.zeros(img.shape[:2], dtype=np.uint8)
# find countours. use a more complex CHAIN_APPROX if SIMPLE is not enough 
contours, hier = cv2.findContours(img,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# draw contour
for cnt in contours:
    cv2.drawContours(res,[cnt],0,(255),bitsize)

#invert input image to create mask
img_inverted = cv2.bitwise_not(img)
# apply mask to get routing path
path = cv2.bitwise_and(res,res, mask=img_inverted)
# join drawn contour and input image to get solid
solid = cv2.bitwise_or(img,res)
# show images
cv2.imshow('Input',img)
cv2.imshow('Path',path)
cv2.imshow('Solid',solid)
cv2.waitKey(0)
cv2.destroyAllWindows()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-30
    • 1970-01-01
    相关资源
    最近更新 更多