本系列教程是逐步徒手实现一个DICOM阅图软件,采用C++语言,基于MFC的对话框程序来实现。整个实现过程中尽量不用或者少用第三方库、非开源库,主打一个独立自主。
DICOM文件是医学影像标准文件,其组成方式比较简单,就是文件信息头+图像像素数据,这点和BMP图像非常类似,所以作为的教程的第一步,咱们先从实现BMP图像的加载与显示开始。
一、先制作一个BMP图像
打开画图软件,调整画面尺寸是512*512,图像内容任意,颜色选黑白
存储时需要图像存储为256色位图
这个一个8bit的图像,尺寸为512*512,则文件尺寸应该略大于262144( =512*512*1 ),观察生成文件尺寸为263222字节,符合要求。
二、创建一个MFC的对话框程序
其它步骤一路next下去即可。
三、显示图像前的准备工作
先在MFC窗口上删除多余文本框和按钮,然后添加一个“Picture Control”,将其属性中的“Type”改成"Owner Draw",属性“ID”改成"IDC_SHOWIMAGE",顾名思义,这个控件将是我们用来显示图像的窗口。
再在窗口资源上添加一个按钮,ID改成“IDC_LOADDATA”,Caption改成“加载”。
双击【加载】按钮,IDE会自动生成该按钮的点击函数。
四、BMP文件格式简单介绍
BMP文件由4部分组成:
1. BMP文件头:BITMAPFILEHEADER,长度14字节
2. 位图信息头:BITMAPINFOHEADER,长度40字节
3. 调色板:,长度由索引颜色数决定,如24位以上真彩则没有调色板。
4. 位图数据:长度为图像的长*宽*位数/8。
五、添加显示代码,显示图像
void CusDicomViewerDlg::OnBnClickedLoaddata( )
{
CString bmpFilename = L"E:\\TestBmp\\001.bmp"; // 手工制作的bmp文件安放目录
UCHAR* pBmpBuffer = NULL; // 文件的内容
int bufLength = 0; // 文件长度
CFile file; // 打开的文件
if ( file.Open( bmpFilename, CFile::modeRead|CFile::shareDenyNone) )
{
bufLength = ( int )file.GetLength( );
pBmpBuffer = new UCHAR[bufLength]; // 将文件全部导入内存
file.Read( pBmpBuffer, bufLength );
file.Close( );
}
BITMAPFILEHEADER* head = ( BITMAPFILEHEADER* )( pBmpBuffer ); // 直接指向文件头
BITMAPINFOHEADER* info = ( BITMAPINFOHEADER* )( pBmpBuffer + 14 ); // 直接指图像信息
RGBQUAD* rgbquad = ( RGBQUAD* )( pBmpBuffer + 14 + 40 ); //
// 图像预备显示
UCHAR* pPixelBuffer = pBmpBuffer + 14 + 40 + 256*4; // 直接指向像素数据
// 进行图像显示
CWnd* pWnd = GetDlgItem( IDC_SHOWIMAGE ); // 获取到要显示的控件
if ( pWnd == NULL )
return;
CRect rc;
pWnd->GetClientRect( &rc );
int imageWidth = rc.Width( );
int imageHeight = rc.Height( );
UINT32 *pShowImage = new UINT32[imageWidth*imageHeight]; // 创建一个要显示的内存区域
// 设置要显示的内容
for ( int y = 0; y < imageHeight; y++ )
{
for ( int x = 0; x < imageWidth; x++ )
{
UCHAR c = pPixelBuffer[ x + y * info->biWidth ]; // 取的BMP中每一个像素,为8bit数据
pShowImage[x + y * imageWidth] = RGB( c, c, c ); // 显示像素为32bit,因为灰度,所以3通道颜色一样。
}
}
CDC* pDC = pWnd->GetDC( );
CDC mMemDC;
mMemDC.CreateCompatibleDC( pDC ); // 创建一个内存dc,用于窗口图像重绘时不闪烁
mMemDC.SetBkMode( TRANSPARENT );
// 创建临时图像
CBitmap bitmap;
bitmap.CreateBitmap( imageWidth,imageHeight,1,
32, pShowImage );
CBitmap *pOldBitmap;
pOldBitmap = mMemDC.SelectObject( &bitmap );
pDC->BitBlt( 0, 0, imageWidth, imageHeight, &mMemDC, 0, 0, SRCCOPY ); // 窗口绘制
// 释放信息
bitmap.DeleteObject( );
pWnd->ReleaseDC( pDC );
// 释放内存
mMemDC.DeleteDC();
mMemDC.m_hDC = 0;
if ( pShowImage != NULL )
{
delete[] pShowImage;
pShowImage = NULL;
}
if ( pBmpBuffer != NULL )
{
delete[] pBmpBuffer;
pBmpBuffer = NULL;
}
}
这样,就徒手显示了一个BMP图像
下一篇: