Сортировка изображений по метаданным? - PullRequest
0 голосов
/ 01 октября 2019

Я пытаюсь отсортировать слова разных субъектов в соответствующие папки на основе их PatientID. В текущем каталоге есть все условия для всех предметов без сортировки. Я могу просмотреть каталог dicom и сгруппировать субъекты по их PatientID и подсчитать, сколько dicoms имеет каждый субъект. Можно ли скопировать или переместить каталоги в другой каталог и отсортировать их в папке на основе их PatientID.

код:

os.listdir('\\dicoms')

device = torch.device("cuda")
print(device)
input_path = '\\dicoms\\'

ds_columns = ['ID', 'PatientID', 'Modality', 'StudyInstance',
                'SeriesInstance', 'PhotoInterpretation', 'Position0',
                'Position1', 'Position2', 'Orientation0', 'Orientation1',
                'Orientation2', 'Orientation3', 'Orientation4', 'Orientation5',
                'PixelSpacing0', 'PixelSpacing1']

def extract_dicom_features(ds):
    ds_items = [ds.SOPInstanceUID,
                ds.PatientID,
                ds.Modality,
                ds.StudyInstanceUID,
                ds.SeriesInstanceUID,
                ds.PhotometricInterpretation,
                ds.ImagePositionPatient,
                ds.ImageOrientationPatient,
                ds.PixelSpacing]
    line = []
    for item in ds_items:
        if type(item) is pydicom.multival.MultiValue:
            line += [float(x) for x in item]
        else:
            line.append(item)
    return line

list_img = os.listdir(input_path + 'imgs')
print(len(list_img))
df_features = []
for img in tqdm.tqdm(list_img):
    img_path = input_path + 'imgs/' + img
    ds = pydicom.read_file(img_path)
    df_features.append(extract_dicom_features(ds))
df_features = pd.DataFrame(df_features, columns=ds_columns)

df_features.head()
df_features.to_csv('\\meta.csv')
print(Counter(df_features['PatientID']))

пример метаданных:

,ID,PatientID,Modality,StudyInstance,SeriesInstance,PhotoInterpretation,Position0,Position1,Position2,Orientation0,Orientation1,Orientation2,Orientation3,Orientation4,Orientation5,PixelSpacing0,PixelSpacing1


0,ID_000012eaf,ID_f15c0eee,CT,ID_30ea2b02d4,ID_0ab5820b2a,MONOCHROME2,-125.0,-115.89798,77.970825,1.0,0.0,0.0,0.0,0.927184,-0.374607,0.488281,0.488281

пример вывода счетчика:

Counter({'ID_19702df6': 28, 'ID_b799ed34': 26, 'ID_e3523464': 26, 'ID_cd9169c2': 26, 'ID_e326a8a4': 24, 'ID_45da90cb': 24, 'ID_99e4f787': 24, 'ID_df751e93': 24, 'ID_929a5b39': 20})

Я добавил следующий код вПопробуйте отсортировать изображения в подкаталогах, но я сталкиваюсь с ошибкой:

dest_path = input_path+'imageProcessDir'
counter = 0
for index, rows in df_features.iterrows():
    filename = basename(rows['ID'])
    image = cv2.imread(input_path+rows['ID'])
    counter=counter+1
    fold = rows['PatientID']+"/"
    dest_fold = dest_path+fold
    cv2.imwrite(dest_fold+"/"+filename+ "_" +str(counter)+".dcm", img)

ошибка:

Traceback (most recent call last):
  File "ct_move.py", line 77, in <module>
    cv2.imwrite(dest_fold+"/"+filename+ "_" +str(counter)+".dcm", img)
TypeError: Expected cv::UMat for argument 'img'

Ответы [ 3 ]

1 голос
/ 02 октября 2019

Чтобы решить вашу проблему, использование opencv здесь излишне. Если все, что вам нужно сделать, это переместить изображения dicom из одного места в другое в файловой системе, вы можете использовать os.rename или shutil.move, если вы находитесь в UNIX-подобной системе. Если вы не изменяете содержимое изображения, это более чистые и быстрые решения.

Я заметил две мелочи в вашем последнем блоке кода:

  • Я думаю, что заметил, что вы хотитепеременная fold с префиксом "/" вместо суффикса для путей работы.

  • Кроме того, счетчик будет продолжать увеличиваться во всех выражениях, где я думаю, что вы хотитеувеличивать его для каждого субъекта (я предполагаю, что df_features будет отсортирован здесь по PatientID, если нет, возможно, вы могли бы использовать класс Counter).

dest_path = input_path+'imageProcessDir'
counter = 0
prev_fold = '/' + df_features.loc[0, 'PatientID']
for index, rows in df_features.iterrows():
    filename = basename(rows['ID'])
    counter=counter + 1
    fold = '/' + rows['PatientID']
    dest_fold = dest_path + fold
    out_file = dest_fold + "/" + filename + "_" + str(counter) + ".dcm"
    os.rename(input_path + rows['ID'], out_file)
    if fold != prev_fold:
        counter = 0  # reset when the PatientID changes
    prev_fold = fold

Я бы также использовал os.path.join для обработки путей в файловой системе вместо добавления "/" ко всему:

fold = rows['PatientID']
dest_fold = os.path.join(dest_path, fold)

, так как я думаю, что есть также проблема с путем к входному файлу: input_path + rows['ID']

edit:

Это избавление от использования '/' и вставка os.path.join

dest_path = os.path.join(input_path, 'imageProcessDir')
counter = 0
prev_fold = df_features.loc[0, 'PatientID']
for index, rows in df_features.iterrows():
    filename = basename(rows['ID'])
    counter=counter + 1
    fold = rows['PatientID']
    dest_fold = os.path.join(dest_path, fold)
    os.makedirs(dest_fold, exist_ok=True)  # make sure target folder exists
    out_file = os.path.join(dest_fold, filename + "_" + str(counter) + ".dcm")
    os.rename(os.path.join(input_path, rows['ID']), out_file)
    if fold != prev_fold:
        counter = 0  # reset when the PatientID changes
    prev_fold = fold

Также обратите вниманиечто os.rename(os.path.join(input_path, rows['ID']), out_file) может потребоваться os.rename(os.path.join(input_path, rows['ID'] + '.dcm'), out_file)

Если это не слишком много, вы можете сделать резервную копиюваших файлов, прежде чем пытаться это сделать, чтобы убедиться, что вы получите то, что хотите!

0 голосов
/ 04 октября 2019

Спасибо, я решил проблему с вашей помощью.

Решение:

os.listdir('directory')
device = torch.device("cuda")
print(device)
input_path = 'directory\\'

ds_columns = ['ID', 'PatientID', 'Modality', 'StudyInstance',
                'SeriesInstance', 'PhotoInterpretation', 'Position0',
                'Position1', 'Position2', 'Orientation0', 'Orientation1',
                'Orientation2', 'Orientation3', 'Orientation4', 'Orientation5',
                'PixelSpacing0', 'PixelSpacing1']

def extract_dicom_features(ds):
    ds_items = [ds.SOPInstanceUID,
                ds.PatientID,
                ds.Modality,
                ds.StudyInstanceUID,
                ds.SeriesInstanceUID,
                ds.PhotometricInterpretation,
                ds.ImagePositionPatient,
                ds.ImageOrientationPatient,
                ds.PixelSpacing]
    line = []
    for item in ds_items:
        if type(item) is pydicom.multival.MultiValue:
            line += [float(x) for x in item]
        else:
            line.append(item)
    return line

list_img = os.listdir(input_path)
print(len(list_img))
print('***********')
print(list_img)
print('***********')

df_features = []
for img in tqdm.tqdm(list_img):
    img_path = input_path + img
    ds = pydicom.read_file(img_path)
    df_features.append(extract_dicom_features(ds))
df_features = pd.DataFrame(df_features, columns=ds_columns)
print(df_features)
print('***********')
df_features.head()
df_features.to_csv('\\test_meta.csv')
print(Counter(df_features['PatientID']))
print('***********')
df_features['ID'] = df_features['ID'].astype(str) + ".dcm"
print(df_features)
print('***********')

dest_path = '\\sorted'
counter = 0
prev_fold = '\\' + df_features.loc[0, 'PatientID']
for index, rows in df_features.iterrows():
    filename = basename(rows['ID'])
    counter=counter + 1
    fold = '\\' + rows['PatientID']
    dest_fold = dest_path + fold

    out_file = os.path.join(dest_fold, filename)
    print(out_file)
    print('-------------')
    if not os.path.exists(dest_fold):
        os.mkdir(dest_fold)
    os.rename(os.path.join(input_path, rows['ID']), out_file)
    if fold != prev_fold:
        counter = 0
    prev_fold = fold
0 голосов
/ 03 октября 2019

Я бы также для этого отменил резюме - это излишнее.

Попробуйте вместо этого pydicom .

Что бы я сделал для вашей проблемы (переместите всефайлы с одинаковым идентификатором пациента в свою папку и подсчитывают, сколько для каждого):

  1. получить список файлов dicom в виде списка (используйте glob.glob для поиска в каталоге и / или просто передачив полном списке файлов через argv)
  2. загрузить все эти файлы в список объектов файлов pydicom dicom (DataSets), так что-то вроде:
import pydicom

for fname in glob.glob(sys.argv[1], recursive=False):
    print("loading: {}".format(fname))
    files.append(pydicom.read_file(fname))
просмотрите этот список и переместите (при необходимости создайте новый каталог) этот файл. Итак, что-то вроде (не рабочий код - я не могу вспомнить, что методы модуля os я просто помещаю функцию в <>, просто показываю, как это сделать концептуально):
from collections import defaultdict
# dict for counting number of files for each patient ID
patient_id_count = defaultdict(lambda: 0)

for f in files:
    id = f.PatientID    # this gets the patient ID from the current file
    if os.<directory doesnt exist>(id):
        os.<create directory>(id)
    os.<move>(f.file_name, id)
    patient_id_count{id} += 1
...