图像细化---Zhang-Suen算法

Zhang-Suen算法是一种经典的细化算法,后续很多在其基础上进行改进, 论文是1984年在IPCV(Image Processing and Computer Vision)发表的。
论文pdf: A fast parallel algorithm for thinning digital patterns

一、基本原理

输入:二值图
输出:细化后图像

思路:删除掉非骨架上的非零像素点

其思路比较简单,重点在于如何判断非零像素点是不是骨架点。
查找非骨架点
对于非零像素点,如下图所示考虑其8领域像素点,文中共分为两个步骤来判断该点是否需要删除。

  • 第一步
    判断该点是否满足如下条件,如果满足则删除,否则保留。

(1)(a)2B(P1)6(2)(b)A(P1)=1(3)(c)P2P4P6=0(4)(d)P4P6P8=0

其中A(P1)表示按P2P9再到P2的顺序,从0变到1的次数,如下图所示,其A(P1)=2B(P1)表示其8领域非零像素个数,下图中B(P1)=3

  • 第二步
    类似第一步,参考图3,第一步的条件会删除东南边界点和西北的角点,这里只需要把式(c)和(d)更改为以下条件

(5)(c)P2P4P8=0(6)(d)P2P6P8=0

二、代码逻辑

**展开代码**

inline int GetObjectPixel(Image& image, int row, int col)
{
	if (row >= 0 && row < image.GetWidth() && col >= 0 && col < image.GetHeight())
	{
		return (*image.GetPixel(row, col) > 128) ? 1 : 0;
	}

	return 0;
}

inline bool IsDelete(Image& image, int i, int j, bool bSecond = false)
{
	int p2 = GetObjectPixel(image, i - 1, j );
	int p3 = GetObjectPixel(image, i - 1, j + 1);
	int p4 = GetObjectPixel(image, i, j + 1);
	int p5 = GetObjectPixel(image, i + 1, j + 1);
	int p6 = GetObjectPixel(image, i + 1, j);
	int p7 = GetObjectPixel(image, i + 1, j - 1);
	int p8 = GetObjectPixel(image, i, j - 1);
	int p9 = GetObjectPixel(image, i - 1, j - 1);

	// cacl AP
	int ap = 0;
	if (1 == p3 - p2) {
		ap += 1;
	}
	if (1 == p4 - p3) {
		ap += 1;
	}
	if (1 == p5 - p4) {
		ap += 1;
	}
	if (1 == p6 - p5) {
		ap += 1;
	}
	if (1 == p7 - p6) {
		ap += 1;
	}
	if (1 == p8 - p7) {
		ap += 1;
	}
	if (1 == p9 - p8) {
		ap += 1;
	}
	if (1 == p2 - p9) {
		ap += 1;
	}

	if (ap != 1) {
		return false;
	}

	// cacl PB
	int pb = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
	if (pb < 2 || pb > 6) {
		return false;
	}

	if (bSecond) {
		if (0 == p2 * p4 * p8 && 0 == p2 * p6 * p8) {
			return true;
		}
	}
	else {
		if (0 == p2 * p4 * p6 && 0 == p4 * p6 * p8) {
			return true;
		}
	}

	return false;
}

void Skeletonize(Image& image)
{
        const int row = image.GetWidth(), column = image.GetHeight();
	int c = 0;
	std::vector<int> XYPosition;
	while (true) {
		c = 0;
		// first
		for (int i = 0; i < row; ++i)
		{
			for (int j = 0; j < column; ++j)
			{
				if (*image.GetPixel(i, j) > 128) {
					if (IsDelete(image, i, j))
					{
						XYPosition.push_back(i);
						XYPosition.push_back(j);
						c += 1;
					}
				}
			}
		}
		if (c > 0) {
			for (int idx = 0; idx < c; ++idx){
				*image.GetPixel(XYPosition[idx * 2], XYPosition[idx * 2+ 1]) = 0;
			}
			XYPosition.clear();
			c = 0;
		}
		else {
			break;
		}
		// second
		for (int i = 0; i < row; ++i)
		{
			for (int j = 0; j < column; ++j)
			{
				if (*image.GetPixel(i, j) > 128) {
					if (IsDelete(image, i, j, true))
					{
						XYPosition.push_back(i);
						XYPosition.push_back(j);
						c += 1;
					}
				}
			}
		}

		if (c > 0) {
			for (int idx = 0; idx < c; ++idx) {
				*image.GetPixel(XYPosition[idx * 2], XYPosition[idx * 2 + 1]) = 0;
			}
			XYPosition.clear();
			c = 0;
		}
		else {
			break;
		}
	}
}

三、效果

四、其他参考资料

https://www.geometrictools.com/Documentation/Skeletons.pdf

posted @   半夜打老虎  阅读(3495)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示