本文参考网上大神的源码,在此基础上修改,适配Unity,并支持移动端,本文代码支持安卓端,ios端请各位自行适配,原理不变,只是在数据读取的方法上可以有点区别。
大神原贴:医学影像调窗技术 - assassinx - 博客园
Dicom格式文件解析器 - assassinx - 博客园
下面直接上源码。
public RawImage testimg;
public TextMeshProUGUI detext;
string fileName = "";
Dictionary<string, string> tags = new Dictionary<string, string>();//dicom文件中的标签
BinaryReader dicomFile = null;//dicom文件流
//文件元信息
//public Bitmap gdiImg;//转换后的gdi图像
private Texture2D dicomimg = null;
UInt32 fileHeadLen;//文件头长度
long fileHeadOffset;//文件数据开始位置
UInt32 pixDatalen;//像素数据长度
long pixDataOffset = 0;//像素数据开始位置
bool isLitteEndian = true;//是否小字节序(小端在前 、大端在前)
bool isExplicitVR = true;//有无VR
MemoryStream mstream;
//像素信息
int colors;//颜色数 RGB为3 黑白为1
//public int windowWith = 2048, windowCenter = 2048 / 2;//窗宽窗位
private int windowWith = 0, windowCenter = 0;//窗宽窗位
int rows, cols;
void Start()
{
#if UNITY_EDITOR
fileName = Application.dataPath + "/StreamingAssets/DicomImage" + "/test.dcm";
#elif UNITY_IPHONE
fileName = Application.dataPath +"/Raw/DicomImage"+"/test.dcm";
#elif UNITY_ANDROID
//fileName = Application.persistentDataPath + "/DicomImage"+"/test.dcm";
fileName = "jar:file://" + Application.dataPath + "!/assets/DicomImage"+"/test.dcm";
#endif
detext.text += fileName + "\n";
mstream = new MemoryStream();
UnityWebRequest request = UnityWebRequest.Get(fileName);
request.SendWebRequest();//读取数据
while (true)
{
if (request.downloadHandler.isDone)//是否读取完数据
{
mstream.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);
break;
}
}
readAndShow();
}
public void readAndShow()
{
if (fileName == string.Empty)
return;
dicomFile = new BinaryReader(mstream);
if(dicomFile == null)
detext.text += "dicomFile == null" + "\n";
//跳过128字节导言部分
dicomFile.BaseStream.Seek(128, SeekOrigin.Begin);
if (new string(dicomFile.ReadChars(4)) != "DICM")
{
//MessageBox.Show("没有dicom标识头,文件格式错误");
Debug.Log("没有dicom标识头,文件格式错误");
detext.text += "没有dicom标识头,文件格式错误" + "\n";
return;
}
else
{
detext.text += "DICM" + "\n";
}
tagRead();
getImg();
IDictionaryEnumerator enor = tags.GetEnumerator();
dicomFile.Close();
}
void tagRead()//不断读取所有tag 及其值 直到碰到图像数据 (7fe0 0010 )
{
detext.text += "tagRead" + "\n";
bool enDir = false;
int leve = 0;
StringBuilder folderData = new StringBuilder();//该死的文件夹标签
string folderTag = "";
while (dicomFile.BaseStream.Position + 6 < dicomFile.BaseStream.Length)
{
//读取tag
string tag = dicomFile.ReadUInt16().ToString("x4") + "," +
dicomFile.ReadUInt16().ToString("x4");
string VR = string.Empty;
UInt32 Len = 0;
//读取VR跟Len
//对OB OW SQ 要做特殊处理 先置两个字节0 然后4字节值长度
//------------------------------------------------------这些都是在读取VR一步被阻断的情况
if (tag.Substring(0, 4) == "0002")//文件头 特殊情况
{
//VR = new string(dicomFile.ReadChars(2));
VR = Encoding.Default.GetString(dicomFile.ReadBytes(2));
if (VR == "OB" || VR == "OW" || VR == "SQ" || VR == "OF" || VR == "UT" || VR == "UN")
{
dicomFile.BaseStream.Seek(2, SeekOrigin.Current);
Len = dicomFile.ReadUInt32();
}
else
Len = dicomFile.ReadUInt16();
}
else if (tag == "fffe,e000" || tag == &#