使用结构元素迭代直到收敛的形态学细化

时间:2018-01-20 13:57:55

标签: c++ algorithm opencv image-processing

已经看过以下帖子:

“Don't care” elements in kernel used for binary morphological tree pruning, MATLAB

A fast thinning algorithm

Structuring Element (Image Thinning)

我正在尝试实现细化算法(在C ++中),如here所示。 明确指出,图1中的结构元素(在链接中)将用于细化:

  

在每次迭代时,图像首先由左手结构元素稀释,然后由右手结构化,然后是两个元素的剩余六个90°旋转。

以下是链接中显示的结构元素:structuring elements

(图1:链接中描述的结构元素。)

所以我已经实现了结构元素,如下图所示。 (由于代码包含基本代码,因此我不在此处包含它)。例如, seLeft0 表示 s 上删除 e ,旋转 0 度。

structuring elements

(图2:在我的代码中实现的结构元素。)

为了使用该结构元素,我首先加载源文件。

// Read original image 
Mat src = imread("maze.jpg",IMREAD_GRAYSCALE);

然后我声明另一个Mat文件,它将成为二进制文件中的目标文件(dst_bin)

Mat dst_bin(src.size(), src.type());

之后,我使用adaptiveThreshold函数将原始图像转换为二进制。

//  Convert into binary using Adaptive th.
    adaptiveThreshold(src, dst_bin, 1, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 95, -2);

到此为止我一切按预期工作。使用这段代码(因为dst_bin中的值是0或1,我将Mat文件与255相乘以便我可以看到该图。)

imshow("Maze after bin. th. ", dst_bin*255);

我得到以下迷宫:

Original maze (图3:原始迷宫)

现在繁琐的部分来了。

我应用如下结构元素: (因为应用结构化元素会导致值大于1,所以在每个filter2D之后达到阈值。)

Mat dum = dst_bin.clone();

filter2D(dst_bin, dum, dst_bin.depth(), seLeft0);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seRight0);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seLeft90);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seRight90);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seLeft180);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seRight180);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seLeft270);
threshold(dum, dum, 1, 1, THRESH_BINARY);

filter2D(dum, dum, dst_bin.depth(), seRight270);
threshold(dum, dum, 1, 1, THRESH_BINARY);
imshow("1st iteration", dum * 255);

for (int iii = 0; iii < 10; iii++)
{
    filter2D(dum, dum, dst_bin.depth(), seLeft0);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight0);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seLeft90);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight90);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seLeft180);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight180);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seLeft270);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight270);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

}

imshow("10th iteration", dum * 255);

但不是像这里所示那样变薄:

expected thinning (图4:预期变薄。)

第一次迭代后我得到以下结果:

1st iteration result (图5:第1次变薄的结果)

这是第10次迭代:

10th iteration result (图6:第10次细化的结果)

正如您所看到的那样,结果不是预期的,因为我一直关注的link中对此进行了解释。

那么请你告诉我我做错了什么?

我能想到的第一件事是关于结构元素。如图1所示, DO NOT CARE 项目。我已将它们实现为(如图2所示)。那么如何在C ++ / OpenCV中的结构元素中实现 DO NOT CARE 项呢?我应该把它们归零还是一些?或者是否有另一种方法(比如以某种方式组合它们)。

第二件事是我在OpenCV 3.x.x中使用 filter2D 。这是正确的方法吗?

总而言之,我如何实现我一直关注的链接中描述的细化算法。

您诚挚的......

PS:你可以在附录中找到代码。

-------- --------附录

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <vector>
#include <array>
using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    // Read original image 
    Mat src = imread("maze.png",IMREAD_GRAYSCALE);
    Mat dst_bin(src.size(), src.type());

    //if fail to read the image
    if (!src.data)
    {
        cout << "Error loading the image" << endl;
        return -1;
    }

    //  Convert into binary using Adaptive th.
    adaptiveThreshold(src, dst_bin, 1, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 95, -2);
    //  now dst_bin e^x = {0,1} 
    imshow("Maze after bin. th. ", dst_bin*255);

    double  minVal;
    double  maxVal;
    minMaxLoc(dst_bin, &minVal, &maxVal); cout << "dst_bin [" << minVal << ", " << maxVal << "]" << endl;

    //  seLeft0
    Mat seLeft0 = getStructuringElement(MORPH_RECT, Size(3, 3));
    array<array<uchar, 3>, 3> data = { { { 0, 0, 0 },{ 0, 1, 0 },{ 1, 1, 1 } } };
    seLeft0 = Mat(3, 3, CV_8UC1, &data);
    cout << "seLeft0 = " << endl << " " << seLeft0 << endl << endl;

    //  seLeft90
    Mat seLeft90 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 1, 0, 0 },{ 1, 1, 0 },{ 1, 0, 0 } } };
    seLeft90 = Mat(3, 3, CV_8UC1, &data);
    cout << "seLeft90 = " << endl << " " << seLeft90 << endl << endl;

    //  seLeft180
    Mat seLeft180 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 1, 1, 1 },{ 0, 1, 0 },{ 0, 0, 0 } } };
    seLeft180 = Mat(3, 3, CV_8UC1, &data);
    cout << "seLeft180 = " << endl << " " << seLeft180 << endl << endl;

    //  seLeft270
    Mat seLeft270 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 0, 0, 1 },{ 0, 1, 1 },{ 0, 0, 1 } } };
    seLeft270 = Mat(3, 3, CV_8UC1, &data);
    cout << "seLeft270 = " << endl << " " << seLeft270 << endl << endl;

    //  seRight0
    Mat seRight0 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 0, 0, 0 },{ 1, 1, 0 },{ 0, 1, 0 } } };
    seRight0 = Mat(3, 3, CV_8UC1, &data);
    cout << "seRight0 = " << endl << " " << seRight0 << endl << endl;

    //  seRight90
    Mat seRight90 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 0, 1, 0 },{ 1, 1, 0 },{ 0, 0, 0 } } };
    seRight90 = Mat(3, 3, CV_8UC1, &data);
    cout << "seRight90 = " << endl << " " << seRight90 << endl << endl;

    //  seRight180
    Mat seRight180 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 0, 1, 0 },{ 0, 1, 1 },{ 0, 0, 0 } } };
    seRight180 = Mat(3, 3, CV_8UC1, &data);
    cout << "seRight180 = " << endl << " " << seRight180 << endl << endl;

    //  seRight270
    Mat seRight270 = getStructuringElement(MORPH_RECT, Size(3, 3));
    data = { { { 0, 0, 0 },{ 0, 1, 1 },{ 0, 1, 0 } } };
    seRight270 = Mat(3, 3, CV_8UC1, &data);
    cout << "seRight270 = " << endl << " " << seRight270 << endl << endl;

    Mat dum = dst_bin.clone();

    filter2D(dst_bin, dum, dst_bin.depth(), seLeft0);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight0);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seLeft90);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight90);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seLeft180);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight180);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seLeft270);
    threshold(dum, dum, 1, 1, THRESH_BINARY);

    filter2D(dum, dum, dst_bin.depth(), seRight270);
    threshold(dum, dum, 1, 1, THRESH_BINARY);
    imshow("1st iteration", dum * 255);

    for (int iii = 0; iii < 10; iii++)
    {
        filter2D(dum, dum, dst_bin.depth(), seLeft0);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seRight0);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seLeft90);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seRight90);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seLeft180);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seRight180);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seLeft270);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

        filter2D(dum, dum, dst_bin.depth(), seRight270);
        threshold(dum, dum, 1, 1, THRESH_BINARY);

    }

    imshow("10th iteration", dum * 255);

    minMaxLoc(dum, &minVal, &maxVal); cout << "dum [" << minVal << ", " << maxVal << "]" << endl;

cout << endl;
    waitKey();
    return 0;
}

0 个答案:

没有答案