Как получить расширенный или сжатый контур в OpenCV? - PullRequest
1 голос
/ 27 марта 2019

Можно ли получить расширенную или сокращенную версию контура?

Например, на изображении ниже я использовал cv :: findContour () и cv :: drawContour для двоичного изображения, чтобы получить контуры:

Imgur

Я хотел бы нарисовать другой контур, который имеет обычное расстояние в пикселях от исходного контура, например:

Imgur

Imgur

За исключением размытия, которое, я думаю, может оказаться не очень хорошей идеей, так как с помощью размытия трудно контролировать расстояние в пикселях, я понятия не имею, как решить эту проблему. Могу ли я узнать, какое направление должно быть правильным?

Ответы [ 2 ]

2 голосов
/ 27 марта 2019

Использование 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)

10 итераций с cv.MORPH_RECT с ядром 3x3:

MORPH_RECT

10 итераций с cv.MORPH_CROSS с ядром 3x3:

MORPH_CROSS

Вы можете изменить смещение, отрегулировав количество итераций.

Гораздо более точный подход - использовать cv:: distanceTransform, чтобы найти все пиксели, которые находятся примерно в 10 пикселях от контура:

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

You 'Я получу два контура на каждой стороне исходного контура.Используйте findContours с RETR_EXTERNAL, чтобы восстановить только внешний контур.Чтобы также восстановить внутренний контур, используйте RETR_LIST

0 голосов
/ 27 марта 2019

Я думаю, что решение может быть проще, без расширения и новых контуров.

  1. Для каждого центра масс поиска контура: cv :: моменты (контуры [i]) -> cv:: Point2f mc (mu.m10 / mu.m00), mu.m01 / mu.m00));

  2. Для каждой точки контура: сделать сдвиг для центра масс -> умножитьпо коэффициенту K -> сдвиг назад: pt_new = (k * (pt - mc) + mc);

Но коэффициент k должен быть индивидуальным для каждой точки.Я вычислю это чуть позже ...

...