【问题标题】:How to skeletonize an image in open cv c++如何在opencv c ++中骨架化图像
【发布时间】:2017-02-17 17:21:42
【问题描述】:

我正在使用以下代码在 open cv 3 中使用 c++ 骨架化以下图像。输入图像如下。

#include "stdafx.h"
#include <opencv2/opencv.hpp>

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv/cvaux.h>
#include <opencv2/core/core.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/highgui/highgui.hpp>


using namespace cv;
using namespace std;

/**
* Perform one thinning iteration.
* Normally you wouldn't call this function directly from your code.
*
* Parameters:
*       im    Binary image with range = [0,1]
*       iter  0=even, 1=odd
*/
void thinningIteration(cv::Mat& img, int iter)
{
    CV_Assert(img.channels() == 1);
    CV_Assert(img.depth() != sizeof(uchar));
    CV_Assert(img.rows > 3 && img.cols > 3);

    cv::Mat marker = cv::Mat::zeros(img.size(), CV_8UC1);

    int nRows = img.rows;
    int nCols = img.cols;

    if (img.isContinuous()) {
        nCols *= nRows;
        nRows = 1;
    }

    int x, y;
    uchar *pAbove;
    uchar *pCurr;
    uchar *pBelow;
    uchar *nw, *no, *ne;    // north (pAbove)
    uchar *we, *me, *ea;
    uchar *sw, *so, *se;    // south (pBelow)

    uchar *pDst;

    // initialize row pointers
    pAbove = NULL;
    pCurr = img.ptr<uchar>(0);
    pBelow = img.ptr<uchar>(1);

    for (y = 1; y < img.rows - 1; ++y) {
        // shift the rows up by one
        pAbove = pCurr;
        pCurr = pBelow;
        pBelow = img.ptr<uchar>(y + 1);

        pDst = marker.ptr<uchar>(y);

        // initialize col pointers
        no = &(pAbove[0]);
        ne = &(pAbove[1]);
        me = &(pCurr[0]);
        ea = &(pCurr[1]);
        so = &(pBelow[0]);
        se = &(pBelow[1]);

        for (x = 1; x < img.cols - 1; ++x) {
            // shift col pointers left by one (scan left to right)
            nw = no;
            no = ne;
            ne = &(pAbove[x + 1]);
            we = me;
            me = ea;
            ea = &(pCurr[x + 1]);
            sw = so;
            so = se;
            se = &(pBelow[x + 1]);

            int A = (*no == 0 && *ne == 1) + (*ne == 0 && *ea == 1) +
                (*ea == 0 && *se == 1) + (*se == 0 && *so == 1) +
                (*so == 0 && *sw == 1) + (*sw == 0 && *we == 1) +
                (*we == 0 && *nw == 1) + (*nw == 0 && *no == 1);
            int B = *no + *ne + *ea + *se + *so + *sw + *we + *nw;
            int m1 = iter == 0 ? (*no * *ea * *so) : (*no * *ea * *we);
            int m2 = iter == 0 ? (*ea * *so * *we) : (*no * *so * *we);

            if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
                pDst[x] = 1;
        }
    }

    img &= ~marker;
}

/**
* Function for thinning the given binary image
*
* Parameters:
*       src  The source image, binary with range = [0,255]
*       dst  The destination image
*/
void thinning(const cv::Mat& src, cv::Mat& dst)
{
    dst = src.clone();
    dst /= 255;         // convert to binary image

    cv::Mat prev = cv::Mat::zeros(dst.size(), CV_8UC1);
    cv::Mat diff;

    do {
        thinningIteration(dst, 0);
        thinningIteration(dst, 1);
        cv::absdiff(dst, prev, diff);
        dst.copyTo(prev);
    } while (cv::countNonZero(diff) > 0);

    dst *= 255;
}



/**
* This is an example on how to call the thinning funciton above
*/





int main()
{
    cv::Mat src = cv::imread("G:\\realimage9.jpg");
    /*Mat image = imread("G:\\realimage.jpg", CV_LOAD_IMAGE_UNCHANGED);*/
    if (!src.data)
        return -1;


    cv::Mat bw;
    cv::cvtColor(src, bw, CV_BGR2GRAY);







    //  /*dilate(bw, bw, Mat(), Point(-1, -1), 4);
    //  erode(bw, bw, Mat(), Point(-1, -1), 2);*/
    GaussianBlur(bw, bw, cv::Size(9, 9), 2, 2);

    cv::imshow("blur", bw);

    cv::threshold(bw, bw, 10, 255, CV_THRESH_BINARY_INV);
    cv::imshow("convert", bw);




    thinning(bw, bw);
    cv::imshow("src", src);
    cv::imshow("dst", bw);
    cv::waitKey();
    return 0;



}

我得到的输出是

不够流畅。我在这里使用了 zhang-suen-thinning 算法。我从互联网上得到了这个代码。我是打开 cv 和 C++ 的新手。我被困在这里。我的下一步是提取端点、孔洞等特征。因此,有人可以帮助我获得更平滑的骨架化图像。

【问题讨论】:

    标签: c++ windows opencv


    【解决方案1】:

    这是一个悬而未决的问题。

    这是一篇论文加上一个可在网络上运行的 Java 程序,它或多或少可以满足您的需求。但它仍然应该被认为是实验性的。

    如果您发现 this code 对您的研究/软件有用,请考虑引用以下出版物:

    Andrés Solís Montero 和 Jochen Lang。 Skeleton pruning by contour approximation and the integer medial axis transform。 计算机与图形学,爱思唯尔,2012。

    贡献者
    1. Andrés Solís Montero
    2. Jochen Lang
    3. 大卫·拉罗
    4. 安娜·劳拉·佩雷斯
    5. 科里·埃德蒙兹

    【讨论】:

    • 非常感谢您的关心。我会试试这个,让你知道。 :)
    • 看起来不错...可惜它是在 Java 中的 ;)
    • 哦。 :( 我正在使用 c++。没关系,谢谢你的帮助。这对我来说意义重大。:)
    猜你喜欢
    • 2012-05-26
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 1970-01-01
    • 2014-12-19
    • 2013-05-17
    • 1970-01-01
    相关资源
    最近更新 更多