opencv как получить среднюю линию контура - PullRequest
1 голос
/ 26 марта 2020

У меня есть изображение, из которого я получаю контур использования findContours. Это выглядит примерно так: (показывая «внутренний и внешний контур»). enter image description here

Есть ли у меня способ получить «среднюю точку» этих двух контуры? ie какая-то полилиния, которая вписывается точно между двумя линиями, видимыми на изображении, так что расстояние в любой точке результирующего времени одинаково от нее до верхнего контура, как и от нее до нижнего контура?

Более сложный пример будет выглядеть следующим образом: enter image description here

Обратите внимание, что не имеет значения, что происходит на перекрестках, если ничего не прослеживается сам по себе, поэтому результат более сложного примера потребует нескольких строк.

1 Ответ

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

Есть способ получить "среднюю точку" двух контуров, но я не думаю, что существует существующее решение OpenCV.

Вы можете использовать следующие этапы:

  • Преобразование изображения в оттенки серого и применение двоичного порога.
    Вы можете использовать cvtColor(... COLOR_BGR2GRAY) и threshold(...) Функции OpenCV.
  • Заполните пиксели за пределами области между строками белым цветом.
    Вы можете использовать floodFill Функция OpenCV.
  • Применить «преобразование расстояния» к двоичному изображению.
    Вы можете использовать distanceTransform Функция OpenCV.
    Использовать CV_DIST_L2 для евклидова расстояния.
  • Примените алгоритм Дейкстры для нахождения кратчайших путей между большинством левого и самого правого узлов.
    Представление результата "преобразования расстояния" (изображения) в виде взвешенного графа и применение алгоритма Дейкстры является наиболее сложный этап.

Я реализовал решение в MATLAB.
Реализованный MATLAB используется в качестве «доказательства концепции».
Я знаю, что вы ожидали реализации C ++, но это требует большой работы ,

В реализации MATLAB используется функция im2graph, которую я скачал с здесь .

Вот реализация MATLAB:

origI = imread('two_contours.png'); % Read input image
I = rgb2gray(origI);  % Convert RGB to Grayscale.
BW = imbinarize(I); % Convert from Grayscale to binary image.

% Fill pixels outsize the area between lines.
BW2 = imfill(BW, ([1, size(I,2)/2; size(I,1), size(I,2)/2]));

% Apply "distance transform" (find compute euclidean distance from closest white pixel)
D = bwdist(BW2);

% Mark all pixels outsize the area between lines with zero.
D(BW2 == 1) = 0;

figure;imshow(D, []);impixelinfo % Display D matrix as image

[M, N] = size(D);

% Find starting point and end point - assume we need to find a path from left side to right side.
x0 = 1;
[~, y0] = max(D(:, x0));

x1 = N;
[~, y1] = max(D(:, x1));

% https://www.mathworks.com/matlabcentral/fileexchange/46088-dijkstra-lowest-cost-for-images
StartNode = y0;
EndNode = M*N - (M-y1-1);
conn = 8;%4 or 8 - connected neighborhood for linking pixels

% Use 100 - D, because graphshortestpath searches for minimum weight (and we are looking for maximum weight path).
CostMat = 100 - D;
G = im2graph(CostMat, conn);

%Find "shortest" path from StartNode to EndNode
[dist, path, pred] = graphshortestpath(G, StartNode, EndNode);

% Mark white path in image J image
J = origI;R = J(:,:,1);G = J(:,:,2);B = J(:,:,3);
R(path) = 255;G(path) = 255;B(path) = 255;
J = cat(3, R, G, B);
figure;imshow(J);impixelinfo % Display J image

Результат:

D - Результат преобразования расстояния:
enter image description here

J - Исходное изображение с "дорожкой", отмеченной белым цветом:
enter image description here


Обновление:

Для нового примера вы можете определить три пути.

Решение становится более сложным.
Пример не обобщен для решения всех случаев.

Должно быть более простое решение, я просто не могу придумать одно.

tmpI = imread('three_contours.png'); % Read input image
origI = permute(tmpI, [2, 1, 3]); % Transpose image
I = rgb2gray(origI);  % Convert RGB to Grayscale.
BW = imbinarize(I); % Convert from Grayscale to binary image.

% Fill pixels outsize the area between lines.
%BW2 = imfill(BW, ([1, size(I,2)/2; size(I,1), size(I,2)/2]));
BW2 = imfill(BW, ([1, 1; size(I,1), size(I,2); size(I,2)/2, 1]));

% Apply "distance transform" (find compute euclidean distance from closest white pixel)
D = bwdist(BW2);

% Mark all pixels outsize the area between lines with zero.
D(BW2 == 1) = 0;

figure;imshow(D, []);impixelinfo % Display D matrix as image

[M, N] = size(D);

% Find starting point and end point - assume we need to find a path from left side to right side.
x0 = 1;
[~, y0a] = max(D(1:M/2, x0));

% Y coordinate of second point
[~, y0b] = max(D(M/2:M, x0));
y0b = y0b + M/2;

x1 = N;
[~, y1] = max(D(:, x1));

% https://www.mathworks.com/matlabcentral/fileexchange/46088-dijkstra-lowest-cost-for-images
StartNodeA = y0a;
StartNodeB = y0b;
EndNode = M*N - (M-y1-1);
conn = 8;%4 or 8 - connected neighborhood for linking pixels

% Use 100 - D, because graphshortestpath searches for minimum weight (and we are looking for maximum weight path).
D(D==0) = -10000; % Increase the "cost" where D is zero
CostMat = 1000 - D;
G = im2graph(CostMat, conn);

%Find "shortest" path from StartNode to EndNode
[dist, pathA, pred] = graphshortestpath(G, StartNodeA, EndNode);

[dist, pathB, pred] = graphshortestpath(G, StartNodeB, EndNode);

[dist, pathC, pred] = graphshortestpath(G, StartNodeA, StartNodeB);

% Mark white path in image J image
J = origI;R = J(:,:,1);G = J(:,:,2);B = J(:,:,3);
R(pathA) = 255;
G(pathB) = 255;
B(pathC) = 255;
J = cat(3, R, G, B);
J = permute(J, [2, 1, 3]); % Transpose image
figure;imshow(J);impixelinfo % Display J image

Три строки:
enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...