新しい内視鏡画像ファイリングシステム

現在使用している内視鏡画像ファイリングシステムがもう限界とのことで新しいシステムが導入されることになりました。

最近では、内視鏡画像も dicom ファイルにするのがデフォルトのようで、コニカミノルタの UNITEA というシステムが導入されることになりました。

UNITEA から dicom ファイルを dcm4chee へ

UNITEA はそれ自体が pacs として機能するようで、そして 9 個のクライアントが設定できるので、クライアントから dicom ファイルを閲覧することができ、それだけでも小さな病院のニーズには十分だと思われます。

しかし、UNITEA ではファイルは dicom ファイルとして記録されているわけではないので、もしもコンピュータがクラッシュしたらそれまでです。

UNITEA から pacs アプリへ dicom ファイルのエクスポートは簡単にできるようなので、それを利用して以下のようにしようと考えました。

タスクとしては 3 つあります。

  • dicom ファイルのタグ情報を読み込んで、それをデータベース化する。
  • dicom ファイルを jpg ファイルに変換する
  • 変換した jpg ファイルを新しいファイル構造内にコピーする

dicom ファイルのタグ情報をデータベース化

「/var/www/html/DICOM」内にある dicom ファイルを処理します。

そのディレクトリを再帰的に検索し dicom ファイルのリストを作成して、タグ情報を読み込んで mysql に書き込みます。

データベースの examine テーブルの examID は unique にしてあるので、同じ examID であればデータは replace されます。


import os
import magic
import pydicom
import pymysql

class DCM_JPG():
 
    def __init__( self ):    
        self.dcmdir = '/var/www/html/DICOM'
        self.dcmarr = []
        self.host = 'localhost'
        self.user = 'root'
        self.password = 'pass'
        self.db = 'es'
        
    def dicomArr(self):       
        for root, dir, files in os.walk( self.dcmdir ):
            for file_ in files:
                full_path = os.path.join(root, file_)
                file_type = magic.from_file(full_path)
                if file_type == 'DICOM medical imaging data':
                    self.dcmarr.append(full_path)  
                    
    def getDicomInfo( self ):

        for eachFile in self.dcmarr:           
            ds = pydicom.read_file(eachFile)
            studyID = ds.StudyID
            patiendID = ds.PatientID
            birthdate = ds.PatientBirthDate
            patientName = ds.PatientName
            gender = ds.PatientSex
            studyDate = ds.StudyDate

            path = studyDate[:4] + '/' + studyDate[4:6] + '/' + studyDate[6:] + '/' + str(studyID)
            info = [ studyID, patiendID, birthdate, patientName, gender, studyDate, path ]
            self.insertDB(info)
            
    def insertDB( self, info ):
        conn = pymysql.connect(host=self.host,
            user=self.user,
            db=self.db,
            password=self.password,
            cursorclass=pymysql.cursors.DictCursor)
        try:
            with conn.cursor() as cursor:
                sql = "replace INTO examine ( examID, karteNo, birthdate, ptName, gender, studyDate, path ) VALUES ( %s, %s, %s, %s, %s, %s, %s )"
                cursor.execute( sql, info )
            conn.commit()
        finally:
            conn.close()

if __name__ == "__main__":   
    tojpg = DCM_JPG() 
    tojpg.dicomArr()
    tojpg.getDicomInfo()

dicom ファイルを jpg・png へ変換


import pydicom
from PIL import Image

file = pydicom.dcmread('sample.dcm')
img = file.pixel_array
pil_img = Image.fromarray(img)
pil_img.save('conv.jpg')

オリジナルの jpg ファイルは 222 KB ありましたが、dicom ファイルに変換してさらに jpg ファイルに変換すると 40 KB になります。

jpg じゃなくて png にすると 390 KB ですが、だからといってきれいに見えるわけではないようです。

UNITEAでは普通に jpg 変換できますが、Panasonic の Plissimo EX だとおかしなファイルが作成されます。

dicom ファイルを jpg に変換することは多分ないのでいいんですけどね。

ディレクトリを作成し jpg ファイルを保存

以下のように、年・月・日・検査IDというディレクトリを作成し、ファイル名は検査ID + 撮影時間としました。

年・月・日は検査施行日です。


.
└── 2018
    ├── 03
    │   └── 29
    │       └── 36227
    │           ├── 36227103517.jpg
    │           ├── 36227103521.jpg
    │           ├── 36227103603.jpg
    │           ├── 36227103627.jpg
    │           ├── 36227103636.jpg
    │           ├── 36227103645.jpg
    │           ├── 36227103658.jpg
    │           ├── 36227103753.jpg
    │           ├── 36227103947.jpg
    │           ├── 36227104118.jpg
    │           ├── 36227104150.jpg
    │           └── 36227104153.jpg
    └── 04
        └── 05
            └── 36333
                ├── 36333141353.jpg
                ├── 36333141421.jpg
                ├── 36333141437.jpg
                ├── 36333141524.jpg
                ├── 36333141536.jpg
                ├── 36333141623.jpg
                ├── 36333142140.jpg
                ├── 36333142416.jpg
                └── 36333142447.jpg

全プログラム

dcmjpg.py

import os
import magic
import pydicom
import pymysql
from PIL import Image

class DCM_JPG():
 
    def __init__( self ):    
        self.dcmdir = '/var/www/html/DICOM'
        self.dcmarr = []
        self.host = 'localhost'
        self.user = 'root'
        self.password = 'pass'
        self.db = 'es'
        
    def dicomArr(self):       
        for root, dir, files in os.walk( self.dcmdir ):
            for file_ in files:
                full_path = os.path.join(root, file_)
                file_type = magic.from_file(full_path)
                if file_type == 'DICOM medical imaging data':
                    self.dcmarr.append(full_path)  
                    
    def getDicomInfo( self ):
        for eachFile in self.dcmarr:           
            ds = pydicom.read_file(eachFile)
            studyID = ds.StudyID
            patiendID = ds.PatientID
            birthdate = ds.PatientBirthDate
            patientName = ds.PatientName
            gender = ds.PatientSex
            studyDate = ds.StudyDate

            path = studyDate[:4] + '/' + studyDate[4:6] + '/' + studyDate[6:] + '/' + str(studyID)
            info = [ studyID, patiendID, birthdate, patientName, gender, studyDate, path ]
            self.insertDB(info)
            
    def insertDB( self, info ):
        conn = pymysql.connect(host=self.host,
            user=self.user,
            db=self.db,
            password=self.password,
            cursorclass=pymysql.cursors.DictCursor)
        try:
            with conn.cursor() as cursor:
                sql = "replace INTO examine ( examID, karteNo, birthdate, ptName, gender, studyDate, path ) VALUES ( %s, %s, %s, %s, %s, %s, %s )"
                cursor.execute( sql, info )
            conn.commit()
        finally:
            conn.close()
            
    def createDir_convert( self ):
        for eachFile in self.dcmarr:           
            ds = pydicom.read_file(eachFile)
            studyID = ds.StudyID
            studyDate = ds.StudyDate
            aqtime = ds.AcquisitionTime
            arr = ds.pixel_array
            im = Image.fromarray(arr)            
            path = '/var/www/html/ES_jpg/' + studyDate[:4] + '/' + studyDate[4:6] + '/' + studyDate[6:] + '/' + str(studyID)
            os.makedirs( path, exist_ok=True)            
            jpgfn = path + '/' + str(studyID) + str(aqtime) + '.jpg'          
            im.save( jpgfn )
       
if __name__ == "__main__":   
    tojpg = DCM_JPG() 
    tojpg.dicomArr()
    tojpg.getDicomInfo()
    tojpg.createDir_convert()

studyID がない

UNITEA から dcm4chee へのファイル転送は簡単にできたのですが、それを jpg ファイルに変換して保存しようとするとエラーが出ます。

調べてみると、dicom ファイルに studyID と aquisition time が設定されていません。
aquisition time はともかく studyID がないのはとても不便です。

内視鏡データベースの中での検査に対する何らかの固有の識別名は必要です。
なくても力技でなんとかなるのですが、ユニークなIDがないと不便です。

dicom ファイルのタグ情報をいろいろ調べて、SOP Instance UID か Study Instance UID のどちらかを使えないかと思いました。

SOP Instance UID はその dicom ファイルの完全な ID で世界中でそのファイルだけに振られたもののはずです。
例えば以下のような感じです。


1.2.392.200036.9107.500.220.99001.20220621.163259.493

この数字列の中で「163259」という番号が、おそらくこの内視鏡検査に割り振られた番号です。

もう一つ、Study Instance UID というものもあります。


1.2.392.200059.10.2.107601092.1.1470

この中の「1470」という数字が、この検査の studyNo、つまり studyID です。

この2つの数字で「1470」の方を使うべきと思いますが、このままでは mmr の studyID とかぶってしまい、unique でなくなってしまいます。

そこで、過去の mmr の studyID を書き換えることにしました。

例えば、「1470」→「mmr_1470」という風にです。

mmr の studyID を一気に書き換える

mysql 上の es というデータベースの mmr というテーブルの studyID を「1470」→「mmr_1470」という風に書き換えます。


UPDATE mmr,
    (
        SELECT
        studyID AS tmpstudy, CONCAT( 'mmr_',studyID) AS tmpid
        FROM
        mmr
    ) tblB
SET mmr.studyID=tblB.tmpid
WHERE mmr.studyID=tblB.tmpstudy