opencv+C++中的图片骨架提取

631 阅读1分钟

前段时间看opencv官方说明文档,看到了这个void cv::ximgproc::thinning,就尝试调用一下,结果cv::ximgproc提示不存在,又查了一遍,原来ximgproc是opencv-contrib扩展模块中的,官方说明如下:

image.png 但如果只想要这一个功能,安装opencv-contrib挺麻烦的,就抠出了ZHANG-SUEN和GUO-HALL实现代码

enum thinningType {
THINNING_ZHANGSUEN,
THINNING_GUOHALL
};
// Applies a thinning iteration to a binary image
static void thinningIteration(cv::Mat img, int iter, int thinningType) {
cv::Mat marker = cv::Mat::zeros(img.size(), CV_8UC1);

    if (thinningType == THINNING_ZHANGSUEN) {
    	for (int i = 1; i < img.rows - 1; i++)
    	{
    		for (int j = 1; j < img.cols - 1; j++)
    		{
    			uchar p2 = img.at<uchar>(i - 1, j);
    			uchar p3 = img.at<uchar>(i - 1, j + 1);
    			uchar p4 = img.at<uchar>(i, j + 1);
    			uchar p5 = img.at<uchar>(i + 1, j + 1);
    			uchar p6 = img.at<uchar>(i + 1, j);
    			uchar p7 = img.at<uchar>(i + 1, j - 1);
    			uchar p8 = img.at<uchar>(i, j - 1);
    			uchar p9 = img.at<uchar>(i - 1, j - 1);

    			int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
    				(p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
    				(p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
    				(p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
    			int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
    			int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
    			int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);

    			if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
    				marker.at<uchar>(i, j) = 1;
    		}
    	}
    }
    if (thinningType == THINNING_GUOHALL) {
    	for (int i = 1; i < img.rows - 1; i++)
    	{
    		for (int j = 1; j < img.cols - 1; j++)
    		{
    			uchar p2 = img.at<uchar>(i - 1, j);
    			uchar p3 = img.at<uchar>(i - 1, j + 1);
    			uchar p4 = img.at<uchar>(i, j + 1);
    			uchar p5 = img.at<uchar>(i + 1, j + 1);
    			uchar p6 = img.at<uchar>(i + 1, j);
    			uchar p7 = img.at<uchar>(i + 1, j - 1);
    			uchar p8 = img.at<uchar>(i, j - 1);
    			uchar p9 = img.at<uchar>(i - 1, j - 1);

    			int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
    				((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
    			int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
    			int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
    			int N = N1 < N2 ? N1 : N2;
    			int m = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);

    			if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0)))
    				marker.at<uchar>(i, j) = 1;
    		}
    	}
    }

    img &= ~marker;

}

// Apply the thinning procedure to a given image

void thinning(InputArray input, OutputArray output, int thinningType) {
cv::Mat processed = input.getMat().clone();

// Enforce the range of the input image to be in between 0 - 255

processed /= 255;

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

    do {
    	thinningIteration(processed, 0, thinningType);
    	thinningIteration(processed, 1, thinningType);
    	absdiff(processed, prev, diff);
    	processed.copyTo(prev);
    } while (countNonZero(diff) > 0);

    processed *= 255;

    output.assign(processed);

}

可以贴到自己的代码中