圖像細化---Zhang-Suen算法


Zhang-Suen算法是一種經典的細化算法,后續很多在其基礎上進行改進, 論文是1984年在IPCV(Image Processing and Computer Vision)發表的。
論文pdf: A fast parallel algorithm for thinning digital patterns

一、基本原理

輸入:二值圖
輸出:細化后圖像

思路:刪除掉非骨架上的非零像素點

其思路比較簡單,重點在於如何判斷非零像素點是不是骨架點。
查找非骨架點
對於非零像素點,如下圖所示考慮其8領域像素點,文中共分為兩個步驟來判斷該點是否需要刪除。

  • 第一步
    判斷該點是否滿足如下條件,如果滿足則刪除,否則保留。

\[\begin{align} (a)\quad & 2 \leq B(P_1) \leq 6 \\ (b)\quad & A(P_1) = 1 \\ (c)\quad & P_2 * P_4 * P_6 = 0 \\ (d)\quad & P_4 * P_6 * P_8 = 0 \end{align} \]

其中\(A(P_1)\)表示按\(P_2\)\(P_9\)再到\(P_2\)的順序,從0變到1的次數,如下圖所示,其$A(P_1) = 2 $; \(B(P_1)\)表示其8領域非零像素個數,下圖中\(B(P_1) = 3\)

  • 第二步
    類似第一步,參考圖3,第一步的條件會刪除東南邊界點和西北的角點,這里只需要把式(c)和(d)更改為以下條件

\[\begin{align} (c)\quad & P_2 * P_4 * P_8 = 0 \\ (d)\quad & P_2 * P_6 * P_8 = 0 \end{align} \]

二、代碼邏輯

**展開代碼**

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM