기존의 알려진 방법을 기초로 시도했다.
결론부터 말하면 기존 알고리즘으로는 아쉬운 부분이 존재한다. 제대로 만들기 위해서는 한 땀 한 땀 mesh 를 작성해야 할 필요가 있다.
Brain MRI 중 T1 TRA SE 이미지가 적당해서 이걸로 선택했다. 한 장씩 DICOM 저장해서 확인한다. 익명성을 위해서 UUID를 이용해 버리는 바람에 DICOM에 포함된 Image Position 정보를 이용해서 순서대로 정렬시켜야 한다. Image Position 의 3번째 값이 머리-> 꼬리 방향과 연관된 정보이다.
MRI에는 CT 처럼 HU 값이 없다. 그냥 바탕의 적당한 값을 기준으로 어두운 부분은 False 있는 부분은 True 형식으로 변환시켰다. 적절한 처리를 거치면 이렇게 얼굴의 윗 부분을 만들 수 있다.

이 Numpy matrix에서 점에 대한 정보만 있어야 한다. Copilot에서 물어봤더니 약간 수정해야 하지만 매우 편한 스크립트를 짜주었다.
points = []
for x in range(blk.shape[0]):
for y in range(blk.shape[1]):
for z in range(blk.shape[2]):
if blk[x, y, z] > 0:
points.append([x, y, z])
points = numpy.array(points)
Open3D 패키지를 이용해서 point cloud를 만들어 준다.
pcd = open3d.geometry.PointCloud()
pcd.points = open3d.utility.Vector3dVector(points)
mesh 를 만들기 위해서는 법선(normal)이 있어야 한다. 당연히 이 정보는 없으니까 만들어 주어야 한다. pcd.has_normals() 을 이용해서 normal 이 있는지 알 수 있다. 없으면 estimate_normals() 을 이용하여 만들어 줄 수도 있다.
if pcd.has_normals():
pcd.normals = ...
else:
pcd.estimate_normals()
BPA는 다음 처럼
## BPA
distances = pcd.compute_nearest_neighbor_distance()
radius = 10
bpa_mesh = open3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd, open3d.utility.DoubleVector([radius, radius * 2]))
print(open3d.io.write_triangle_mesh("/root/3D/head_bpa.ply", bpa_mesh))
Poisson은 다음 처럼
poisson_mesh, densities = open3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9)
bbox = pcd.get_axis_aligned_bounding_box()
p_mesh_crop = poisson_mesh.crop(bbox)

이런 느낌으로 mesh를 만들 수 있다. 위에서도 언급했지만 두 방법 모두 mesh가 빠지는 부분이 있다.