当前位置: 首页 > news >正文

计算机视觉 图片处理 在骨架化过程中,每次迭代都会从图像的边缘移除一层像素,直到只剩下单像素宽度的骨架

你说得对,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()

代码解释

  1. 初始化骨架图像和前一次骨架图像

    • skeleton 用于存储当前的骨架图像。
    • prev_skeleton 用于存储上一次迭代的骨架图像,以便比较是否发生变化。
  2. 迭代处理

    • 每次迭代中,先对当前的二值图像进行腐蚀操作,然后进行膨胀操作。
    • 计算腐蚀和膨胀后的图像的差值,这个差值就是当前迭代的骨架部分。
    • 将差值与之前的骨架图像进行逻辑或操作,更新骨架图像。
    • 更新二值图像为腐蚀后的图像,继续下一次迭代。
  3. 停止条件

    • 使用 np.array_equal(skeleton, prev_skeleton) 检查当前的骨架图像是否与上一次的骨架图像相同。
    • 如果相同,说明骨架图像已经不再变化,此时已经完成了骨架化,退出循环。

为什么这样可以

在骨架化过程中,每次迭代都会从图像的边缘移除一层像素,直到只剩下单像素宽度的骨架。当骨架图像不再变化时,说明已经无法再从边缘移除像素,此时的骨架图像就是最终的骨架。

结果

使用上述代码,你可以得到一个单像素宽度的骨架图像,而不是一个完全空白的图像。这种骨架化方法在许多计算机视觉任务中非常有用,尤其是在需要提取形状特征的场景中。

http://www.dtcms.com/a/340241.html

相关文章:

  • 机器学习--数据清洗—(续篇)
  • 【论文阅读】Multi-metrics adaptively identifies backdoors in Federated Learning
  • Python文件操作与异常处理详解 :基础方法、注意事项及os模块常用功能
  • day31 SQLITE
  • 百度Q2财报:总营收327亿 AI新业务收入首次超100亿
  • 前端-JavaScript笔记(核心语法)
  • Go语言数据类型全解析
  • 线程安全的产生以及解决方案
  • 记一次pnpm start启动异常
  • 学习设计模式《二十三》——桥接模式
  • 算法实战入门第二篇:链表结构与五大经典应用
  • 如何制作免费的比特币冷钱包
  • C++中的 Eigen库使用
  • 机器学习算法核心总结
  • AI全栈工程师:重塑软件开发全生命周期的未来革命
  • Nginx目录结构与配置文件全解析
  • 3-1〔OSCP ◈ 研记〕❘ WEB应用攻击▸理论概述 OWASP
  • 【LeetCode 热题 100】279. 完全平方数——(解法三)空间优化
  • Windows 中的“计数器”
  • ASP.NET 使用redis 存储session 负载机器共享会话状态
  • 【39页PPT】大模型DeepSeek在运维场景中的应用(附下载方式)
  • RabbitMQ:消息转化器
  • 高通 XR 系列芯介绍
  • 【论文阅读】SIMBA: single-cell embedding along with features(2)
  • ansible playbook 实战案例roles | 实现基于firewalld添加端口
  • ansible playbook 实战案例roles | 实现基于 IHS 的 AWStats 访问监控系统
  • Milvus 可观测性最佳实践
  • 分布式唯一 ID 生成方案
  • 基于 Uniapp 的医疗挂号系统开发经验分享
  • 苹果XR芯片介绍