如何将轮廓扩大特定数量的像素(无需遍历每个像素)?
How to dilate a contour by a specific number of pixels (without iterating over every pixel)?
我正在编写一个 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()
这是输出图像:
这可能不是最干净的解决方案,但它很简单并且适用于所有形状。通过一些额外的工作,您也可以将其用于模板内的切口。所以这可能足以满足您的需求。
找到等高线,在其上画一条 2 倍钻头大小的白线。现在使用 impute 图像的反转版本作为掩码,只留下路由路径 - 就像在输出图像中一样。相反,您还可以组合图像以创建更大的白色形状(如您的问题所述)。
结果:
代码:
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()
我正在编写一个 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()
这是输出图像:
这可能不是最干净的解决方案,但它很简单并且适用于所有形状。通过一些额外的工作,您也可以将其用于模板内的切口。所以这可能足以满足您的需求。
找到等高线,在其上画一条 2 倍钻头大小的白线。现在使用 impute 图像的反转版本作为掩码,只留下路由路径 - 就像在输出图像中一样。相反,您还可以组合图像以创建更大的白色形状(如您的问题所述)。
结果:
代码:
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()