본문 바로가기

Languages&Library/Python

DICOM series에 object detection결과 그리기

워낙에 좋은 코드들이 많지만, 내가 사용하는 방법.

사실 결과에 따라서 항상 새로 코드를 짜는 편인데, 

이 방법은 ROI의 위치 확인용도로 사용한다.

 

딥러닝 결괏 값은 text파일에 (x1, y1, z1, x2, y2, z2) 이 순서로 좌표값을 저장하였다.

 

 

일반 jpg파일로 여러 장 저장할 수 있지만, case도 많고 1 case에 몇백 장씩 있으면 데이터 관리가 힘들다.

그래서 1개의 파일에 결과를 보기위해서 파일 포맷을 찾다가 nifti는 color값을 넣을 수가 없어서

(color값도 넣고 볼수있을수도 있지만, 난 도저히 찾아봐도 되지가 않았다)

 

그래서. mha 파일 포맷으로 저장하여 ImageJ를 이용하여 열어서 확인하는 방식으로 구성하였음.

 

import numpy as np
import SimpleITK as sidk
import os


# 실험에 사용한 window값을 가져왔는데 이 코드에서는 winodws[0]번째만 사용하였음
windows = [(500, 200), (700, 400), (1200, 400)]
def adjust_window(image, window):
    width = window[0]
    level = window[1]
    upper = level + width / 2
    lower = level - width / 2
    copied_image = image.clip(lower, upper)
    copied_image = copied_image - lower
    return (copied_image / (upper - lower)).astype('float32')

def get_matrix_from_txt(txt_path):
    f = open(txt_path, 'r')
    txt_matrix = list()
    while True:
        line = f.readline()
        if not line: break
        line = line.strip()
        line = line.split(',')
        line = list(map(int, line))
        txt_matrix.append(line)
    del line
    f.close()
    return txt_matrix

# +-1은 1pixel만 그리면 너무 작게 그려질까 걱정이 되서, 추가한 pixel임
# opencv를 사용해서 rect를 그리는 방법도 있는데, 그렇게 하면
# volume에서 이미지를 가져와서 그리고 다시 변환해줘야하는 번거로움이 있어서 이렇게 짯었다.
def draw_rectangle(matrix, image_vol, color):
    output_vol = image_vol.copy()
    for mat in matrix:
        z = mat[2]
        while z < mat[5]:
            x = mat[0]
            while x < mat[3]:
                for i in range(0, 3):
                    try:
                        output_vol[i][z][x][mat[1] - 1] = color[i]
                        output_vol[i][z][x][mat[1]] = color[i]
                        output_vol[i][z][x][mat[1] + 1] = color[i]
                    except:
                        print(mat[1])
                    try:
                        output_vol[i][z][x][mat[4] - 1] = color[i]
                        output_vol[i][z][x][mat[4]] = color[i]
                        output_vol[i][z][x][mat[4] + 1] = color[i]
                    except:
                        print(mat[4])
                x += 1
            y = mat[1]
            while y < mat[4]:
                for i in range(0, 3):
                    try:
                        output_vol[i][z][mat[0] - 1][y] = color[i]
                        output_vol[i][z][mat[0]][y] = color[i]
                        output_vol[i][z][mat[0] + 1][y] = color[i]
                    except:
                        print(mat[0])
                    try:
                        output_vol[i][z][mat[3] - 1][y] = color[i]
                        output_vol[i][z][mat[3]][y] = color[i]
                        output_vol[i][z][mat[3] + 1][y] = color[i]
                    except:
                        print(mat[3])
                y += 1
            z += 1

    return output_vol


def draw_numpy_gt_and_deep_result(img_dir, save_dir, gt, deep):
    deep_list_file = os.listdir(root_folder_deep)
    deep_list = [file for file in deep_list_file if file.endswith(".txt")]
    deep_list.sort()

    gt_file = os.listdir(gt)
    gt_list = [file for file in gt_file if file.endswith(".txt")]
    gt_list.sort()
	
    #python에서는 file을 읽어온 후 꼭 정렬이 필요함.

    for i in deep_list:
        deep_path = root_folder_deep + i
        deep_name = i.replace(root_folder_deep, '')
        img_path = img_dir + i.replace('.txt', '.npy')
        if not os.path.isfile(img_path):
            continue
        
        # DICOM을 매번 불러오는 것은 itk사용도 해야하고 시간이 많이걸려서
        # 학습데이터 만들때, 원본 값을 그대로 저장한 후에 필요할 때 이것만 불러와서 사용한다.
        img_vol = np.load(img_path)
        img = adjust_window(img_vol, windows[0])
        
        # rectangle 종류를 구분하기 위해서 color 채널값으로 만들어줘야하므로, stack을 하여
        # 3 channel로 만들어주는 과정
        img_3channel = np.stack((img, img, img), axis=0)
        for j in json_list:
            json_path = json_gt + j
            human_path = human_gt + j
            gt_name = j.replace(json_gt, '')
            if os.path.isfile(human_path) and deep_name == gt_name:
                print(deep_name)
                deep_matrix = get_matrix_from_txt(deep_path)
                gt_matrix = get_matrix_from_txt(json_path)
                red = [1, 0, 0]
                green = [0, 1, 0]
                blue = [0, 0, 1]
                rect_img = draw_rectangle(deep_matrix, img_3channel, red)
                rect_img = draw_rectangle(gt_matrix, rect_img, green)
                
                # float type 그대로 저장하면 용량이 너무 많이 차지하므로,
                # 8bit로 바꿔줘서 저장한다.
                rect_img *= 255.0
                rect_img = rect_img.astype('uint8')
                
                # 무식하게 channel값을 계속 뒤로 미뤄주는데
                # 혹시나 실수하여 x,y 좌표값이 바뀌거나 하는 문제 때문에 이렇게 사용함
                # 꼭 이렇게 할필요는 없음 다만 mha로 저장할때는 
                # 맨 마지막 shape처럼 나오도록해야 함
                # rect_img.shape[3,z,x,y]
                rect_img = np.moveaxis(rect_img, 0, 1)
                # rect_img.shape[z,3,x,y]
                rect_img = np.moveaxis(rect_img, 1, 2)
                # rect_img.shape[z,x,3,y]
                rect_img = np.moveaxis(rect_img, 2, 3)
                # rect_img.shape[z,x,y,3]
                
                output_img = sitk.GetImageFromArray(rect_img)
                output_path = save_dir + i.replace('.txt', '.mha')
                
                # sitk를 이용하여 저장한다. itk도 사용가능하지만, 귀찮아서 sitk를 사용했음
                sitk.WriteImage(output_img, output_path)
                break

 

 

내 코드를 보니 이 그림이 떠올랐음.....

'Languages&Library > Python' 카테고리의 다른 글

동영상 클립 만들기 / 원하는 구간 자르기  (0) 2023.04.19