天天看點

DICOM圖形轉換(一)-- CT&MR醫學圖像資料轉換RGBA圖像CT&MR醫學圖像資料轉換RGBA圖像

CT&MR醫學圖像資料轉換RGBA圖像

簡述

本文主要講述的是把一個CT或者MR的資料轉成RGBA圖像,不解釋dicom檔案的解析。文中的代碼涉及的是2種語言python和javascript,主要是項目需要,這裡就不再做代碼轉換。

DICOM關鍵的參數

Tag Name 說明
Meta資訊 TransferSyntaxUID 位元組排序,1.2.840.10008.1.2.2:大端排序,其他是小端排序
0x0020, 0x0032 ImagePositionPatient 指定圖像左上角的x,y和z坐标
0x0020, 0x0037 ImageOrientationPatient 指定相對于患者的第一行和第一列的方向餘弦
0x0020, 0x1041 SliceLocation 像面的相對位置,以毫米為機關,
0x0028, 0x0002 SamplesPerPixel 圖像中單獨平面的數量
0x0028, 0x0010 Rows 圖像中的行數
0x0028, 0x0011 Columns 圖像中的列數
0x0028, 0x0030 PixelSpacing 患者體内每個像素中心之間的實體距離,由數字對指定-相鄰行間距(定界符)和相鄰列間距,機關為mm
0x0028, 0x0100 BitsAllocated 為每個像素樣本配置設定的位數
0x0028, 0x1050 WindowCenter 視窗中心
0x0028, 0x1051 WindowWidth 視窗寬度
0x7fe0, 0x0010 PixelData 圖像資料

轉換資料

  • 判斷TransferSyntaxUID是大端排序,還是小端排序。大端排序的話位元組是正序讀取,小端排序位元組是反序讀取。
    判斷是否是小端排序
    def is_little_endian(dicom):
         is_little_endian = True
         transfer_syntax = dicom.file_meta.get("TransferSyntaxUID")
         if transfer_syntax == '1.2.840.10008.1.2.2':
             is_little_endian = False
     
         return is_little_endian
               
  • BitsAllocated表示多少位表示一個值,8位等于1個位元組,例如:32位等于4位元組
  • 根據TransferSyntaxUID和BitsAllocated把PixelData從位元組數組轉換為int數組,轉換後就是該ct的灰階圖
    def getPixelData(is_little_endian, BitsAllocated, PixelData):
        count = int(BitsAllocated / 8)
        newPixelData = []
    
        for i in range(0, len(PixelData), count):
            value = 0
            if is_little_endian:
                for j in range(count):
                    value = value | (PixelData[i + j] << j * 8)
            else:
                for j in range(count):
                    value = PixelData[i + j] | (value << j * 8)
    
            newPixelData.append(value)
    
        return newPixelData
               
  • 根據SamplesPerPixel對圖像資料進行轉換
    • 1表示是灰階圖資料,即1個數值表示圖像的顔色,圖像資料為灰階圖的資料的時候,需要根據 WindowWidth 和 WindowCenter計算灰階值的最大值grayEnd和最小值grayStart
      const windowWidth = ct.WindowWidth[ct.WindowWidth.length - 1];
      const windowCenter = ct.WindowCenter[ct.WindowCenter.length - 1];
      const grayStart = (windowCenter - windowWidth / 2);
      const grayEnd = (windowCenter + windowWidth / 2);
                 
    • 3表示是RGB資料,即3個數值表示圖像的顔色
  • 最後把圖像資料轉換成RGBA的圖像資料
    export function dicomToImageData(ct) {
    
      const Rows = ct.Rows; // 擷取:圖像的總行數,行分辨率
      const Columns = ct.Columns; // 擷取:圖像的總列數,列分辨率
    
    
      const PixelData = ct.PixelData; // 擷取:像素資訊
      const buffers = new Uint8ClampedArray(4 * Rows * Columns);
      let index = 0;
    
      const windowWidth = ct.WindowWidth[ct.WindowWidth.length - 1];
      const windowCenter = ct.WindowCenter[ct.WindowCenter.length - 1];
      const grayStart = (windowCenter - windowWidth / 2);
      const grayEnd = (windowCenter + windowWidth / 2);
    
      for (let i = 0; i < Rows; i++) {
        for (let j = 0; j < Columns; j++) {
          if (ct.SamplesPerPixel === 1) {
            let grayGDI;
            let gray = PixelData[i * Columns + j]; // 某個點的灰階值
            if (gray < grayStart) {
              grayGDI = 0;
            } else if (gray > grayEnd) {
              grayGDI = 255;
            } else {
              grayGDI = (gray - grayStart) * 255 / windowWidth;
            }
    
            if (grayGDI > 255) {
              grayGDI = 255;
            } else if (grayGDI < 0) {
              grayGDI = 0;
            }
            buffers[index++] = grayGDI;
            buffers[index++] = grayGDI;
            buffers[index++] = grayGDI;
            buffers[index++] = 255;
          } else if (ct.SamplesPerPixel === 3) {
            buffers[index++] = PixelData[index - 1];
            buffers[index++] = PixelData[index - 1];
            buffers[index++] = PixelData[index - 1];
            buffers[index++] = 255;
          }
        }
      }
      return new ImageData(buffers, Columns, Rows);
    }
               

這時候就已經都轉換完成,轉換好的是一個一維Columns * Rows * 4的RGBA圖像資料。

DICOM圖形轉換(一)-- CT&amp;MR醫學圖像資料轉換RGBA圖像CT&amp;MR醫學圖像資料轉換RGBA圖像