ray 에서 로그를 모두 확인하고자 할 때에는 위 내용이 필요하다고 한다. 이것을 선언하는 위치가 중요하다.
import os
os.environ['RAY_DEDUP_LOGS'] = '0'
import ray
ray 를 불러오기 전에 해야 한다.

ray 에서 로그를 모두 확인하고자 할 때에는 위 내용이 필요하다고 한다. 이것을 선언하는 위치가 중요하다.
import os
os.environ['RAY_DEDUP_LOGS'] = '0'
import ray
ray 를 불러오기 전에 해야 한다.

안 될때는 안 되더니, 될 때는 또 금방 된다. 이번에는 copilot이 도움이 컸다. 몇몇 부분에서 수학적인 계산이 필요한 부분이 있었는데 관련 부분을 충분히 입력하면 거의 동작 가능한 수준에서 만들어 준다.

더 촘촘하게 mesh를 구성해보려고 했는데 2가지 이유로 안했다. 첫 번째로는 메모리 부분이다. 사소한 부분일 것 같기는 한데 numpy에서 오류가 난다. 두 번째는 현재 가로 해상도는 대략 최대 1.6mm 이다. 표면이 거칠기는 한데 그것보다는 thickness가 더 큰 영향을 미친다고 본다.

Blender에서 불러온 다음 표면을 살짝 부드럽게 해주면 좀 더 그럴듯하다.
콧구멍과 귓볼 처럼 굴곡이 심한 부분은 잘 안된다. 캡처 사진에서는 잘 안 보이는데 콧구멍이 5개쯤 된다.


이 논문에서 영감을 받아서 진행했었다. 이제 저 아래쪽 그림을 보고 너무 겁먹지 않아도 좋을 듯 하다. 그 이유는 아래쪽 이미지처럼 잘 복원하려면 MRI 화질이 매우 매우 좋아야 한다. 작정하고 복원을 위한 시퀀스를 구성하지 않은 이상 짜부러진 얼굴이 나올 가능성이 높다.
기존의 알려진 방법을 기초로 시도했다.
결론부터 말하면 기존 알고리즘으로는 아쉬운 부분이 존재한다. 제대로 만들기 위해서는 한 땀 한 땀 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가 빠지는 부분이 있다.
한 땀 한 땀 만들어야 하나 고민하고 있었는데 누군가가 이미 구현해둔 방법들이 있는 것을 알게 되었다.
jupyterlab 환경에서는 안된 것 같다. 좀 더 확인해 볼 필요가 있다. 얼핏 검색해 본 바에 의하면 numpy 버전을 1.대로 낮추어 야 할 필요가 있는 것 같다.
Numpy 버전을 낮추는 방법은 다시 설치를 하면 된다.
pip install numpy==1.26.4 --break-system-packages
