PPTX DOCX XLSX PDF ODP
Aspose.Imaging  .NET
DICOM

通过 C# 对 DICOM 进行卡通化

使用服务器端 API 构建您自己的 .NET 应用程序来卡通化 DICOM 文件。

如何使用 C# 将 DICOM 文件卡通化

卡通效果具有固有的吸引力,常常唤起怀旧的童年记忆。几乎每一篇平面设计文章都将卡通图像作为基本元素。卡通化肖像、微调灯光、转换为黑白、尝试颜色、混合各种编辑技术以及制作复杂的图像效果都可以通过图像滤镜(例如AdjustBrightness、BinarizeFixed、Filter、ReplaceColor 和ApplyMask)来实现。这些滤镜可以应用于原始加载的照片。无论您的网页主题是什么,卡通风格的图像都适合用于插图目的。科学文章变得充满活力,而多样化的内容对用户更具吸引力,从而提高网站流量。为了卡通化 DICOM 文件,我们将使用 Aspose.Imaging for .NET API 是一个功能丰富、功能强大 易于使用的 C# 平台图像处理和转换 API。打开 NuGet 包管理器,搜索 Aspose.Imaging 并安装。您还可以从包管理器控制台使用以下命令。

包管理器控制台命令


PM> Install-Package Aspose.Imaging

通过 C# 对 DICOM 进行卡通化的步骤

你需要 aspose.imaging.dll 在您自己的环境中尝试以下工作流程。

  • 使用 Image.Load 方法加载 DICOM 文件 +卡通化图像;
  • 以 Aspose.Imaging 支持的格式将压缩图像保存到光盘

系统要求

所有主要操作系统都支持 .NET 的 Aspose.Imaging。只需确保您具有以下先决条件。

  • Microsoft Windows 或具有 .NET Framework、.NET Core、Windows 应用程序、ASP.NET Web 应用程序的兼容操作系统。
  • Microsoft Visual Studio 等开发环境。
  • 项目中引用的 Aspose.Imaging for .NET。
 

Cartoonify DICOM 图像 - .NET

using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Png;
using Aspose.Imaging.ImageFilters.FilterOptions;
using Aspose.Imaging.ImageOptions;
using Aspose.Imaging.Masking;
using Aspose.Imaging.Masking.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
string templatesFolder = @"c:\Users\USER\Downloads";
Cartoonify();
void Cartoonify()
{
FilterImages(image =>
{
using (var processedImage = new PngImage(image))
{
image.Resize(image.Width * 2, image.Height, ResizeType.LeftTopToLeftTop);
processedImage.Cartoonify();
var gr = new Graphics(image);
gr.DrawImage(processedImage, processedImage.Width, 0);
gr.DrawLine(new Pen(Color.DarkRed, 3), processedImage.Width, 0, processedImage.Width, image.Height);
}
}, "cartoonify");
}
string RasterizeVectorImage(string formatExt, string inputFile)
{
string outputFile = Path.Combine(templatesFolder, $"rasterized.{formatExt}.png");
using (var image = Image.Load(inputFile))
{
image.Save(outputFile, new PngOptions());
}
return outputFile;
}
void FilterImages(Action<RasterImage> doFilter, string filterName)
{
List<string> rasterFormats = new List<string>() { "jpg", "png", "bmp", "apng", "dicom",
"jp2", "j2k", "tga", "webp", "tif", "gif", "ico" };
List<string> vectorFormats = new List<string>() { "svg", "otg", "odg", "eps", "wmf", "emf", "wmz", "emz", "cmx", "cdr" };
List<string> allFormats = new List<string>(rasterFormats);
allFormats.AddRange(vectorFormats);
allFormats.ForEach(
formatExt =>
{
var inputFile = Path.Combine(templatesFolder, $"template.{formatExt}");
bool isVectorFormat = vectorFormats.IndexOf(formatExt) > -1;
//Need to rasterize vector formats before background remove
if (isVectorFormat)
{
inputFile = RasterizeVectorImage(formatExt, inputFile);
}
var outputFile = Path.Combine(templatesFolder, $"{filterName}_{formatExt}.png");
Console.WriteLine($"Processing {formatExt}");
using (var image = (RasterImage)Image.Load(inputFile))
{
doFilter(image);
//If image is multipage save each page to png to demonstrate results
if (image is IMultipageImage multiPage && multiPage.PageCount > 1)
{
for (var pageIndex = 0; pageIndex < multiPage.PageCount; pageIndex++)
{
string fileName = $"{filterName}_page{pageIndex}_{formatExt}.png";
multiPage.Pages[pageIndex].Save(templatesFolder + fileName, new PngOptions());
File.Delete(templatesFolder + fileName);
}
}
else
{
image.Save(outputFile, new PngOptions());
File.Delete(outputFile);
}
}
//Remove rasterized vector image
if (isVectorFormat)
{
File.Delete(inputFile);
}
}
);
}
static class ImageFilterExtensions
{
public static void Cartoonify(this RasterImage image)
{
using var outlines = image.DetectOutlines(Color.Black);
image.AdjustBrightness(30);
image.Filter(image.Bounds, new MedianFilterOptions(7));
var gr = new Graphics(image);
gr.DrawImage(outlines, Point.Empty);
}
public static RasterImage DetectOutlines(this RasterImage image, Color outlineColor)
{
var outlines = new PngImage(image);
outlines
.GetDataContext()
.ApplyConvolutionFilter(ConvolutionFilterOptions.Blur)
.ApplyConvolutionFilter(ConvolutionFilterOptions.Outline)
.ApplyData();
outlines.BinarizeFixed(30);
ImageMasking.ApplyMask(outlines, outlines, new MaskingOptions() { BackgroundReplacementColor = Color.Transparent });
outlines.ReplaceColor(Color.FromArgb(255, 255, 255), 0, outlineColor);
outlines.ApplyConvolutionFilter(ConvolutionFilterOptions.Blur);
return outlines;
}
public static RasterImage ApplyOperationToRasterImage(this RasterImage image, Action<RasterImage> operation)
{
if (image is IMultipageImage multipage)
{
foreach (var page in multipage.Pages)
{
operation.Invoke((RasterImage)page);
}
}
else
{
operation.Invoke(image);
}
return image;
}
public static RasterImage ApplyFilter(this RasterImage image, FilterOptionsBase filterOptions)
{
return image.ApplyOperationToRasterImage(img =>
{
img.Filter(img.Bounds, filterOptions);
});
}
public static RasterImage ApplyConvolutionFilter(this RasterImage image, ConvolutionFilterOptions filterOptions)
{
return image.ApplyOperationToRasterImage(img =>
{
var pixelsLoader = new ImagePixelsLoader(img.Bounds);
img.LoadPartialArgb32Pixels(img.Bounds, pixelsLoader);
var outBuffer = new PixelBuffer(img.Bounds, new int[img.Width * img.Height]);
ConvolutionFilter.DoFiltering(pixelsLoader.PixelsBuffer, outBuffer, filterOptions);
img.SaveArgb32Pixels(outBuffer.Rectangle, outBuffer.Pixels);
});
}
public static IImageDataContext GetDataContext(this RasterImage image)
{
IPixelBuffer GetImageBuffer(RasterImage img)
{
var pixelsLoader = new ImagePixelsLoader(img.Bounds);
img.LoadPartialArgb32Pixels(img.Bounds, pixelsLoader);
return pixelsLoader.PixelsBuffer;
}
if (image is IMultipageImage multipage)
{
return new MultipageDataContext(
multipage.Pages.Select(page => new ImageDataContext((RasterImage)page)
{
Buffer = GetImageBuffer((RasterImage)page)
}));
}
return new ImageDataContext(image)
{
Buffer = GetImageBuffer(image)
};
}
public static IImageDataContext ApplyToDataContext(this IImageDataContext dataContext,
Func<IPixelBuffer, IPixelBuffer> processor)
{
if (dataContext is MultipageDataContext multipage)
{
foreach (var context in multipage)
{
context.Buffer = processor.Invoke(context.Buffer);
}
}
if (dataContext is ImageDataContext imageDataContext)
{
imageDataContext.Buffer = processor.Invoke(imageDataContext.Buffer);
}
return dataContext;
}
public static IImageDataContext ApplyConvolutionFilter(this IImageDataContext dataContext,
ConvolutionFilterOptions filterOptions)
{
return dataContext.ApplyToDataContext(buffer =>
{
var outBuffer = new PixelBuffer(buffer.Rectangle, new int[buffer.Rectangle.Width * buffer.Rectangle.Height]);
ConvolutionFilter.DoFiltering(buffer, outBuffer, filterOptions);
return outBuffer;
});
}
}
class ConvolutionFilter
{
public static void DoFiltering(
IPixelBuffer inputBuffer,
IPixelBuffer outputBuffer,
ConvolutionFilterOptions options)
{
var factor = options.Factor;
var bias = options.Bias;
var kernel = options.Kernel;
var filterWidth = kernel.GetLength(1);
var filterCenter = (filterWidth - 1) / 2;
int x, y;
int filterX, filterY, filterPx, filterPy, filterYPos, pixel;
double r, g, b, kernelValue;
int top = inputBuffer.Rectangle.Top;
int bottom = inputBuffer.Rectangle.Bottom;
int left = inputBuffer.Rectangle.Left;
int right = inputBuffer.Rectangle.Right;
for (y = top; y < bottom; y++)
{
for (x = left; x < right; x++)
{
r = 0;
g = 0;
b = 0;
for (filterY = -filterCenter; filterY <= filterCenter; filterY++)
{
filterYPos = filterY + filterCenter;
filterPy = filterY + y;
if (filterPy >= top && filterPy < bottom)
{
for (filterX = -filterCenter; filterX <= filterCenter; filterX++)
{
filterPx = filterX + x;
if (filterPx >= left && filterPx < right)
{
kernelValue = kernel[filterYPos, filterX + filterCenter];
pixel = inputBuffer[filterPx, filterPy];
r += ((pixel >> 16) & 0xFF) * kernelValue;
g += ((pixel >> 8) & 0xFF) * kernelValue;
b += (pixel & 0xFF) * kernelValue;
}
}
}
}
r = (factor * r) + bias;
g = (factor * g) + bias;
b = (factor * b) + bias;
r = r > 255 ? 255 : (r < 0 ? 0 : r);
g = g > 255 ? 255 : (g < 0 ? 0 : g);
b = b > 255 ? 255 : (b < 0 ? 0 : b);
outputBuffer[x, y] = ((inputBuffer[x, y] >> 24) << 24) | ((byte)r << 16) | ((byte)g << 8) | (byte)b;
}
}
}
}
class ConvolutionFilterOptions
{
public double Factor { get; set; } = 1.0;
public int Bias { get; set; } = 0;
public double[,] Kernel { get; set; }
public static ConvolutionFilterOptions Blur
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { 1, 2, 1 }, { 2, 4, 2 }, { 1, 2, 1 } },
Factor = 0.25 * 0.25
};
}
}
public static ConvolutionFilterOptions Sharpen
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }
};
}
}
public static ConvolutionFilterOptions Emboss
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { -2, -1, 0 }, { -1, 1, 1 }, { 0, 1, 2 } }
};
}
}
public static ConvolutionFilterOptions Outline
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { -1, -1, -1 }, { -1, 8, -1 }, { -1, -1, -1 } }
};
}
}
public static ConvolutionFilterOptions BottomSobel
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } }
};
}
}
public static ConvolutionFilterOptions TopSobel
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }
};
}
}
public static ConvolutionFilterOptions LeftSobel
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { 1, 0, -1 }, { 2, 0, -2 }, { 1, 0, -1 } }
};
}
}
public static ConvolutionFilterOptions RightSobel
{
get
{
return new ConvolutionFilterOptions
{
Kernel = new double[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }
};
}
}
}
interface IImageDataContext
{
void ApplyData();
}
class ImageDataContext : IImageDataContext
{
public ImageDataContext(RasterImage image)
{
this.Image = image;
}
public RasterImage Image { get; }
public IPixelBuffer Buffer { get; set; }
public void ApplyData()
{
this.Buffer.SaveToImage(this.Image);
}
}
class MultipageDataContext : List<ImageDataContext>, IImageDataContext
{
public MultipageDataContext(IEnumerable<ImageDataContext> enumerable) : base(enumerable)
{
}
public void ApplyData()
{
foreach (var context in this)
{
context.ApplyData();
}
}
}
class ImagePixelsLoader : IPartialArgb32PixelLoader
{
public ImagePixelsLoader(Aspose.Imaging.Rectangle rectangle)
{
this.PixelsBuffer = new CompositePixelBuffer(rectangle);
}
public CompositePixelBuffer PixelsBuffer { get; }
public void Process(Aspose.Imaging.Rectangle pixelsRectangle, int[] pixels, Point start, Point end)
{
this.PixelsBuffer.AddPixels(pixelsRectangle, pixels);
}
}
interface IPixelBuffer
{
Aspose.Imaging.Rectangle Rectangle { get; }
int this[int x, int y]
{
get;
set;
}
void SaveToImage(RasterImage image);
}
class PixelBuffer : IPixelBuffer
{
public PixelBuffer(Aspose.Imaging.Rectangle rectangle, int[] pixels)
{
this.Rectangle = rectangle;
this.Pixels = pixels;
}
public Aspose.Imaging.Rectangle Rectangle { get; }
public int[] Pixels { get; }
public int this[int x, int y]
{
get => this.Pixels[this.GetIndex(x, y)];
set => this.Pixels[this.GetIndex(x, y)] = value;
}
public void SaveToImage(RasterImage image)
{
image.SaveArgb32Pixels(this.Rectangle, this.Pixels);
}
public bool Contains(int x, int y)
{
return this.Rectangle.Contains(x, y);
}
private int GetIndex(int x, int y)
{
x -= this.Rectangle.Left;
y -= this.Rectangle.Top;
return x + y * this.Rectangle.Width;
}
}
class CompositePixelBuffer : IPixelBuffer
{
private readonly List<PixelBuffer> _buffers = new List<PixelBuffer>();
public CompositePixelBuffer(Aspose.Imaging.Rectangle rectangle)
{
this.Rectangle = rectangle;
}
public Aspose.Imaging.Rectangle Rectangle { get; }
public int this[int x, int y]
{
get => this.GetBuffer(x, y)[x, y];
set => this.GetBuffer(x, y)[x, y] = value;
}
public void SaveToImage(RasterImage image)
{
foreach (var pixelBuffer in this._buffers)
{
pixelBuffer.SaveToImage(image);
}
}
public IEnumerable<PixelBuffer> Buffers => this._buffers;
public void AddPixels(Aspose.Imaging.Rectangle rectangle, int[] pixels)
{
if (this.Rectangle.IntersectsWith(rectangle))
{
this._buffers.Add(new PixelBuffer(rectangle, pixels));
}
}
private PixelBuffer GetBuffer(int x, int y)
{
return this._buffers.First(b => b.Contains(x, y));
}
}
 
  • 关于 .NET API 的 Aspose.Imaging

    Aspose.Imaging API 是一种图像处理解决方案,用于在应用程序中创建、修改、绘制或转换图像(照片)。它提供:跨平台的图像处理,包括但不限于各种图像格式之间的转换(包括统一的多页或多帧图像处理)、绘图等修改、使用图形基元、转换(调整大小、裁剪、翻转和旋转) 、二值化、灰度、调整)、高级图像处理功能(过滤、抖动、遮罩、去偏斜)和内存优化策略。它是一个独立的库,不依赖任何软件进行图像操作。可以在项目中使用原生 API 轻松添加高性能图像转换功能。这些是 100% 私有的本地 API,图像在您的服务器上处理。

    通过在线应用程序卡通化 DICOM

    通过访问我们的 Live Demos 网站 对 DICOM 文档进行卡通化。 现场演示有以下好处

      无需下载或设置任何东西
      无需编写任何代码
      只需上传您的 DICOM 文件并点击 "Cartoonify now" 按钮
      立即获取生成文件的下载链接

    DICOM 什么是 DICOM 文件格式

    DICOM 是 Digital Imaging and Communications in Medicine 的首字母缩写词,属于医学信息学领域。 DICOM 是文件格式定义和网络通信协议的结合。 DICOM 使用 .DCM 扩展名。 .DCM 以两种不同的格式存在,即格式 1.x 和格式 2.x。 DCM Format 1.x 还提供了两个普通版本和扩展版本。 DICOM 用于集成来自不同供应商的打印机、服务器、扫描仪等医疗成像设备,还包含每个患者的唯一识别数据。如果 DICOM 文件能够接收 DICOM 格式的图像数据,则它们可以在两方之间共享。 DICOM的通信部分是应用层协议,实体之间使用TCP/IP进行通信。 HTTP 和 HTTPS 协议用于 DICOM 的 Web 服务。 Web 服务支持的版本是 1.0、1.1、2 或更高版本。

    阅读更多

    其他支持的卡通化格式

    使用 C#,可以轻松卡通化不同的格式,包括。

    APNG (动画便携式网络图形)
    BMP (位图图片)
    ICO (窗口图标)
    JPG (联合摄影专家组)
    JPEG (联合摄影专家组)
    DIB (设备无关位图)
    DJVU (图形格式)
    DNG (数码相机图像)
    EMF (增强的元文件格式)
    EMZ (Windows 压缩增强元文件)
    GIF (图形交换格式)
    JP2 (JPEG 2000)
    J2K (小波压缩图像)
    PNG (便携式网络图形)
    TIFF (标记图像格式)
    TIF (标记图像格式)
    WEBP (光栅 Web 图像)
    WMF (微软视窗元文件)
    WMZ (压缩的 Windows Media Player 皮肤)
    TGA (塔加图形)
    SVG (可缩放矢量图形)
    EPS (封装的 PostScript 语言)
    CDR (矢量绘图图像)
    CMX (Corel 交换图像)
    OTG (开放文档标准)
    ODG (Apache OpenOffice 绘图格式)