Я пытаюсь реализовать алгоритм змеи для активного контура, используя C ++ и OpenCV 3. Я работаю с версией, которая использует градиентный спуск.В качестве базового теста я пытаюсь нарисовать контур губы.Это базовое изображение.
![This](https://i.stack.imgur.com/LvpvX.jpg)
Это эволюция контура без внешних сил (альфа = 0,001, бета = 3, размер шага =0.3).
![This](https://i.stack.imgur.com/Eps4f.png)
Когда я добавляю внешнюю силу, это результат.
![this](https://i.stack.imgur.com/oEK8N.png)
В качестве внешней силы я использовал только определение края с помощью производной Собеля.
![Sobel derivative](https://i.stack.imgur.com/oj3Lr.png)
Этот код я использую для точекобновление.
array<Mat, 2> edges = edgeMatrices(croppedImage);
const float ALPHA = 0.001, BETA = 3, GAMMA = 0.3, // Gamma is step size.
a = GAMMA * ALPHA, b = GAMMA * BETA;
const uint16_t CYCLES = 1000;
const float p = b, q = -a - 4 * b, r = 1 + 2 * a + 6 * b;
Mat pMatrix = pentadiagonalMatrix(POINTS_NUM, p, q, r).inv();
for (uint16_t i = 0; i < CYCLES; ++i) {
// Extract the x and y derivatives for current points.
auto externalForces = external(edges, x, y);
x = pMatrix * (x + GAMMA * externalForces[0]);
y = pMatrix * (y + GAMMA * externalForces[1]);
// Draw the points.
if (i % 200 == 0 && i > 0)
drawPoints(croppedImage, x, y, { 0.2f * i, 0.2f * i, 0 });
}
Это код для вычисления производных.
array<Mat, 2> edgeMatrices(Mat &img) {
// Convert image.
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
// Apply scharr filter.
Mat grad_x, grad_y, blurred_x, blurred_y;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
int kernSize = 3;
Sobel(gray, grad_x, ddepth, 1, 0, kernSize, scale, delta, BORDER_DEFAULT);
Sobel(gray, grad_y, ddepth, 0, 1, kernSize, scale, delta, BORDER_DEFAULT);
GaussianBlur(grad_x, blurred_x, Size(5, 5), 30);
GaussianBlur(grad_y, blurred_y, Size(5, 5), 30);
return { blurred_x, blurred_y };
}
array<Mat, 2> external(array<Mat, 2> &edgeMat, Mat &x, Mat &y) {
array<Mat, 2> ext;
ext[0] = { Size{ 1, POINTS_NUM }, CV_32FC1 };
ext[1] = { Size{ 1, POINTS_NUM }, CV_32FC1 };
for (size_t i = 0; i < POINTS_NUM; ++i) {
ext[0].at<float>(0, i) = - edgeMat[0].at<short>(y.at<float>(0, i), x.at<float>(0, i));
ext[1].at<float>(0, i) = - edgeMat[1].at<short>(y.at<float>(0, i), x.at<float>(0, i));
}
return ext;
}
Как видите, точки контура сходятся очень странным образом, а не к краюгубы (это был результат, который я ожидал).Я не могу понять, является ли это ошибкой в реализации или настройкой параметров, или это просто нормальное поведение, и я что-то неправильно понял в алгоритме.У меня есть некоторые сомнения по поводу производных матриц, я думаю, что они должны быть каким-то образом упорядочены, но я не уверен, какой из них правильный.Кто-нибудь может мне помочь?
Единственные реализации, которые я нашел, - это жадный метод.