PNG と JPG を Dicom (dcm) に変換する方法、当時踏んだ落とし穴 (Python 編)

        医療画像の一般的なデータ形式である Dicom は、医療 AI に深く関わっている学生にとっては避けては通れない落とし穴です。私はアルゴリズムの導入に根ざした初心者にすぎませんが。しかし、この種のデータにさらされることは避けられません。いいえ、最近アルゴリズムのクラスメートからアルゴリズムを受け取りました。テスト用の公開データ セットを見つける必要がありました。ただし、Dicom データ セットは一般的ではないため (追記: 1,000 枚の画像では十分ではありません。言葉を失います)、PNG および JPG タイプのデータ セットのみに焦点を当てることができます (PNG および JPG で直接トレーニングされたデータ セットを除く)。

        しかし、PNG や JPG データを Dicom に変換するのは簡単ではありません。注意しないと、「規格外の Dicom」が表示されます。インターネット上のチュートリアルもいくつか試しましたが、残念ながら、変換された Dicom は真っ黒か、認識できません。 C++ で書かれているため、コンパイルを何度も繰り返す必要があり、面倒です。また、既製の Dicom データを使用し、ピクセル データを PNG または JPG データに置き換えることも試しました。しかし、すべてが無駄でした!

        それ以来、私はひたすら勉強(東を写し、西を写す)し、PNG と JPG を Dicom に変換するこの Python バージョンを完成させました。

目次

1. Dicom データ形式の概要

2. PNG、JPG から Dicom へ (PNG を例にします)

3. Dicomのさらなる改善 

4.結果表示


1. Dicom データ形式の概要

        PNG、JPG タイプのデータを Dicom データに変換する前に、Dicom データの基本形式を簡単に理解する必要がある場合があります。

(1) プリアンブル: 重要ではありません。主に下位互換性とスケーラビリティのために数バイトが予約されています。

(2) プレフィックス: 重要ではありません。主なことは、ファイルが DICOM 標準に準拠しているかどうかを確認することです。プリアンブルとプレフィックスはオプションであり、DICOM ファイルには必須ではありません。

(3) ファイル メタ情報 (ファイル メタ情報ヘッダー):重要! ! ! ファイル メタ情報ヘッダーは DICOM ファイルの必要な部分であり、DICOM バージョン番号、ファイルのバイト順序、データ要素のエンコード方法などの重要な情報が含まれています。

(4) データ要素:重要! ! ! は、実際の医療画像と関連情報を含む DICOM ファイルの部分です。

2. PNG、JPG から Dicom へ (PNG を例にします)

        Dicom のデータ構造がわかったら、主要な部分の PNG と JPG を変換できます。早速、コードに移りましょう。次の分析を表示したくない場合は、main 関数のパスを変更するだけで済みます。

import os
import pydicom
from PIL import Image

def png_to_dicom(input_png_path, output_dcm_path, patient_name="Anonymous", study_description="PNG to DICOM"):
    for fileNames in os.listdir(input_png_path):
        input_filename = os.path.basename(fileNames).split('.')[0]
        output_filename = input_filename + ".dcm"
        input_filepath = input_png_path + fileNames
        output_dcmpath = output_dcm_path + output_filename

        # 读取PNG图像
        img = Image.open(input_filepath)

        # 将PNG图像转换为灰度图像(单通道)
        pixel_array = img.convert("L")

        # 创建一个空的FileDataset对象,并添加DICOM数据集元素
        ds = pydicom.dataset.FileDataset(output_dcm_path, {}, file_meta=pydicom.dataset.Dataset())  # 创建文件元信息头对象
        # 添加DICOM文件元信息头
        ds.file_meta.FileMetaInformationGroupLength = 184
        ds.file_meta.FileMetaInformationVersion = b'\x00\x01'
        ds.file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.1.1'
        ds.file_meta.MediaStorageSOPInstanceUID = '1.2.410.200048.2858.20230531153328.1.1.1'
        ds.file_meta.TransferSyntaxUID = '1.2.840.10008.1.2'
        ds.file_meta.ImplementationClassUID = '1.2.276.0.7230010.3.0.3.5.4'
        ds.file_meta.ImplementationVersionName = 'ANNET_DCMBK_100'

        # 添加DICOM数据集元素
        ds.PatientName = patient_name
        ds.StudyDescription = study_description
        ds.Columns, ds.Rows = img.size
        ds.SamplesPerPixel = 1
        ds.BitsAllocated = 8
        ds.BitsStored = 8
        ds.HighBit = 7
        ds.PixelRepresentation = 0
        # 数据显示格式
        ds.PhotometricInterpretation = "MONOCHROME2"
        ds.PixelData = pixel_array.tobytes()  # 直接使用灰度图像的字节数据

        # 保存DICOM数据集到文件
        ds.is_little_endian = True
        ds.is_implicit_VR = True  # 使用隐式VR

        ds.save_as(output_dcmpath)
        print(output_dcmpath)


if __name__ == "__main__":
    # 输入PNG图像路径和输出DICOM图像路径
    input_png_path = "Your_Input_PNG_Path"
    output_dcm_path = "Your_Output_Dicom_Path"

    # 将PNG转换为DICOM
    png_to_dicom(input_png_path, output_dcm_path)

コードのこの部分を詳しく分析してみましょう。

(1) FileMetaInformationGroupLength: ファイル メタ情報部分の長さを指定します。これはオプションですが、あまりにも法外にならないようにしてください。

(2) FileMetaInformationVersion: ファイルメタ情報部分のバージョン番号を示します。

(3) MediaStorageSOPClassUID: 画像のデータ型を定義します。各型には一意の UID ID があります。たとえば、「1.2.840.10008.5.1.4.1.1.1.1」は「デジタル X 線画像ストレージ - プレゼンテーション用」を表します。

(4) MediaStorageSOPClassUID: 特定の画像データ インスタンスを一意に識別します。

(5) TransferSyntaxUID: DICOM 画像データの伝送構文を表し、ネットワーク伝送におけるデータの符号化方式を指定します。各メソッドには一意の UID 識別があり、たとえば、「1.2.840.10008.1.2」は「Implicit VR Little Endian」を表します。

(6) ImplementationClassUID: DICOM 標準を実装するアプリケーションまたはデバイスを識別するために使用される一意の識別子。

(7) ImplementationVersionName: DICOM 標準を実装するアプリケーションまたはデバイスのバージョン名または識別。

        「この混乱した数字の意味をどうやって知ることができますか?」と疑問に思うかもしれませんが、賢明な私はすでにそれを考えています。まず、標準の Dicom データをランダムに選択し、次のコードを実行します。

import pydicom
dataset = pydicom.dcmread("Your_Dicom_Path", force=True)
print(dataset.file_meta)

        MediaStorageSOPClassUID と TransferSyntaxUID を変更したい場合は、対応する UID を自分で確認する必要があるため、何をしたいのかがわかっていない限り、以下の内容を自分で変更することはお勧めしません。する:

3. Dicomのさらなる改善 

         ハハハハ、これ以上あるとは思わなかった!実際、ステップ 2 を通じて、表示用の Dicom データ形式をすでに取得できます。しかし、それだけです。アルゴリズムをやりたい場合、または私と同じように、他の人のアルゴリズムを検証してください。そうですね、このステップは不可欠です。

        ステップ 2 では、ファイル メタ情報 (ファイル メタ情報ヘッダー) といくつかの DataElement (主にピクセル データ) を新しい Dicom に追加しました。したがって、この Dicom は正常に読み込んで閲覧することができます。ただし、アルゴリズムのトレーニングやアルゴリズムの検証に使用する場合は、この Dicom データの一意性を保証する必要があります。

        理解を容易にし、Dicom データの一意性を確保するために、新しい py ファイルを作成しました。

import os
import pydicom

# 源文件夹和目标文件夹路径
source_folder = 'Your_Input_Dicom_Path'
target_folder = 'Your_Output_Dicom_Path'

patient_pid = 20230726001
accession_number = 202307261001
study_uid = 2023072620001
seriesNumber = 1
seriesInstanceUID = "1.2.410.200048.2858.20230529094313.1"
modality = "CR"
pixelSpacing = [0.160145, 0.160114]
instanceNumber = 1
bodyPartExamined = "CHEST"

# 遍历源文件夹中的文件
for filename in os.listdir(source_folder):
    if filename.endswith('.dcm'):
        # 构建源文件路径和目标文件路径
        source_file = os.path.join(source_folder, filename)
        target_file = os.path.join(target_folder, filename)

        # 加载源DCM文件
        dcm_data = pydicom.dcmread(source_file, force=True)

        # 添加患者PID、Accession Number和Study UID等信息
        dcm_data.PatientID = str(patient_pid)
        dcm_data.AccessionNumber = str(accession_number)
        dcm_data.StudyInstanceUID = str(study_uid)
        dcm_data.SeriesNumber = seriesNumber
        dcm_data.SeriesInstanceUID = seriesInstanceUID
        dcm_data.Modality = modality
        dcm_data.PixelSpacing = pixelSpacing
        dcm_data.BodyPartExamined = bodyPartExamined
        dcm_data.InstanceNumber = instanceNumber

        # 将文件名作为患者名
        file_name_without_extension = os.path.splitext(filename)[0]
        dcm_data.PatientName = file_name_without_extension

        # 保存修改后的DCM文件到目标文件夹
        dcm_data.save_as(target_file)

        # 递增计数器
        patient_pid += 1
        accession_number += 1
        study_uid += 1
    else:
        print("error!")

同様に、コードの次の部分を詳細に分析してみましょう。

(1)patient_pid: 患者の一意の識別子です。任意に記述してください。

(2) accession_numbe: 患者の検査に割り当てられ、特定の検査または医用画像セットを一意に識別するための固有の識別番号。

(3)study_uid:医用画像研究に対応するIDです。任意に記述してください。

(4) seriesNumber: 画像が属するシリーズの番号を識別します。私のアプローチに従うことをお勧めします。

(5) seriesInstanceUID: 画像シリーズを一意に識別するため、私の方法に従うことをお勧めしますが、標準の Dicom を見つけて記述方法を参照することもできます。

(6) モダリティ: 画像を取得するために使用される画像モダリティ。私の方法に従うことをお勧めします。または、標準の Dicom を見つけてその記述方法を参照することもできます。

(7) PixelSpacing: 行方向と列方向のピクセルの物理的な間隔。私の方法に従うことをお勧めします。または、標準の Dicom を見つけてその書き方を参照することもできます。

(8)instanceNumber: 画像内の個々のインスタンスに割り当てられる一意の番号。通常、一連の画像を区別するために使用されます。お好きなように記述してください。

(9) bodyPartExaminated: 部分を確認し、実際の状況に応じて記述します。記述できなくても構いません。

4.結果表示

        言っておきたいのは、PNG、JPG、またはその他の種類のデータを Dicom に変換する際に、一定の損失が必然的に発生するということです。十分な Dicom データがある場合は、アルゴリズムのトレーニングでも検証でも Dicom を使用することをお勧めします (PNG による直接トレーニングを除く)。 PNG または JPG を Dicom に変換するのは、本当に無力な行為です。

おすすめ

転載: blog.csdn.net/m0_46303486/article/details/131938281