计算机视觉 图片处理 在骨架化过程中,每次迭代都会从图像的边缘移除一层像素,直到只剩下单像素宽度的骨架
你说得对,if cv2.countNonZero(binary) == 0: break
这个条件确实表示图像中已经没有非零像素,即图像完全变为空白。这并不是骨架化完成的标志,而是表示图像已经被腐蚀到没有任何内容了。
在骨架化过程中,我们需要一个更合适的停止条件,以确保图像被正确地简化为单像素宽度的骨架,而不是被完全腐蚀掉。
骨架化的正确停止条件
在骨架化过程中,每次迭代都会从图像的边缘移除一层像素,直到只剩下单像素宽度的骨架。正确的停止条件是当图像中不再有可以被移除的像素时,即图像已经不能再被腐蚀,但仍然有非零像素存在。
改进的骨架化代码
以下是一个更完整的骨架化代码示例,其中包含了正确的停止条件:
import cv2
import numpy as npdef skeletonize(image):# 确保输入图像是二值化的_, binary = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)# 创建结构元素element = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))# 初始化骨架图像skeleton = np.zeros_like(binary)# 初始化前一次的骨架图像prev_skeleton = np.zeros_like(binary)# 迭代直到骨架图像不再变化while True:# 腐蚀操作eroded = cv2.erode(binary, element)# 膨胀操作temp = cv2.dilate(eroded, element)# 计算差值temp = cv2.subtract(binary, temp)# 更新骨架skeleton = cv2.bitwise_or(skeleton, temp)# 更新二值图像binary = eroded.copy()# 检查骨架图像是否发生变化if np.array_equal(skeleton, prev_skeleton):break# 更新前一次的骨架图像prev_skeleton = skeleton.copy()return skeleton# 读取图像
image = cv2.imread('your_image.png', cv2.IMREAD_GRAYSCALE)# 骨架化处理
skeleton = skeletonize(image)# 显示结果
cv2.imshow('Skeleton', skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码解释
-
初始化骨架图像和前一次骨架图像:
skeleton
用于存储当前的骨架图像。prev_skeleton
用于存储上一次迭代的骨架图像,以便比较是否发生变化。
-
迭代处理:
- 每次迭代中,先对当前的二值图像进行腐蚀操作,然后进行膨胀操作。
- 计算腐蚀和膨胀后的图像的差值,这个差值就是当前迭代的骨架部分。
- 将差值与之前的骨架图像进行逻辑或操作,更新骨架图像。
- 更新二值图像为腐蚀后的图像,继续下一次迭代。
-
停止条件:
- 使用
np.array_equal(skeleton, prev_skeleton)
检查当前的骨架图像是否与上一次的骨架图像相同。 - 如果相同,说明骨架图像已经不再变化,此时已经完成了骨架化,退出循环。
- 使用
为什么这样可以
在骨架化过程中,每次迭代都会从图像的边缘移除一层像素,直到只剩下单像素宽度的骨架。当骨架图像不再变化时,说明已经无法再从边缘移除像素,此时的骨架图像就是最终的骨架。
结果
使用上述代码,你可以得到一个单像素宽度的骨架图像,而不是一个完全空白的图像。这种骨架化方法在许多计算机视觉任务中非常有用,尤其是在需要提取形状特征的场景中。