# Python - 图像的细化（骨架抽取）

### 2、骨架的获取

（1）基于烈火模拟

（2）基于最大圆盘

1.内部点不能删除

2.鼓励点不能删除

3.直线端点不能删除

4.如果P是边界点，去掉P后，如果连通分量不增加，则P可删除

### 3、代码实现

```#! /usr/bin/env python3
# -*- coding:utf-8 -*-

# Author   : Ma Yi
# Blog     : http://www.cnblogs.com/mayi0312/
# Date     : 2020-04-24
# Name     : test02
# Software : PyCharm
# Note     : 骨架抽取
import cv2
import copy

# 映射表
g_array = [0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0]

def thin(img):
"""
细化函数，根据算法，运算出中心点的对应值
:param img: 需要细化的图片（经过二值化处理的图片）
:return:
"""
h, w = img.shape
i_thin = copy.deepcopy(img)
for i in range(h):
for j in range(w):
if img[i, j] == 0:
a = [1] * 9
for k in range(3):
for l in range(3):
if -1 < (i - 1 + k) < h and -1 < (j - 1 + l) < w and i_thin[i - 1 + k, j - 1 + l] == 0:
a[k * 3 + l] = 0
i_sum = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128
i_thin[i, j] = g_array[i_sum] * 255

return i_thin

def to_binary(img):
"""
二值化函数，阈值根据图片的昏暗程序自己设定
:param img: 需要二值化的图片
:return:
"""
w, h = img.shape
i_two = copy.deepcopy(img)
for i in range(w):
for j in range(h):
if img[i, j] < 200:
i_two[i, j] = 0
else:
i_two[i, j] = 255

return i_two

# 入口函数
if __name__ == '__main__':
# 读取图片，并显示
img_binary = to_binary(image)
img_thin = thin(img_binary)
cv2.imshow("image", image)
cv2.imshow("img_binary", img_binary)
cv2.imshow("img_thin", img_thin)
cv2.waitKey(0)```

效果不是很好，来看一个最简单的事例：

```#! /usr/bin/env python3
# -*- coding:utf-8 -*-

# Author   : Ma Yi
# Blog     : http://www.cnblogs.com/mayi0312/
# Date     : 2020-04-24
# Name     : test02
# Software : PyCharm
# Note     : 图像抽取骨架
import cv2
import copy

# 映射表
l_array = [0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0]

def v_thin(img):
"""
细化函数，根据算法，运算出中心点的对应值
:param img: 需要细化的图片（经过二值化处理的图片）
:param array: 映射矩阵array
:return:
"""
h, w = img.shape
i_next = 1
for i in range(h):
for j in range(w):
if i_next == 0:
i_next = 1
else:
i_m = int(img[i, j - 1]) + int(img[i, j]) + int(img[i, j + 1]) if 0 < j < w - 1 else 1
if img[i, j] == 0 and i_m != 0:
a = [0] * 9
for k in range(3):
for l in range(3):
if -1 < (i - 1 + k) < h and -1 < (j - 1 + l) < w and img[i - 1 + k, j - 1 + l] == 255:
a[k * 3 + l] = 1
i_sum = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128
img[i, j] = l_array[i_sum] * 255
if l_array[i_sum] == 1:
i_next = 0

def h_thin(img):
"""
细化函数，根据算法，运算出中心点的对应值
:param img: 需要细化的图片（经过二值化处理的图片）
:param array: 映射矩阵array
:return:
"""
h, w = img.shape
i_next = 1
for j in range(w):
for i in range(h):
if i_next == 0:
i_next = 1
else:
i_m = int(img[i -1, j]) + int(img[i, j]) + int(img[i + 1, j]) if 0 < i < h - 1 else 1
if img[i, j] == 0 and i_m != 0:
a = [0] * 9
for k in range(3):
for l in range(3):
if -1 < (i - 1 + k) < h and -1 < (j - 1 + l) < w and img[i - 1 + k, j - 1 + l] == 255:
a[k * 3 + l] = 1
i_sum = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128
img[i, j] = l_array[i_sum] * 255
if l_array[i_sum] == 1:
i_next = 0

def xi_hua(img, num=10):
for i in range(num):
v_thin(img)
h_thin(img)

return img

def to_binary(img):
"""
二值化函数，阈值根据图片的昏暗程序自己设定
:param img: 需要二值化的图片
:return:
"""
w, h = img.shape
i_two = copy.deepcopy(img)
for i in range(w):
for j in range(h):
if img[i, j] < 200:
i_two[i, j] = 0
else:
i_two[i, j] = 255

return i_two

# 入口函数
if __name__ == '__main__':
# 读取图片，并显示
img_binary = to_binary(image)
cv2.imshow("image", image)
cv2.imshow("img_binary", img_binary)
img_thin = xi_hua(img_binary)
cv2.imshow("img_thin", img_thin)
cv2.waitKey(0)```

本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。