需要帮助实施特殊的边缘检测器

我正在从一篇研究论文中实施一种方法。 部分方法需要一个主要的边缘检测器,作者描述如下:

  • 获取DC图像(对于宽度和高度都有效地缩减8)
  • 计算DC图像的Sobel梯度
  • 阈值Sobel梯度图像(使用T = 120)
  • 形态学操作清理边缘图像
  • 请注意,这不是 Canny边缘检测 - 它们不会打扰非最大抑制等事情。我当然可以用Canny边缘检测来做到这一点,但我希望按照文中所表达的内容来实现。

    最后一步是我有点卡住了。

    这正是作者对此所说的:

    在从边缘检测过程获得二值边缘图之后,采用二值形态学操作去除孤立的边缘像素,这可能在边缘检测期间引起误报警

    以下是所有事情应该看起来如何(边缘块已填充为黑色):

    替代文字

    如果我跳过最后一步,这就是我所拥有的:

    替代文字

    这似乎是在正确的轨道上。 所以,如果我为步骤4做了腐蚀,会发生什么情况:

    替代文字

    我尝试过腐蚀和膨胀的组合,以获得与他们相同的结果,但不要靠近。 任何人都可以提出形态运算符的组合,这将使我获得期望的结果吗?

    这里是二值化输出,以防有人想玩弄它:

    如果你真的很热心,这里是源代码(C ++):

    #include <cv.h>
    #include <highgui.h>
    #include <stdlib.h>
    #include <assert.h>
    
    using cv::Mat;
    using cv::Size;
    
    #include <stdio.h>
    
    #define DCTSIZE 8
    #define EDGE_PX 255
    
    /*
     * Display a matrix as an image on the screen.
     */
    void
    show_mat(char *heading, Mat const &m)
    {
        Mat clone = m.clone();
    
        Mat scaled(clone.size(), CV_8UC1);
        convertScaleAbs(clone, scaled);
    
        IplImage ipl = scaled;
    
        cvNamedWindow(heading, CV_WINDOW_AUTOSIZE); 
        cvShowImage(heading, &ipl);
        cvWaitKey(0);
    }
    
    /*
     * Get the DC components of the specified matrix as an image.
     */
    Mat
    get_dc(Mat const &m)
    {
        Size s = m.size();
        assert(s.width  % DCTSIZE == 0);
        assert(s.height % DCTSIZE == 0);
    
        Size dc_size = Size(s.height/DCTSIZE, s.width/DCTSIZE);
    
        Mat dc(dc_size, CV_32FC1);
        cv::resize(m, dc, dc_size, 0, 0, cv::INTER_AREA);
    
        return dc;
    }
    
    /*
     * Detect the edges:
     *
     * Sobel operator
     * Thresholding
     * Morphological operations
     */
    Mat
    detect_edges(Mat const &src, int T)
    {
        Mat sobelx    = Mat(src.size(), CV_32FC1);
        Mat sobely    = Mat(src.size(), CV_32FC1);
        Mat sobel_sum = Mat(src.size(), CV_32FC1);
    
        cv::Sobel(src, sobelx, CV_32F, 1, 0, 3, 0.5);
        cv::Sobel(src, sobely, CV_32F, 0, 1, 3, 0.5);
    
        cv::add(cv::abs(sobelx), cv::abs(sobely), sobel_sum);
    
        Mat binarized = src.clone();
        cv::threshold(sobel_sum, binarized, T, EDGE_PX, cv::THRESH_BINARY);
    
        cv::imwrite("binarized.png", binarized);
    
        //
        // TODO: this is the part I'm having problems with.
        //
    
    #if 0
        //
        // Try a 3x3 cross structuring element.
        //
        Mat elt(3,3, CV_8UC1);
        elt.at<uchar>(0, 1) = 0;
        elt.at<uchar>(1, 0) = 0;
        elt.at<uchar>(1, 1) = 0;
        elt.at<uchar>(1, 2) = 0;
        elt.at<uchar>(2, 1) = 0;
    #endif
    
        Mat dilated = binarized.clone();
        //cv::dilate(binarized, dilated, Mat());
    
        cv::imwrite("dilated.png", dilated);
    
        Mat eroded = dilated.clone();
        cv::erode(dilated, eroded, Mat());
    
        cv::imwrite("eroded.png", eroded);
    
        return eroded;
    }
    
    /*
     * Black out the blocks in the image that contain DC edges.
     */
    void
    censure_edge_blocks(Mat &orig, Mat const &edges)
    {
        Size s = edges.size();
        for (int i = 0; i < s.height; ++i)
        for (int j = 0; j < s.width;  ++j)
        {
            if (edges.at<float>(i, j) != EDGE_PX)
                continue;
    
            int row = i*DCTSIZE;
            int col = j*DCTSIZE;
    
            for (int m = 0; m < DCTSIZE; ++m)
            for (int n = 0; n < DCTSIZE; ++n)
                orig.at<uchar>(row + m, col + n) = 0;
        }
    }
    
    /*
     * Load the image and return the first channel.
     */
    Mat
    load_grayscale(char *filename)
    {
        Mat orig = cv::imread(filename);
        std::vector<Mat> channels(orig.channels());
        cv::split(orig, channels);
        Mat grey = channels[0];
        return grey;
    }
    
    int
    main(int argc, char **argv)
    {
        assert(argc == 3);
    
        int bin_thres = atoi(argv[2]);
    
        Mat orig = load_grayscale(argv[1]);
        //show_mat("orig", orig);
    
        Mat dc = get_dc(orig);
        cv::imwrite("dc.png", dc);
    
        Mat dc_edges = detect_edges(dc, bin_thres);
    
        cv::imwrite("dc_edges.png", dc_edges);
    
        censure_edge_blocks(orig, dc_edges);
        show_mat("censured", orig);
        cv::imwrite("censured.png", orig);
    
        return 0;
    }
    

    我无法想象任何形态学操作的组合,如果你的部分结果作为输入,将会产生与假定的正确结果相同的边缘。

    我注意到底层的形象是不同的; 这可能有助于你的结果如此不同。 Lena图像适用于指示结果的类型,但不适用于比较。 你有与原作者完全相同的图像吗?


    作者描述的可以通过使用8way连接的连接组件分析来实现。 我不会称这种形态。

    我认为你错过了其他的东西:他们的图像没有比一个像素厚的边缘。 你的。 您所引用的段落只是讨论去除孤立像素,所以必须有一个步骤您错过或实施不同。

    祝你好运!


    我认为你需要的是一种侵蚀或开放,即从某种意义上说是4路而不是8路。 OpenCV的默认形态内核是一个3x3的矩形( shape = CV_SHAPE_RECT IplConvKernel )。 这在薄边上非常苛刻。

    您可能想尝试使用shape = CV_SHAPE_CROSS的3x3自定义IplConvKernel侵蚀。 如果你需要一个更精细的过滤器,你可能想尝试使用4个不同的CV_SHAPE_RECT内核,大小为1x2,2x1,锚点分别为(0,1)和(1,0)。

    链接地址: http://www.djcxy.com/p/4055.html

    上一篇: Need help implementing a special edge detector

    下一篇: How to check if a checkbox in a checkbox array is checked with jquery