三维血管重建

原始图片数据如下(共100张):

如何求每个界面的最大内圆?求每幅图片中阴影各点到阴影边界的最小距离中的最大距离即为最大内圆的半径,通过这种思路可得到内圆圆心位置和半径,代码实现:

#coding=utf-8
import matplotlib.pyplot as plt
from skimage import io
import math
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# 在画3D的时候需要

def transfer_data(image_path):
    # get center points
    img = io.imread(image_path)
    points = []     # 存放图片中阴影的点信息
    bound = []      # 存放图片中阴影的边界点信息
    for x in range(img.shape[0]):
        for y in range(img.shape[1]):
            if img[x, y] == 0:
                points.append([x, y])  # 阴影点
                # 判断是否为阴影的边界
                if img[x - 1, y] > 0 or img[x + 1, y] > 0 or img[x, y - 1] > 0 or img[x, y + 1] > 0:
                    bound.append([x, y])  # 阴影边界
    return points, bound


def get_center_radius(image_path):
    points, bound = transfer_data(image_path)
    radius_list = []
    for point in points:
        min_radius = 1000
        for bound_point in bound:
            if min_radius <= 0:
                min_radius = 0
                break
            # 求阴影点到阴影边界的最小距离
            distance = math.sqrt((bound_point[0] - point[0]) ** 2
                                 + (bound_point[1] - point[1]) ** 2)
            if distance < min_radius:
                min_radius = distance

        radius_list.append([point[0], point[1], min_radius])
    max_radius = [0, 0, 0]
    # 在所有阴影点离边界的最小距离中求取最大距离,即为内圆半径
    for ele in radius_list:
        if ele[2] > max_radius[2]:
            max_radius = ele
    return max_radius

def parse_images():
    center_radius = []
    for i in range(100):
        image_path = 'images/'+str(i)+'.bmp'
        temp = get_center_radius(image_path)
        center_radius.append({'index': i, 'data': temp})
        print(image_path, temp)
    return center_radius

# 求出了100个离散的中心点
center_radius = parse_images()
print(center_radius)

求出结果为:

center_radius = [{'index': 0, 'data': [95, 256, 29.0]}, {'index': 1, 'data': [95, 256, 29.0]}, {'index': 2, 'data': [95, 256, 29.0]}, {'index': 3, 'data': [95, 256, 29.0]}, {'index': 4, 'data': [95, 256, 29.0]}, {'index': 5, 'data': [95, 256, 29.0]}, {'index': 6, 'data': [95, 256, 28.861739379323623]}, {'index': 7, 'data': [95, 257, 29.0]}, {'index': 8, 'data': [95, 257, 29.0]}, {'index': 9, 'data': [95, 257, 29.0]}, {'index': 10, 'data': [95, 257, 29.0]}, {'index': 11, 'data': [95, 258, 29.0]}, {'index': 12, 'data': [95, 258, 29.0]}, {'index': 13, 'data': [95, 258, 29.0]}, {'index': 14, 'data': [95, 259, 29.0]}, {'index': 15, 'data': [95, 260, 29.0]}, {'index': 16, 'data': [95, 260, 29.0]}, {'index': 17, 'data': [95, 261, 29.0]}, {'index': 18, 'data': [95, 262, 29.0]}, {'index': 19, 'data': [95, 263, 29.0]}, {'index': 20, 'data': [94, 266, 29.0]}, {'index': 21, 'data': [94, 267, 29.0]}, {'index': 22, 'data': [94, 268, 29.0]}, {'index': 23, 'data': [95, 267, 29.0]}, {'index': 24, 'data': [95, 276, 29.017236257093817]}, {'index': 25, 'data': [95, 275, 29.017236257093817]}, {'index': 26, 'data': [95, 275, 29.017236257093817]}, {'index': 27, 'data': [96, 285, 29.068883707497267]}, {'index': 28, 'data': [96, 285, 29.068883707497267]}, {'index': 29, 'data': [96, 284, 29.068883707497267]}, {'index': 30, 'data': [97, 291, 29.120439557122072]}, {'index': 31, 'data': [97, 291, 29.154759474226502]}, {'index': 32, 'data': [97, 291, 29.120439557122072]}, {'index': 33, 'data': [97, 291, 29.120439557122072]}, {'index': 34, 'data': [98, 296, 29.120439557122072]}, {'index': 35, 'data': [98, 296, 29.120439557122072]}, {'index': 36, 'data': [99, 300, 29.120439557122072]}, {'index': 37, 'data': [100, 304, 29.120439557122072]}, {'index': 38, 'data': [104, 316, 29.154759474226502]}, {'index': 39, 'data': [104, 316, 29.154759474226502]}, {'index': 40, 'data': [106, 321, 29.154759474226502]}, {'index': 41, 'data': [118, 344, 29.154759474226502]}, {'index': 42, 'data': [115, 339, 29.154759474226502]}, {'index': 43, 'data': [115, 339, 29.154759474226502]}, {'index': 44, 'data': [120, 347, 29.410882339705484]}, {'index': 45, 'data': [120, 347, 29.410882339705484]}, {'index': 46, 'data': [120, 347, 29.410882339705484]}, {'index': 47, 'data': [137, 368, 29.698484809834994]}, {'index': 48, 'data': [136, 367, 29.698484809834994]}, {'index': 49, 'data': [136, 367, 29.698484809834994]}, {'index': 50, 'data': [137, 368, 29.698484809834994]}, {'index': 51, 'data': [137, 368, 29.698484809834994]}, {'index': 52, 'data': [138, 369, 29.698484809834994]}, {'index': 53, 'data': [140, 371, 29.698484809834994]}, {'index': 54, 'data': [144, 375, 29.410882339705484]}, {'index': 55, 'data': [152, 382, 29.206163733020468]}, {'index': 56, 'data': [156, 385, 29.206163733020468]}, {'index': 57, 'data': [183, 402, 29.410882339705484]}, {'index': 58, 'data': [183, 402, 29.410882339705484]}, {'index': 59, 'data': [185, 403, 29.154759474226502]}, {'index': 60, 'data': [196, 408, 29.154759474226502]}, {'index': 61, 'data': [199, 409, 29.120439557122072]}, {'index': 62, 'data': [204, 411, 29.120439557122072]}, {'index': 63, 'data': [236, 419, 29.154759474226502]}, {'index': 64, 'data': [236, 419, 29.154759474226502]}, {'index': 65, 'data': [236, 419, 29.154759474226502]}, {'index': 66, 'data': [230, 418, 29.120439557122072]}, {'index': 67, 'data': [236, 419, 29.068883707497267]}, {'index': 68, 'data': [294, 419, 29.068883707497267]}, {'index': 69, 'data': [286, 420, 29.068883707497267]}, {'index': 70, 'data': [299, 418, 29.120439557122072]}, {'index': 71, 'data': [294, 419, 29.154759474226502]}, {'index': 72, 'data': [299, 418, 29.120439557122072]}, {'index': 73, 'data': [299, 418, 29.120439557122072]}, {'index': 74, 'data': [299, 418, 29.120439557122072]}, {'index': 75, 'data': [331, 409, 29.154759474226502]}, {'index': 76, 'data': [331, 409, 29.154759474226502]}, {'index': 77, 'data': [343, 404, 29.154759474226502]}, {'index': 78, 'data': [343, 404, 29.154759474226502]}, {'index': 79, 'data': [372, 387, 29.206163733020468]}, {'index': 80, 'data': [372, 387, 29.206163733020468]}, {'index': 81, 'data': [387, 375, 29.410882339705484]}, {'index': 82, 'data': [387, 375, 29.68164415931166]}, {'index': 83, 'data': [387, 375, 29.68164415931166]}, {'index': 84, 'data': [388, 374, 29.68164415931166]}, {'index': 85, 'data': [400, 362, 29.68164415931166]}, {'index': 86, 'data': [401, 361, 29.68164415931166]}, {'index': 87, 'data': [401, 361, 29.410882339705484]}, {'index': 88, 'data': [401, 361, 29.206163733020468]}, {'index': 89, 'data': [407, 354, 29.206163733020468]}, {'index': 90, 'data': [413, 346, 29.154759474226502]}, {'index': 91, 'data': [413, 346, 29.154759474226502]}, {'index': 92, 'data': [431, 314, 29.154759474226502]}, {'index': 93, 'data': [431, 314, 29.154759474226502]}, {'index': 94, 'data': [433, 309, 29.154759474226502]}, {'index': 95, 'data': [433, 309, 29.120439557122072]}, {'index': 96, 'data': [436, 301, 29.120439557122072]}, {'index': 97, 'data': [437, 298, 29.120439557122072]}, {'index': 98, 'data': [439, 291, 29.120439557122072]}, {'index': 99, 'data': [440, 287, 29.120439557122072]}]

说明:在结果中的index表示原始图片的序号,data表示图片内圆的圆心坐标和圆半径

{'index': 0, 'data': [95, 256, 29.0]}

表示图片0.bmp的圆心坐标为(95, 256) 半径为29.0

#coding=utf-8
import matplotlib.pyplot as plt
from skimage import io
import math
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# 在画3D的时候需要

# 使用100个离散的中心点,采用曲线拟合方式,得出x(z)与y(z)的曲线
center_radius = [{'index': 0, 'data': [95, 256, 29.0]}, {'index': 1, 'data': [95, 256, 29.0]}, {'index': 2, 'data': [95, 256, 29.0]}, {'index': 3, 'data': [95, 256, 29.0]}, {'index': 4, 'data': [95, 256, 29.0]}, {'index': 5, 'data': [95, 256, 29.0]}, {'index': 6, 'data': [95, 256, 28.861739379323623]}, {'index': 7, 'data': [95, 257, 29.0]}, {'index': 8, 'data': [95, 257, 29.0]}, {'index': 9, 'data': [95, 257, 29.0]}, {'index': 10, 'data': [95, 257, 29.0]}, {'index': 11, 'data': [95, 258, 29.0]}, {'index': 12, 'data': [95, 258, 29.0]}, {'index': 13, 'data': [95, 258, 29.0]}, {'index': 14, 'data': [95, 259, 29.0]}, {'index': 15, 'data': [95, 260, 29.0]}, {'index': 16, 'data': [95, 260, 29.0]}, {'index': 17, 'data': [95, 261, 29.0]}, {'index': 18, 'data': [95, 262, 29.0]}, {'index': 19, 'data': [95, 263, 29.0]}, {'index': 20, 'data': [94, 266, 29.0]}, {'index': 21, 'data': [94, 267, 29.0]}, {'index': 22, 'data': [94, 268, 29.0]}, {'index': 23, 'data': [95, 267, 29.0]}, {'index': 24, 'data': [95, 276, 29.017236257093817]}, {'index': 25, 'data': [95, 275, 29.017236257093817]}, {'index': 26, 'data': [95, 275, 29.017236257093817]}, {'index': 27, 'data': [96, 285, 29.068883707497267]}, {'index': 28, 'data': [96, 285, 29.068883707497267]}, {'index': 29, 'data': [96, 284, 29.068883707497267]}, {'index': 30, 'data': [97, 291, 29.120439557122072]}, {'index': 31, 'data': [97, 291, 29.154759474226502]}, {'index': 32, 'data': [97, 291, 29.120439557122072]}, {'index': 33, 'data': [97, 291, 29.120439557122072]}, {'index': 34, 'data': [98, 296, 29.120439557122072]}, {'index': 35, 'data': [98, 296, 29.120439557122072]}, {'index': 36, 'data': [99, 300, 29.120439557122072]}, {'index': 37, 'data': [100, 304, 29.120439557122072]}, {'index': 38, 'data': [104, 316, 29.154759474226502]}, {'index': 39, 'data': [104, 316, 29.154759474226502]}, {'index': 40, 'data': [106, 321, 29.154759474226502]}, {'index': 41, 'data': [118, 344, 29.154759474226502]}, {'index': 42, 'data': [115, 339, 29.154759474226502]}, {'index': 43, 'data': [115, 339, 29.154759474226502]}, {'index': 44, 'data': [120, 347, 29.410882339705484]}, {'index': 45, 'data': [120, 347, 29.410882339705484]}, {'index': 46, 'data': [120, 347, 29.410882339705484]}, {'index': 47, 'data': [137, 368, 29.698484809834994]}, {'index': 48, 'data': [136, 367, 29.698484809834994]}, {'index': 49, 'data': [136, 367, 29.698484809834994]}, {'index': 50, 'data': [137, 368, 29.698484809834994]}, {'index': 51, 'data': [137, 368, 29.698484809834994]}, {'index': 52, 'data': [138, 369, 29.698484809834994]}, {'index': 53, 'data': [140, 371, 29.698484809834994]}, {'index': 54, 'data': [144, 375, 29.410882339705484]}, {'index': 55, 'data': [152, 382, 29.206163733020468]}, {'index': 56, 'data': [156, 385, 29.206163733020468]}, {'index': 57, 'data': [183, 402, 29.410882339705484]}, {'index': 58, 'data': [183, 402, 29.410882339705484]}, {'index': 59, 'data': [185, 403, 29.154759474226502]}, {'index': 60, 'data': [196, 408, 29.154759474226502]}, {'index': 61, 'data': [199, 409, 29.120439557122072]}, {'index': 62, 'data': [204, 411, 29.120439557122072]}, {'index': 63, 'data': [236, 419, 29.154759474226502]}, {'index': 64, 'data': [236, 419, 29.154759474226502]}, {'index': 65, 'data': [236, 419, 29.154759474226502]}, {'index': 66, 'data': [230, 418, 29.120439557122072]}, {'index': 67, 'data': [236, 419, 29.068883707497267]}, {'index': 68, 'data': [294, 419, 29.068883707497267]}, {'index': 69, 'data': [286, 420, 29.068883707497267]}, {'index': 70, 'data': [299, 418, 29.120439557122072]}, {'index': 71, 'data': [294, 419, 29.154759474226502]}, {'index': 72, 'data': [299, 418, 29.120439557122072]}, {'index': 73, 'data': [299, 418, 29.120439557122072]}, {'index': 74, 'data': [299, 418, 29.120439557122072]}, {'index': 75, 'data': [331, 409, 29.154759474226502]}, {'index': 76, 'data': [331, 409, 29.154759474226502]}, {'index': 77, 'data': [343, 404, 29.154759474226502]}, {'index': 78, 'data': [343, 404, 29.154759474226502]}, {'index': 79, 'data': [372, 387, 29.206163733020468]}, {'index': 80, 'data': [372, 387, 29.206163733020468]}, {'index': 81, 'data': [387, 375, 29.410882339705484]}, {'index': 82, 'data': [387, 375, 29.68164415931166]}, {'index': 83, 'data': [387, 375, 29.68164415931166]}, {'index': 84, 'data': [388, 374, 29.68164415931166]}, {'index': 85, 'data': [400, 362, 29.68164415931166]}, {'index': 86, 'data': [401, 361, 29.68164415931166]}, {'index': 87, 'data': [401, 361, 29.410882339705484]}, {'index': 88, 'data': [401, 361, 29.206163733020468]}, {'index': 89, 'data': [407, 354, 29.206163733020468]}, {'index': 90, 'data': [413, 346, 29.154759474226502]}, {'index': 91, 'data': [413, 346, 29.154759474226502]}, {'index': 92, 'data': [431, 314, 29.154759474226502]}, {'index': 93, 'data': [431, 314, 29.154759474226502]}, {'index': 94, 'data': [433, 309, 29.154759474226502]}, {'index': 95, 'data': [433, 309, 29.120439557122072]}, {'index': 96, 'data': [436, 301, 29.120439557122072]}, {'index': 97, 'data': [437, 298, 29.120439557122072]}, {'index': 98, 'data': [439, 291, 29.120439557122072]}, {'index': 99, 'data': [440, 287, 29.120439557122072]}]
z_index = []
x_index = []
y_index = []
r_list = []
for item in center_radius:
    z_index.append(item['index'])
    x_index.append(item['data'][0])
    y_index.append(item['data'][1])
    r_list.append(item['data'][2])

radius = sum(r_list) / len(r_list)
# 采用多项式进行拟合x(z)与y(z)
z_array = np.array(z_index)
x_array = np.array(x_index)
y_array = np.array(y_index)

times = 3
x_z_p = np.polyfit(z_array, x_array, times)  # 用3次多项式拟合
y_z_p = np.polyfit(z_array, y_array, times)  # 用3次多项式拟合
x_z_func = np.poly1d(x_z_p)
y_z_func = np.poly1d(y_z_p)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
ax.plot(x_array, y_array, z_array)  # 画三维曲线

z_array = np.arange(0, 100, 0.01)
xvals = x_z_func(z_array)
yvals = y_z_func(z_array)
ax.plot(xvals, yvals, z_array, 'r.', markersize=2)  # 画三维曲线
plt.show()

采用拟合结果如图所示

最终选择7次方,绘制如图(将上面代码中的 markersize=2 改为 markersize=radius 即可)

原文地址:https://www.cnblogs.com/TheoryDance/p/7745580.html