我正在尝试使用C和OpenCV 3实现活动轮廓的蛇算法 . 我正在使用使用梯度下降的版本 . 作为基础测试,我试图画出唇的轮廓 . 这是基本图像 .

This

这是没有外力的轮廓的演变(α= 0.001,β= 3,步长= 0.3) .

This

当我添加外力时,这就是结果 .

this

作为外力,我只使用了Sobel衍生物的边缘检测 .

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

正如你所看到的,轮廓点以一种非常奇怪的方式会聚,而不是朝向唇边(这是我期望的结果) . 我无法理解它是关于实现的错误还是关于调整参数的错误,或者它只是正常行为而且我误解了算法的某些内容 . 我对衍生矩阵有一些疑问,我认为它们应该以某种方式正规化,但我不确定哪一个是正确的 . 有人能帮我吗?

我发现的唯一实现是贪婪的方法 .