把DICOM文件中的图像部分提取到BMP文件的函数

本文介绍了一种将DICOM格式医学图像转换为BMP格式的方法。通过解析DICOM文件的元数据,如像素数量、位深等信息,并处理可能存在的压缩格式,最终将图像数据写入BMP文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先建立一个对话框矿类CDicomBMPDlg ,然后写函数

void CDicomBMPDlg::ConvertDicomToBMP()
{

 short int nCols = 0, nRows = 0;
    short int nBitsAllocated, nSamplesPerPixel = 1;
 short int nHighBit = 0;
 float fWindowWidth = 0, fWindowCenter = 0 , fRescaleSlope = 1, fRescaleIntercept = 0;
 BOOL bIsSigned = FALSE;

 BOOL bGroup2Done = FALSE, bGroup28Done = FALSE, bPixelDataDone = FALSE;

 int nBytesP = 0;
 int nFrameSize = 0;
 long int nLength;
 const char *pszFileName = m_strFileName.GetBuffer(3);
 char szPhotometric[32]="", szTemp[32]="", szTransferSyntaxUID[80]="";

 BOOL bImplicitVR = TRUE;
 COMPRESSION_MODE nCompressionMode = COMPRESS_NONE;
 DATA_ENDIAN nDataEndian = LITTLE_ENDIAN;
 int i;
 int nBytes;


   FILE *fp;
   char *pData = 0;
   short int gTag, eTag;
   int nNumFrames = 1;

   fp = fopen(pszFileName, "rb");
   if (!fp)
    {
       AfxMessageBox("Failed to open file for read.");
       return;
    }

    while(fread(&gTag, sizeof(short), 1, fp) == 1)
    {
    if (nDataEndian == BIG_ENDIAN)
   SwapWord((char *) &gTag, 1);

      switch(gTag)
      {
    case 0x0002: // Meta header.

   if (bGroup2Done)
      break;

   fread(&eTag, sizeof(short), 1, fp);
   // Meta header is always in Little Endian Explicit VR syntax.
         switch(eTag)
          {
             case 0x0010: // Transfer syntax UID
     if (readString(fp, szTransferSyntaxUID, FALSE, LITTLE_ENDIAN) != 0)
      break;

    // Check data endian.
    if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.2")) // Explicit VR Big Endian
     nDataEndian = BIG_ENDIAN; // Big Endian
    else
     nDataEndian = LITTLE_ENDIAN; // Little Endian

    // Check if it is implicit VR or Explicit VR
    if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2")) // Implicit VR Little Endian
     bImplicitVR = TRUE; // Implicit VR
    else
     bImplicitVR = FALSE; // Explicit VR

    // Parse the encapsulation/compression
    if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.50")) // JPEG lossy
     nCompressionMode = COMPRESS_JPEGLOSSY;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.51")) // JPEG lossy 12bit
     nCompressionMode = COMPRESS_JPEGLOSSY12BIT;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.70")) // JPEG lossless first order prediction
     nCompressionMode = COMPRESS_JPEGLOSSLESS;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.57")) // JPEG lossless process 14
     nCompressionMode = COMPRESS_JPEGLOSSLESS2;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.5")) // RLE
     nCompressionMode = COMPRESS_RLE;

    bGroup2Done = TRUE;

   break;

   }
   break;

       case 0x0008: // First non-Meta group
         fread(&eTag, sizeof(short), 1, fp);
       if (nDataEndian == BIG_ENDIAN)
      SwapWord((char *) &eTag, 1);

   if ((eTag == 0x0005) || (eTag == 0x0008))
    bGroup2Done = TRUE;
   break;

       case 0x0028: // Image pixel data info group
         fread(&eTag, sizeof(short), 1, fp);

   if (bGroup28Done)
      break;

       if (nDataEndian == BIG_ENDIAN)
      SwapWord((char *) &eTag, 1);

         switch(eTag)
          {
            case 0x0002: // Samples per Pixel
    nSamplesPerPixel = readUS(fp, nDataEndian);
               break;

            case 0x0004:  // Photometric Interpolation
    readString(fp, szPhotometric, bImplicitVR, nDataEndian);
               break;

            case 0x0008:  // Number of frames
    nNumFrames = readIS(fp, bImplicitVR, nDataEndian);
               break;

             case 0x0010: // Rows
      nRows = readUS(fp, nDataEndian);
               break;

            case 0x0011: // Columns
      nCols = readUS(fp, nDataEndian);
               break;

            case 0x0100: // Bits allocated
      nBitsAllocated = readUS(fp, nDataEndian);
               break;

   case 0x0102: // High bit
    nHighBit = readUS(fp, nDataEndian);
    break;

   case 0x0103: // Is signed?
    bIsSigned = readUS(fp, nDataEndian);
    break;

   case 0x1050: // Window Center
    fWindowCenter = readDS(fp, bImplicitVR, nDataEndian);
    break;

   case 0x1051: // Window Width
    fWindowWidth = readDS(fp, bImplicitVR, nDataEndian);
    break;

   case 0x1052: // Rescale intercept
    fRescaleIntercept = readDS(fp, bImplicitVR, nDataEndian);
    break;

   case 0x1053: // Rescale slope
    fRescaleSlope = readDS(fp, bImplicitVR, nDataEndian);
    bGroup28Done = TRUE;
    break;

   default:
    // do nothing
    break;
           }
         break;
        case 0x7fe0:
         fread(&eTag, sizeof(short), 1, fp);
   if (bPixelDataDone)
    break;

       if (nDataEndian == BIG_ENDIAN)
      SwapWord((char *) &eTag, 1);

         if (eTag == 0x0010)
         {
    nBytesP = nSamplesPerPixel*nBitsAllocated/8;
    nFrameSize = nCols * nRows * nBytesP;
    nLength = nNumFrames * nFrameSize;

    // Don't try to parse grup 2 and group 28 any more
    bGroup2Done = TRUE;
    bGroup28Done = TRUE;

    // Parse pixel data
    switch(nCompressionMode)
    {
    case COMPRESS_NONE:
     pData = new char[nLength + 16];
     fseek(fp, 4, SEEK_CUR); // Skip 4 bytes (length bytes)
     nBytes = fread(pData, 1, nLength, fp);

     if (nBytes != nLength)
     {
      AfxMessageBox("Failed to read all pixel data.");
     }
     bPixelDataDone = TRUE;
     break;

    case COMPRESS_RLE:
     AfxMessageBox("RLE compression not supported at this moment");
     // To do: 
     //   1. Read the offset table.
     //   2. Read and uncompress RLE image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain RLE decompression source code is in Papyrus and dcmtk.
     break;
    case COMPRESS_JPEGLOSSY:
     AfxMessageBox("JPEG lossy compression not supported at this moment");
     // To do: 
     //   1. Read the offset table
     //   2. Read and uncompress JPEG image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain JPEG decompression source code is in Papyrus and dcmtk.
     break;
    case COMPRESS_JPEGLOSSY12BIT:
     AfxMessageBox("JPEG lossy 12-bit compression not supported at this moment");
     // To do: 
     //   1. Read the offset table
     //   2. Read and uncompress JPEG image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain JPEG decompression source code is in Papyrus and dcmtk.
     break;
    case COMPRESS_JPEGLOSSLESS:
    case COMPRESS_JPEGLOSSLESS2:
     AfxMessageBox("JPEG lossless compression not supported at this moment");
     // To do: 
     //   1. Read the offset table
     //   2. Read and uncompress JPEG image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain JPEG decompression source code is in Papyrus and dcmtk.
     break;
    }

         }
         break;
   }

   if (pData)
    break; // We are done.
    }

  fclose(fp);

  if (pData) // Have we got the pixel data?
  {
   // Need to do byte swap?
   if (nDataEndian == BIG_ENDIAN)
   {
    if (nBitsAllocated > 8)
   SwapWord(pData, nLength/2);
   }

   if (nBitsAllocated > 8)
   {
    // We need to convert it to 8-bit.
    char *pNewData;

    pNewData = convertTo8Bit(pData, nLength/2, bIsSigned, nHighBit,
     fRescaleSlope, fRescaleIntercept, fWindowCenter, fWindowWidth);

    // Use the new 8-bit data.
    if (pNewData)
    {
     delete [] pData;
     pData = pNewData;
     nBytesP = 1;
     nFrameSize /= 2;

     nLength /= 2;
    }
   }

   // Write BMP files
   for (i = 0; i < nNumFrames; i++)
  WriteBMPFile(pData + nFrameSize*i, nFrameSize, nCols, nRows, nBytesP, szPhotometric, i+1);

   // Free the memory.
   delete [] pData;

   AfxMessageBox("Images successfully converted into BMP.");

  }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

benna

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值