{学海无涯}【基于VTK的三维建模】——1.Dicom文件的读取与显示

来源:互联网 发布:淘宝买家账户体检中心 编辑:程序博客网 时间:2024/04/27 23:10

学习中,记笔记是个好习惯。

似乎有点晚了,不过没关系,从现在开始!


这次要做的项目是老师给的,要从一批Dicom文件中读取头部模型的数据并进行三维建模。先是读取头部CT图片,再是读取头部MIR(核磁共振成像)图片。不过医学图像都是存储为Dicom格式。


今天完成的效果图如下:



Dicom 文件不仅包含图像,还包含医院信息,患者信息等许多信息,格式等内容不再赘述,我用了一个写好的类CDicom,在文档中创建指针CDicom* m_pDicomCreate。利用该指针,完成相应的操作。


一.读取

代码如下

void CControlView::GetPictures(CString FolderDir){CMainFrame* pMainFrame=(CMainFrame*)::AfxGetMainWnd();if (pMainFrame ==NULL){return;}CImageView* pView= static_cast<CImageView*>(pMainFrame->m_wndSplitter.GetPane(0,0));CDicom002Doc* pDoc=(CDicom002Doc*)pMainFrame->GetActiveDocument();if (pView == NULL)return;if (pDoc == NULL)return;CFileFind FFind;CString szDir=FolderDir;if(szDir.Right(1)!='\\')szDir+='\\';szDir+="001.dcm";BOOL Ressult=FFind.FindFile(szDir);if(Ressult){Ressult=FFind.FindNextFile();pDoc->m_pDicomCreate=new CDicom;ASSERT(pDoc->m_pDicomCreate!= NULL);pDoc->m_pDicomCreate->read_dicom(szDir);//以下都是通过指针得到Dicom文件中的各种信息pDoc->m_dRowPixelSpacing = pDoc->m_pDicomCreate->pixel_spacing.x;//x spacepDoc->m_dColPixelSpacing = pDoc->m_pDicomCreate->pixel_spacing.y;//y space      pDoc->m_dThickness = pDoc->m_pDicomCreate->slice_thickness;pDoc->m_nRow = pDoc->m_pDicomCreate->rows;//pDoc->m_nColumn = pDoc->m_pDicomCreate->columns;//pDoc->m_nLayer = (int)( pDoc->m_nFileNumberCreate* pDoc->m_dThickness/ pDoc->m_dRowPixelSpacing);pDoc->m_nPixels = pDoc->m_nRow* pDoc->m_nColumn;//一层图像的像素点数pDoc->m_nWW = pDoc->m_pDicomCreate->window_width;//从m_pDicomCreate中得到窗宽窗位pDoc->m_nWC = pDoc->m_pDicomCreate->window_center;pDoc->m_pDicomBuffer=pDoc->m_pDicomCreate->ct_value;//你妹的,找半天,这是ct图像缓冲存放的地方,非常关键pDoc->m_strModality = pDoc->m_pDicomCreate->modality;if(pDoc->m_nRow > pDoc->m_nColumn)pDoc->m_nNumN = pDoc->m_nRow;//m_nNumNCreate 导航视图缓冲的长和宽elsepDoc->m_nNumN = pDoc->m_nColumn;UpdateData(TRUE);m_id=pDoc->m_pDicomCreate->patient_id;m_name=pDoc->m_pDicomCreate->patient_name;m_date=pDoc->m_pDicomCreate->patient_birth_date;m_sex=pDoc->m_pDicomCreate->patient_sex;UpdateData(FALSE);pDoc->m_flagPic=true;}}

学到了很多东西,你必须进入程序仔细研读。比如说CDicom这个类中,缓冲图像是存在ct_value中的。


二.数据转化

我们得到的数据是存放在缓冲区的,不能够直接显示。必须转化为位图格式,才能够被操作识别。代码如下:

void CDicom002Doc::MakeDicomBMP(){//if(m_pBMPN!=NULL)//{//delete [] m_pBMPN;//m_pBMPN=NULL;//}m_pBMPN=new unsigned char[m_nRow*m_nColumn];memset(m_pBMPN, 0, m_nRow*m_nColumn*sizeof(unsigned char));TransferToBMP();//if(m_pBMPNs!=NULL)//存储经简单处理过的bmp图  如旋转一定角度  纯数据//{//delete [] m_pBMPNs;//m_pBMPNs=NULL;//}double b=double(m_nColumn)/m_nRow;//int bytoa;//int ay;if (b == 1)//htow==1{//ay=m_nRow;m_pBMPNs=new unsigned char[m_nColumn* m_nRow];memset(m_pBMPNs, 0, m_nColumn* m_nRow* sizeof(unsigned char));//预置为黑色for(int x=0; x< m_nRow; x++)for(int y=0; y< m_nColumn; y++)m_pBMPNs[y* m_nRow+ x]=m_pBMPN[y* m_nRow+ x];//m_pBMPTs=m_pBMPT;}}void CDicom002Doc::TransferToBMP(){int i,j;double ratio,wMin,wMax;ratio=255.0/m_nWW;wMin=m_nWC-(m_nWW>>1);wMax=m_nWC+(m_nWW>>1);for ( i= 0; i< m_nRow; i++)   for ( j= 0; j< m_nColumn; j++)   {      if (m_pDicomBuffer[j* m_nRow+ i] >= (wMax))   m_pBMPN[(m_nColumn-1-j)* m_nRow+ i] = 255;      else if (m_pDicomBuffer[j* m_nRow + i] < (wMin))   m_pBMPN[(m_nColumn-1-j)* m_nRow+ i] = 0;      else   m_pBMPN[(m_nColumn-1-j)* m_nRow+ i] =unsigned char( ratio*(m_pDicomBuffer[j* m_nRow + i]-(wMin)) );   }//m_nRow方向数据颠倒}

其实m_pBMPN[(m_nColumn-1-j)* m_nRow+ i] =unsigned char( ratio*(m_pDicomBuffer[j* m_nRow + i]-(wMin)) );

这个原理,我还是不太懂,如果有哪位同学碰巧知道,请不吝赐教。


三.显示

显示同样利用了现成的类CSTDIB,用来对位图进行操作的类。


void CImageView::DrawDicom(CDC *pDC){CRect rect;CDicom002Doc* pDoc = static_cast<CDicom002Doc* >(GetDocument());CBrush m_Brush(RGB(0,0,0));pDoc->MakeDicomBMP();//if(pDoc->m_pdib!=NULL)//{//delete pDoc->m_pdib;//pDoc->m_pdib=NULL;//}pDoc->m_pdib=new CSTDIB;rect=CRect(10,10,360,360);pDoc->m_pdib->CreateDib256(pDoc->m_pBMPNs,pDoc->m_nNumN,pDoc->m_nNumN);////根据外部图像数据创建256色(灰度)DIB (宽度可以不是4的倍数)pDoc->m_pdib->DrawEx(pDC,rect.Width(),rect.Height(),rect.left,rect.top);}


恩,大体是这样,后面还有很多工作要做。

大概列个提纲:

1.读取一个文件夹中的所有图片数据,存放在数组里

2.利用VTK对数据进行建模。形成3D图像



原创粉丝点击