如何在 OpenCV 中获得扩展或收缩的轮廓?

Kom*_*gcn 6 c++ opencv contour

是否可以获得轮廓的扩展或收缩版本?

例如,在下图中,我在二值图像上使用了 cv::findContour() 和 cv::drawContour 来获取轮廓:

伊姆古尔

我想绘制另一个轮廓,它与原始轮廓有自定义的像素距离,如下所示:

伊姆古尔

伊姆古尔

除了侵蚀之外,我认为这可能不是一个好主意,因为使用侵蚀似乎很难控制像素距离,我不知道如何解决这个问题。我可以知道正确的方向应该是什么吗?

Ste*_*nev 7

使用带有小内核和多次迭代的 cv::erode 可能足以满足您的需求,即使它并不精确。

C++代码:

cv::Mat img = ...;
int iterations = 10;
cv::erode(img, img,
   cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3)),
   cv::Point(-1,-1),
   iterations);
Run Code Online (Sandbox Code Playgroud)

演示:

# img is the image containing the original black contour
for form in [cv.MORPH_RECT, cv.MORPH_CROSS]:
    eroded = cv.erode(img, cv.getStructuringElement(form, (3,3)), iterations=10)
    contours, hierarchy = cv.findContours(~eroded, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
    cv.drawContours(vis, contours, 0, (0,0,255))
    cv.drawContours(vis, contours, 1, (255,0,0))
    show_image(vis)
Run Code Online (Sandbox Code Playgroud)

使用 3x3 内核的 cv.MORPH_RECT 进行 10 次迭代:

MORPH_RECT

使用 3x3 内核的 cv.MORPH_CROSS 进行 10 次迭代:

MORPH_CROSS

您可以通过调整迭代次数来更改偏移量。

更准确的方法是使用 cv::distanceTransform 来查找距离轮廓大约 10px 的所有像素:

dist = cv.distanceTransform(img, cv.DIST_L2, cv.DIST_MASK_PRECISE)
ring = cv.inRange(dist, 9.5, 10.5) # take all pixels at distance between 9.5px and 10.5px
show_image(ring)
contours, hierarchy = cv.findContours(ring, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

vis = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
cv.drawContours(vis, contours, 0, (0,0,255))
cv.drawContours(vis, contours, 2, (255,0,0))
show_image(vis)
Run Code Online (Sandbox Code Playgroud)

距离变换bw 距离变换

您将在原始轮廓的每一侧得到两个轮廓。将 findContours 与 RETR_EXTERNAL 结合使用可仅恢复外轮廓。要恢复内部轮廓,请使用 RETR_LIST