OpenCV实现二值图细化(骨架提取)

对二值图进行细化(骨架提取),也就是把每根线条细化到一个像素的宽度。有两个比较成熟的算法实现此功能,分别是Zhang-Suen算法和Guo-Hall算法。

我们下面使用OpenCVSharp,使用C#实现上述两个算法:

cs 复制代码
private static Mat ThinningIteration(Mat img, int iter, int thinningType)
{
    Mat marker = Mat.Zeros(img.Size(), MatType.CV_8UC1);
    int rows = img.Rows;
    int cols = img.Cols;
    marker.Col(0).SetTo(1);
    marker.Col(cols - 1).SetTo(1);
    marker.Row(0).SetTo(1);
    marker.Row(rows - 1).SetTo(1);

    //THINNING_ZHANGSUEN
    if (thinningType == 1)
    {
        marker.ForEachAsByte((byte* value, int* position) =>
        {
            int i = position[0];
            int j = position[1];
            if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1)
                return;

            var ptr = (byte*)img.Ptr(i, j).ToPointer();

            // p9 p2 p3
            // p8 p1 p4
            // p7 p6 p5
            byte p2 = ptr[-cols];
            byte p3 = ptr[-cols + 1];
            byte p4 = ptr[1];
            byte p5 = ptr[cols + 1];
            byte p6 = ptr[cols];
            byte p7 = ptr[cols - 1];
            byte p8 = ptr[-1];
            byte p9 = ptr[-cols - 1];

            int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7);

            if (iter == 0)
                *value = lut_zhang_iter0[neighbors];
            else
                *value = lut_zhang_iter1[neighbors];
        });
    }
    //THINNING_GUOHALL
    else if (thinningType == 2)
    {
        marker.ForEachAsByte((byte* value, int* position) =>
        {
            int i = position[0];
            int j = position[1];
            if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1)
                return;

            var ptr = (byte*)img.Ptr(i, j).ToPointer();

            // p9 p2 p3
            // p8 p1 p4
            // p7 p6 p5
            byte p2 = ptr[-cols];
            byte p3 = ptr[-cols + 1];
            byte p4 = ptr[1];
            byte p5 = ptr[cols + 1];
            byte p6 = ptr[cols];
            byte p7 = ptr[cols - 1];
            byte p8 = ptr[-1];
            byte p9 = ptr[-cols - 1];

            int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7);

            if (iter == 0)
                *value = lut_guo_iter0[neighbors];
            else
                *value = lut_guo_iter1[neighbors];
        });
    }

    img &= marker;
    return img;
}

public static void Thinning(InputArray input, OutputArray output, int thinningType)
{
    Mat processed = input.GetMat().Clone();
    processed /= 255;

    Mat prev = processed.Clone();
    Mat diff = new Mat();
    do
    {
        processed = ThinningIteration(processed, 0, thinningType);
        processed = ThinningIteration(processed, 1, thinningType);
        Cv2.Absdiff(processed, prev, diff);
        if (diff.CountNonZero() == 0) break;
        processed.CopyTo(prev);
    }
    while (true);

    processed *= 255;

    processed.CopyTo(output);
}

我们的测试框图如下图所示:

原二值图如下图所示:

细化(提取骨骼)之后的结果图如下:

Zhang-Suen算法

Guo-Hall算法

相关推荐
lxmyzzs18 小时前
【图像算法 - 23】工业应用:基于深度学习YOLO12与OpenCV的仪器仪表智能识别系统
人工智能·深度学习·opencv·算法·计算机视觉·图像算法·仪器仪表识别
AI 嗯啦19 小时前
计算机视觉--opencv(代码详细教程)(三)--图像形态学
人工智能·opencv·计算机视觉
gloomyfish2 天前
【零代码】OpenCV C# 快速开发框架演示
人工智能·opencv·c#
阿杜杜不是阿木木3 天前
什么?OpenCV调用cv2.putText()乱码?寻找支持中文的方法之旅
人工智能·opencv·计算机视觉
赴3353 天前
图像边缘检测
人工智能·python·opencv·计算机视觉
星期天要睡觉3 天前
(纯新手教学)计算机视觉(opencv)实战八——四种边缘检测详解:Sobel、Scharr、Laplacian、Canny
人工智能·opencv·计算机视觉
windSnowLi3 天前
Python opencv识别图片中重叠圆的圆心位置
开发语言·python·opencv
lxmyzzs3 天前
【图像算法 - 21】慧眼识虫:基于深度学习与OpenCV的农田害虫智能识别系统
人工智能·深度学习·opencv·算法·yolo·目标检测·计算机视觉
批量小王子3 天前
2025-08-19利用opencv检测图片中文字及图片的坐标
人工智能·opencv·计算机视觉
法迪4 天前
【学习】Linux 内核中的 cgroup freezer 子系统
人工智能·opencv·计算机视觉