如何在OpenCV中获得扩大或缩小的轮廓?

时间:2019-03-27 09:54:48

标签: c++ opencv contour opencv-contour opencv-drawcontour

是否可以获取轮廓的展开或缩小版本?

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

Imgur

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

Imgur

Imgur

除了腐蚀(我认为这可能不是一个好主意,因为似乎很难使用腐蚀来控制像素距离),我不知道如何解决此问题。我可以知道正确的方向吗?

2 个答案:

答案 0 :(得分:1)

使用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);

演示:

# 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)

使用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)

distanceTransform bw distanceTransform

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

答案 1 :(得分:0)

我认为解决方案可能会更容易,而无需膨胀和新轮廓。

  1. 对于每个轮廓搜索质量中心:cv :: moments(contours [i])-> cv :: Point2f mc(mu.m10 / mu.m00),mu.m01 / mu.m00));

  2. 对于轮廓的每个点:进行质心偏移->乘以系数K->向后偏移:pt_new =(k *(pt-mc)+ mc);

但是系数k对于每个点都必须是独立的。我待会儿再计算...