Алгоритм активного контура Snake с C ++ и OpenCV 3 - PullRequest
0 голосов
/ 06 июня 2018

Я пытаюсь реализовать алгоритм змеи для активного контура, используя C ++ и OpenCV 3. Я работаю с версией, которая использует градиентный спуск.В качестве базового теста я пытаюсь нарисовать контур губы.Это базовое изображение.

This

Это эволюция контура без внешних сил (альфа = 0,001, бета = 3, размер шага =0.3).

This

Когда я добавляю внешнюю силу, это результат.

this

В качестве внешней силы я использовал только определение края с помощью производной Собеля.

Sobel derivative

Этот код я использую для точекобновление.

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;
}

Как видите, точки контура сходятся очень странным образом, а не к краюгубы (это был результат, который я ожидал).Я не могу понять, является ли это ошибкой в ​​реализации или настройкой параметров, или это просто нормальное поведение, и я что-то неправильно понял в алгоритме.У меня есть некоторые сомнения по поводу производных матриц, я думаю, что они должны быть каким-то образом упорядочены, но я не уверен, какой из них правильный.Кто-нибудь может мне помочь?

Единственные реализации, которые я нашел, - это жадный метод.

...