使用 C# 在 MVC 中将 Dicom 文件转换为标准图像格式(.jpeg, .png 等)






4.67/5 (4投票s)
我之前有一个医疗领域的项目,遇到了处理 Dicom 文件的一个大挑战。我的应用程序用户希望上传一个包含一些 DICOM 文件的 zip 文件,然后他们希望以图像格式查看它。因此,我以一个示例项目的形式分享我的努力成果。
引言
首先,写这篇文章标志着我在处理 MVC 中的 Dicom 文件这项任务上取得了成功。市面上有很多软件可以显示 Dicom 图像,但这是一个 Web 应用程序,浏览器不理解 DICOM 格式,所以我必须处理上传的 zip 文件,并将每个 DICOM 文件转换为 Jpeg 格式并在浏览器上显示。虽然互联网上有很多关于将 Dicom 文件转换为标准图像格式的项目(Code Project 也有文章),但没有一个项目满足我的要求,因为有些项目使用了已弃用的 DLL,或者有些项目受限于 Dicom 扩展名(*.*dcm*)。因此,我创建了一个可以转换任何 Dicom 文件(带或不带扩展名)为标准图像格式的项目。
背景
熟悉 Dicom 或在 Dicom 库方面遇到挑战的开发者会对此感兴趣。
运行项目的步骤
使用 Visual Studio 2012 或 2013 打开此项目并运行。它将显示 DicomSlider 控制器的 Index 页面。您将看到一个文件上传控件,单击浏览按钮,然后导航到项目文件夹本身,它有一个名为“*Sample Files*”的文件夹,打开该文件夹,您会找到一个 zip 文件,选择它并单击提交按钮。单击提交按钮后,它将处理 zip 文件夹中的每个文件,将其转换为 jpeg 文件,并在同一 Index 页面上显示。现在,让我们看看代码层面是如何实现的。
Using the Code
这是一个简单的无身份验证的 MVC 项目,只有一个控制器、两个操作和一个视图。您需要将两个 DLL 复制到您的项目中才能使此代码正常工作。我在此发布了完整的项目,因此您可以在项目的*bin*文件夹中找到这两个 DLL,名称为:**“*dicom.dll* 和 *dicom.native.dll*”。**
基本上,这个项目有一个视图,可以上传 zip 文件,并且同一个视图也显示 zip 处理的结果。它显示了从 Dicom 格式转换为 JPEG 的图像。那么,让我们一步一步地看一下代码。
1. 视图 (Index.cshtml)
该视图非常简单,只有一个浏览按钮用于上传 Dicom 文件的 zip 包,提交后,它将显示转换后的文件。
@model List<DicomSliderDemo.Models.SliderModel>
@{
ViewBag.Title = "Index";
}
@using (Html.BeginForm("UploadZip", "DicomSlider",
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr>
<input id="filePosted" name="filePosted" type="file" />
<input id="Submit1" type="submit" value="submit" />
</tr>
</table>
}
<div style="width:inherit;height:250PX">
@if (Model != null && Model.Count() > 0)
{
foreach (var pathModel in Model)
{
<div style="DISPLAY: BLOCK; FLOAT: left; WIDTH: 300PX;
height: 200PX; margin:10PX;border:2PX solid GRAY">
<img src="~/DicomSlider/DICOMIMG/@pathModel.Path"
id="@pathModel.Id" alt="" width="300" height="200" />
<label>@pathModel.Id</label>
</div>
}
}
</div>
所以您可以看到这个视图有一个列表类型的模型,这个列表将负责显示转换后的图像。它有一个表单,该表单被发布到“*DicomSlider*”控制器的“UploadZip
”操作。因此,当您单击提交按钮时,表单将带有文件上传控件中选定的文件发布到此操作。我们在*form*元素下有一个Div
,这个div
将负责显示转换后的文件。您可以看到一个img
标签,其src
指向我们根项目文件中的“*DICOMIMG*”文件夹。让我们在控制器层面看看如何使用此文件夹存储图像,因此让我们看一下 Controller 代码,基本上我们将查看“UploadZip
”操作。
2. 控制器
public class DicomSliderController : Controller
{
//
// GET: /DicomSlider/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult UploadZip(HttpPostedFileBase filePosted)
{
List<SliderModel> objModel = new List<SliderModel>();
try
{
objModel=uploadAndSaveZipFile(filePosted);
}
catch (Exception ex)
{ }
return View("Index", objModel);
}
public List<SliderModel> uploadAndSaveZipFile(HttpPostedFileBase objFile)
{
List<SliderModel> objModel = new List<SliderModel>();
try
{
string FilesPath = Server.MapPath("Dtest");
string ImagesPath = Server.MapPath("DICOMIMG");
DirectoryInfo objDirectory = new DirectoryInfo(FilesPath);
DirectoryInfo objDirectoryImg = new DirectoryInfo(ImagesPath);
if (!objDirectoryImg.Exists)
{
Directory.CreateDirectory(ImagesPath);
}
if (objDirectory.Exists)
{
foreach (System.IO.DirectoryInfo subDirectory in objDirectory.GetDirectories())
{
SetDirAttributesNormal(subDirectory);
subDirectory.Delete(true);
}
SetDirAttributesNormal(objDirectory);
objDirectory.Delete(true);
Directory.CreateDirectory(Server.MapPath("Dtest"));
}
ZipFile objZip = ZipFile.Read(objFile.InputStream);
objZip.ExtractAll(FilesPath);
string[] objFInfo = Directory.GetFiles(FilesPath +
"\\" + Path.GetFileNameWithoutExtension(objFile.FileName));
int i = 0;
foreach (var ofile in objFInfo)
{
try
{
var img = new DicomImage(ofile);
Bitmap bitmap = new Bitmap(img.RenderImage());
bitmap.Save(ImagesPath + "\\D" + i + ".jpg", ImageFormat.Jpeg);
i++;
}
catch (Exception ex)
{
}
}
objDirectory = new DirectoryInfo(FilesPath);
if (objDirectory.Exists)
{
foreach (System.IO.DirectoryInfo subDirectory in objDirectory.GetDirectories())
{
SetDirAttributesNormal(subDirectory);
subDirectory.Delete(true);
}
SetDirAttributesNormal(objDirectory);
objDirectory.Delete(true);
}
objDirectoryImg = new DirectoryInfo(ImagesPath);
objModel = objDirectoryImg.GetFiles().Select(x => new SliderModel
{
Id=x.Name,
Path = x.Name,
}).ToList();
}
catch (Exception ex)
{ }
return objModel;
}
[NonAction]
public void SetDirAttributesNormal(DirectoryInfo dir)
{
foreach (var subDirPath in dir.GetDirectories())
{
SetDirAttributesNormal(new DirectoryInfo(subDirPath.ToString()));
subDirPath.Attributes = FileAttributes.Normal;
}
foreach (var filePath in dir.GetFiles())
{
var file = new FileInfo(filePath.Directory + "/" + filePath.Name);
file.Attributes = FileAttributes.Normal;
}
}
}
您可以看到Controller
有四个方法,我将一步一步地进行描述。
- Index 操作:它负责提供文件上传和图像结果显示的页面。
- UploadZip 操作:这是提交操作,当您单击 Index 页面的提交按钮时将被调用。这是负责我们核心功能的操作,它处理 zip 文件并将 DICOM 文件转换为 JPEG 文件。因此,让我们看一下此操作中的重要代码行。
此操作期望“
HttpPostedFileBase
”对象,这是*System.Web*命名空间中包含用户上传文件的标准对象。它正在声明一个“
SliderModel
”列表。如果您查看此类,您会发现其中有两个属性:其中
Id
表示图像名称,Path
表示物理文件名。在我们的例子中,两者是相同的。接下来,它调用一个名为“
uploadAndSaveZipFile
”的函数,并将“HttpPostedFileBase
”对象传递进去,该函数最后返回一个“SliderModel
”列表,然后它返回“Index
”视图,并带有“SliderModel
”,我们已经用这种模型装饰了我们的Index
视图,以便它可以处理它。ID
Path
- uploadAndSaveZipFile 方法:此方法提取 zip 文件并逐个处理文件,将它们转换为 jpeg 文件格式。此函数在提取上传的 zip 文件之前会删除同名的 zip 文件(如果存在),最后,它会提供一个已转换图像的路径和名称列表。因此,让我们看看此方法中的重要代码行。
因此,在前两行中,它分别设置了解压的 zip 文件路径和用于存储已转换图像的文件夹路径。在“*Dtest*”目录中,它将解压 zip 文件,而“*DICOMIMG*”文件夹将存储已转换的图像。
因此,首先,我们检查 Image Directory 是否存在,如果不存在,则创建它。这是一个简单的代码,仅处理“DirectoryInfo
”类。
接下来,它检查“*Dtest*”目录是否存在,如果存在,则删除该文件夹及其文件,因为它可能包含旧文件。它首先循环遍历子目录并删除所有子目录,然后删除根文件夹。删除前要注意的一点是,它调用了一个名为“SetDirAttributesNormal
”的函数。此函数基本上会将文件属性设置为Normal
,以防文件是“ReadOnly
”文件,因为如果文件是只读的,则无法删除,您必须先更改其属性。删除现有目录后,它会创建一个新目录。
接下来,它通过传递上传文件的输入流创建一个“ZipFile
”对象。此调用来自*Ionic.Zip.dll*。创建对象后,它会将 zip 的所有文件解压到“*Dtest*”文件夹。
接下来,它获取“*Dtest*”文件夹中所有文件的列表,并提取不带扩展名的文件名。它遍历列表,现在到了转换部分。
var img = new DicomImage(ofile);
Bitmap bitmap = new Bitmap(img.RenderImage());
bitmap.Save(ImagesPath + "\\D" + i + ".jpg", ImageFormat.Jpeg);
在第一行中,它创建了一个“DicomImage
”类的对象,构造函数接受文件名并返回一个“DicomImage
”类的对象。在第二行中,我们创建了一个Bitmap
类的对象,构造函数接受“Image
”作为参数,因此我们使用“DicomImage
”对象并调用名为“RenderImage
”的方法,该方法返回一个“Image
”对象。然后,在最后一行,它将图像以 jpeg 格式保存在“*DICOMIMG*”文件夹中。
现在,它删除“*Dtest*”目录并返回已转换图像名称的列表。
这就是它将 Dicom 文件转换为 JPEG 文件的方式。
提交的代码可能有些粗糙,对此我表示抱歉,但它肯定会解决您的挑战。
感谢阅读本文,我已附上示例项目,您可以下载并查看。如果您对此文章有任何疑问,我随时为您解答。