骨架

表示一个平面区域的结构形状的一种重要方法是将它简化为图形,这种简化可以通过一种细化(也称为骨架化)算法得到该区域的骨架来实现。细化是一种形态学变形,在提取中轴线的图像处理问题中,细化起着核心作用。为了产生一个区域的中轴的表示,提出了许多典型的算法,这些算法都是通过迭代一个区域的边界点的细化过程,删除这些点时需要服从如下约束条件:(1)不能删除端点,(2)不能破坏连接性,(3)不能导致区域的过度腐蚀。

因此,细化算法的一次迭代由如下步骤组成:(1)标记将被删除的边界点;(2)删除做了标记的点;(3)继续标记将被删除的剩余的边界点;(4)删除标记过的点。反复应用这个基本过程,直到再也没有被删除的点为止,此时算法终止,生成了该区域的骨架。

Zhang-Suen细化算法

首先定义像素点的8邻域如下图(前景为1,背景为0):

# 定义像素点周围的8邻域
#                P9 P2 P3
#                P8 P1 P4
#                P7 P6 P5def neighbours(x,y,image):img = imagex_1, y_1, x1, y1 = x-1, y-1, x+1, y+1return [ img[x_1][y],img[x_1][y1],img[x][y1],img[x1][y1],         # P2,P3,P4,P5img[x1][y], img[x1][y_1], img[x][y_1], img[x_1][y_1] ]    # P6,P7,P8,P9

N(p1)表示与1相邻的8个像素点中,为前景像素点的个数。

for x in range(1, rows - 1):for y in range(1, columns - 1):P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)

S(P1)表示从P2 ~ P9中出现0~1的累计次数,其中0表示背景,1表示前景。

# 计算邻域像素从0变化到1的次数def transitions(neighbours):n = neighbours + neighbours[0:1]      # P2,P3,...,P8,P9,P2return sum( (n1, n2) == (0, 1) for n1, n2 in zip(n, n[1:]) )  # (P2,P3),(P3,P4),...,(P8,P9),(P9,P2)

Zhang-Suen细化算法的整个迭代过程分为两步:

Step One:循环所有前景像素点,对符合如下条件的像素点标记为删除:

1.      2 <= N(p1) <=6,中心像素p1周围的目标像素(二值中的1)的个数在2~6之间;

2.      S(P1) = 1,8邻域像素中,按顺时针方向,相邻两个像素出现0→1的次数;

3.      P2 * P4 * P6 = 0

4.      P4 * P6 * P8 = 0

# Step 1
changing1 = []
rows, columns = Image_Thinned.shape
for x in range(1, rows - 1):for y in range(1, columns - 1):P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)if (Image_Thinned[x][y] == 1     and    # Condition 0: Point P1 in the object regions 2 <= sum(n) <= 6   and    # Condition 1: 2<= N(P1) <= 6transitions(n) == 1 and   # Condition 2: S(P1)=1  P2 * P4 * P6 == 0  and    # Condition 3   P4 * P6 * P8 == 0):       # Condition 4

Step Two:跟Step One很类似,条件1、2完全一致,只是条件3、4稍微不同,满足如下条件的像素P1则标记为删除,条件如下:

1.      2 <= N(p1) <=6

2.      S(P1) = 1

3.      P2 * P4 * P8 = 0

4.      P2 * P6 * P8 = 0

循环上述两步骤,直到两步中都没有像素被标记为删除为止,输出的结果即为二值图像细化后的骨架。

# Step 2
changing2 = []
for x in range(1, rows - 1):for y in range(1, columns - 1):P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)if (Image_Thinned[x][y] == 1   and        # Condition 02 <= sum(n) <= 6  and       # Condition 1transitions(n) == 1 and      # Condition 2P2 * P4 * P8 == 0 and       # Condition 3P2 * P6 * P8 == 0):            # Condition 4changing2.append((x,y))
for x, y in changing2: Image_Thinned[x][y] = 0

伪代码

算法完整代码

# 导入库
import matplotlib
import matplotlib.pyplot as plt
import skimage.io as io# 将图像转为灰度图像
from PIL import Image
img = Image.open("E://straight//3.png").convert('L')
img.save('E://straight//3 greyscale.png')# 读取灰度图像
Img_Original = io.imread('E://straight//3 greyscale.png')# 对图像进行预处理,二值化
from skimage import filters
from skimage.morphology import disk
# 中值滤波
Img_Original = filters.median(Img_Original,disk(5))
# 二值化
BW_Original = Img_Original < 235
# 定义像素点周围的8邻域
#                P9 P2 P3
#                P8 P1 P4
#                P7 P6 P5def neighbours(x,y,image):img = imagex_1, y_1, x1, y1 = x-1, y-1, x+1, y+1return [ img[x_1][y],img[x_1][y1],img[x][y1],img[x1][y1],         # P2,P3,P4,P5img[x1][y], img[x1][y_1], img[x][y_1], img[x_1][y_1] ]    # P6,P7,P8,P9# 计算邻域像素从0变化到1的次数
def transitions(neighbours):n = neighbours + neighbours[0:1]      # P2,P3,...,P8,P9,P2return sum( (n1, n2) == (0, 1) for n1, n2 in zip(n, n[1:]) )  # (P2,P3),(P3,P4),...,(P8,P9),(P9,P2)# Zhang-Suen 细化算法
def zhangSuen(image):Image_Thinned = image.copy()  # Making copy to protect original imagechanging1 = changing2 = 1while changing1 or changing2:   # Iterates until no further changes occur in the image# Step 1changing1 = []rows, columns = Image_Thinned.shapefor x in range(1, rows - 1):for y in range(1, columns - 1):P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)if (Image_Thinned[x][y] == 1     and    # Condition 0: Point P1 in the object regions 2 <= sum(n) <= 6   and    # Condition 1: 2<= N(P1) <= 6transitions(n) == 1 and    # Condition 2: S(P1)=1  P2 * P4 * P6 == 0  and    # Condition 3   P4 * P6 * P8 == 0):         # Condition 4changing1.append((x,y))for x, y in changing1: Image_Thinned[x][y] = 0# Step 2changing2 = []for x in range(1, rows - 1):for y in range(1, columns - 1):P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, Image_Thinned)if (Image_Thinned[x][y] == 1   and        # Condition 02 <= sum(n) <= 6  and       # Condition 1transitions(n) == 1 and      # Condition 2P2 * P4 * P8 == 0 and       # Condition 3P2 * P6 * P8 == 0):            # Condition 4changing2.append((x,y))    for x, y in changing2: Image_Thinned[x][y] = 0return Image_Thinned
# 对染色体图像应用Zhang-Suen细化算法
BW_Skeleton = zhangSuen(BW_Original)
import numpy as np
BW_Skeleton = np.invert(BW_Skeleton)
# 显示细化结果
fig, ax = plt.subplots(1, 2)
ax1, ax2 = ax.ravel()
ax1.imshow(img, cmap=plt.cm.gray)
ax1.set_title('Original binary image')
ax1.axis('off')
ax2.imshow(BW_Skeleton, cmap=plt.cm.gray)
ax2.set_title('Skeleton of the image')
ax2.axis('off')
plt.savefig('E://straight//3 thinned.png')
plt.show()

# 生成骨架图像并保存
Skeleton = np.ones((BW_Skeleton.shape[0],BW_Skeleton.shape[1]),np.uint8) *255 #生成一个空灰度图像
BW_Skeleton = BW_Skeleton + 0
for i in range(BW_Skeleton.shape[0]):for j in range(BW_Skeleton.shape[1]):if BW_Skeleton[i][j] == 0:Skeleton[i][j] = 0plt.axis('off')
plt.imshow(Skeleton, cmap=plt.cm.gray)import imageio
imageio.imwrite('E://straight//3 Skeleton.png', Skeleton)

# 利用opencv在染色体图像上画出中轴线
import numpy as np
import cv2 as cvimg = cv.imread('E://straight//3 Skeleton.png')
binaryImg = cv.Canny(img,100,200)
h = cv.findContours(binaryImg, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
contours = h[1]Org_img =  cv.imread('E://straight//3.png')
cv.drawContours(Org_img, contours, -1,(0,0,255),3)plt.axis('off')
plt.imshow(Org_img, cmap=plt.cm.gray)cv.imwrite('E://straight//3 contours.png',Org_img)

Zhang-Suen细化算法提取中轴线(Python)相关推荐

  1. 改进Zhang Suen细化算法的C#实现

    本文主要实现了改进Zhang Suen细化算法的C#实现,相关论文 :"牟少敏,杜海洋,苏平,查绪恒,陈光艺.一种改进的快速并行细化算法[J].微电子学与计算机,2013,(第1期)&quo ...

  2. C#:实现Zhang Suen细化算法(附完整源码)

    C#:实现Zhang Suen细化算法 #region xqpublic Bitmap zhang_thinimage_improve(Bitmap bmp){int imgWidth = bmp.W ...

  3. 图像处理之Zhang Suen细化算法

    在二值图像处理特别是OCR识别与匹配中,都要通过对字符进行细化以便获得图像的骨架,通过zhang-suen细化算法获得图像,作为图像的特征之一,常用来作为识别或者模式匹配. 一:算法介绍 Zhang- ...

  4. zhang 快速并行细化方法_一种改进的Zhang并行图像细化算法的制作方法

    本发明涉及图像处理技术,具体涉及一种改进的Zhang并行图像细化算法. 背景技术: 图像细化是将图像的线条从多像素宽度减少到单位像素宽度,简称骨架化.细化效果的好坏直接影响后期图像处理的效果.对于二值 ...

  5. python图像线条提取_python3 图像细化(提取骨架线)

    图像细化_八连通法 图像细化 图像细化的方法 八连通-查表法 zhang的快速并行细化算法 八连通-查表法的改进 附上参考链接:https://www.cnblogs.com/xianglan/arc ...

  6. python图像算法,Zhang-Suen 图像细化算法python实现

    算法流程 首先要反转原图像,因为算法之后所有的操作都将0作为前景,将1作为背景. 中心像素x_1(x,y)的8-近邻定义如下所示: 考虑以下两个步骤 步骤1:执行光栅扫描并标记满足以下5个条件的所有像 ...

  7. 手指静脉细化算法过程原理解析 以及python实现细化算法

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8672489.html 文中的一些图片以及思想很多都是参考https://www.cnblogs ...

  8. 3D骨架(细化)提取算法C++

    网上的细化算法大部分都是对2D图像进行提取,对3D图像进行细化代码介绍太少了.目前比较流行的有两个版本. matlat版本 Skeleton3D. ITK版本 itkBinaryThinningIma ...

  9. OpenCV python GrabCut算法提取前景背景图片

    OpenCV python GrabCut算法提取前景背景图片 处理图片:[lena_color.jpg] 手动mask[mask.jpg] import numpy as np import cv2 ...

最新文章

  1. Farseer.net轻量级ORM开源框架 V1.x 入门篇:新版本说明
  2. 关于mysql的update、delete、和insert into能否使用别名问题
  3. Centos/RHEL上查看主板型号
  4. 1、Flutter_初体验_创建第一个应用_AndroidStudio_windows
  5. php写入rabbit速度,RabbitMQ 入门教程(PHP) 实现延迟功能
  6. 小米高管:已投大量精力研发手机AI芯片,造不造还没定
  7. win10分屏快捷键无法使用_Win10系统Win快捷键不能用怎么办_win10 Win快捷键无法使用如何解决-系统城...
  8. 计算机工程师英语简历模板,计算机软件工程师英文简历模板
  9. 教程|电脑PC微信多开
  10. 公共服务中,人脸识别的三类风险隐患与安全防护
  11. 是java运行时环境的缩写,java运行环境的英文缩写
  12. Allegro Design Entry CIS 和 Orcad Capture CIS 区别
  13. 阿里云物联网平台数据解析(python)
  14. 双拼和五笔输入法键盘位浮动贴图,适合初学者使用
  15. 知乎网的CSS命名规律研究
  16. python之emoji表情处理
  17. UML建模——活动图(Activity Diagram)
  18. 如何修改图片像素大小?调整图片大小的简单方法
  19. MTFCSGO准心设置
  20. NOIP2013提高组 day2

热门文章

  1. 在思科三层交换机配置网关的两种方式
  2. 【python】 根据身份证号计算患者真实年龄 完整版
  3. CentOS 7搭建SVN服务器
  4. 清华大学张敏老师,个性化推荐的基础与趋势,145页ppt
  5. 用html制作一个课程表
  6. 沉迷于图书馆无法自拔
  7. 主题和母版页 如何在web窗体调用操作母版页内容元素
  8. 游戏开发15课 微信小游戏自审报告
  9. 2020低压电工模拟考试及低压电工实操考试视频
  10. Java环境百度地图Api的使用