如何融合两个16位图像
how to fusion two 16 bit images
我正在研究结合了 PET 和 CT 的 DICOM 查看器项目。
进度
将两个dicom文件之一的大小调整为较大的一个。
并更改一个dicom文件的颜色
并合并两个dicom文件
示例 dicom 位图 1
bitmap2 , newBitmap(改变颜色红色)
我想要的效果图
private void button1_Click(object sender, EventArgs e)
{
string ima_path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var bitmap1 = dicomImageViewControls[0].DicomElements[0].Bitmap;
var bitmap2 = dicomImageViewControls[1].DicomElements[0].Bitmap;
if( bitmap1.Width<bitmap2.Width)
{
bitmap1 = resizeImage(bitmap1, bitmap2.Width, bitmap2.Height);
bitmap1.Save(ima_path + "\res.png", ImageFormat.Png);
}
else
{
bitmap2 = resizeImage(bitmap2, bitmap1.Width, bitmap1.Height);
bitmap2.Save(ima_path + "\res.png", ImageFormat.Png);
}
Color actualColor;
Bitmap newBitmap = new Bitmap(bitmap2.Width, bitmap2.Height);
for (int i = 0; i < bitmap2.Width; i++)
{
for (int j = 0; j < bitmap2.Height; j++)
{
actualColor = bitmap2.GetPixel(i, j);
float a = actualColor.A;
float r = actualColor.R;
newBitmap.SetPixel(i, j, Color.FromArgb((int)a, (int)r, 0, 0));
}
}
var target = new Bitmap(newBitmap.Width, newBitmap.Height, PixelFormat.Format32bppArgb);
var graphics = Graphics.FromImage(target);
graphics.CompositingMode = CompositingMode.SourceOver; // this is the default, but just to be clear
graphics.DrawImage(newBitmap, 0, 0);
graphics.DrawImage(bitmap1, 0, 0);
newBitmap.Save(ima_path + "\Image2.png", ImageFormat.Png);
}
public static Bitmap resizeImage(Bitmap image, int width, int height)
{
var destinationRect = new Rectangle(0, 0, width, height);
var destinationImage = new Bitmap(width, height);
destinationImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destinationImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destinationRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destinationImage;
}
目标位图
好像是第一张图
=======================================
我在 clear canvas.
中找到了一个新算法
baseImageGraphicProvider.ImageGraphic.PixelData.ForEachPixel(
(n, x, y, i) =>
{
// and this is why the base and overlay slices must be unsigned precisely coincident
var patientLocation = baseImageSopProvider.Frame.ImagePlaneHelper.ConvertToPatient(new PointF(x, y));
var overlayCoordinate = overlayImageSopProvider.Frame.ImagePlaneHelper.ConvertToImagePlane(patientLocation);
var baseValue = (ushort) baseImageGraphicProvider.ImageGraphic.PixelData.GetPixel(i);
var overlayValue = overlayImageGraphicProvider.ImageGraphic.PixelData.GetPixel((int) overlayCoordinate.X, (int) overlayCoordinate.Y);
// the fusion operator: output = underlyingGrey*(1-alpha) + overlayingColour*(alpha) (see DICOM 2009 PS 3.4 N.2.4.3)
var compositeColor = ToRgbVectorFromGrey(baseValue)*(1 - opacity) + ToRgbVector(colorMap[overlayValue])*opacity;
pixelData[3*n] = (byte) compositeColor.X;
pixelData[3*n + 1] = (byte) compositeColor.Y;
pixelData[3*n + 2] = (byte) compositeColor.Z;
});
我觉得这个算法是
var compositeColor = ToRgbVectorFromGrey(baseValue)*(1 - opacity) + ToRgbVector(colorMap[overlayValue])*opacity;
从 greycolor (1-opactiy) + 调色板(在我的例子中是红色调色板)*opacity Returns 每个像素的值中获取原始像素 rgb。
可能是bitmap1
缺少alpha通道,所以绘制的时候会覆盖掉所有的东西。例如,您可能想要考虑将 newBitmap
完全设为红色,并将颜色通道映射到 alpha 通道。 IE。 newBitmap.SetPixel(i, j, Color.FromArgb((int)r, 1, 0, 0));
并切换渲染顺序,以便最后绘制 newBitmap
。
此外,不要忘记释放所有创建的位图和图形对象。
您还可以考虑创建一个自定义函数来融合像素数据,即从左右图像中获取 16 位值并使用一些自定义函数来生成颜色值,因为这应该允许更大如何灵活地可视化数据。但要实现这一点,您需要访问原始 16 位像素数据,并且可能需要为所述 16 位数据编写您自己的调整大小函数。这通常还涉及某种窗口函数以将 16 位数据映射到 8 位值。
您可能还需要某种配准功能来准确组合每个数据集,因为通常无法保证它们仅通过调整大小就能正确对齐。
您可能还想查看 Fast work with bitmaps 以获得任何类型的渲染速度。
我正在研究结合了 PET 和 CT 的 DICOM 查看器项目。
进度
将两个dicom文件之一的大小调整为较大的一个。
并更改一个dicom文件的颜色
并合并两个dicom文件
示例 dicom 位图 1
bitmap2 , newBitmap(改变颜色红色)
我想要的效果图
private void button1_Click(object sender, EventArgs e)
{
string ima_path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var bitmap1 = dicomImageViewControls[0].DicomElements[0].Bitmap;
var bitmap2 = dicomImageViewControls[1].DicomElements[0].Bitmap;
if( bitmap1.Width<bitmap2.Width)
{
bitmap1 = resizeImage(bitmap1, bitmap2.Width, bitmap2.Height);
bitmap1.Save(ima_path + "\res.png", ImageFormat.Png);
}
else
{
bitmap2 = resizeImage(bitmap2, bitmap1.Width, bitmap1.Height);
bitmap2.Save(ima_path + "\res.png", ImageFormat.Png);
}
Color actualColor;
Bitmap newBitmap = new Bitmap(bitmap2.Width, bitmap2.Height);
for (int i = 0; i < bitmap2.Width; i++)
{
for (int j = 0; j < bitmap2.Height; j++)
{
actualColor = bitmap2.GetPixel(i, j);
float a = actualColor.A;
float r = actualColor.R;
newBitmap.SetPixel(i, j, Color.FromArgb((int)a, (int)r, 0, 0));
}
}
var target = new Bitmap(newBitmap.Width, newBitmap.Height, PixelFormat.Format32bppArgb);
var graphics = Graphics.FromImage(target);
graphics.CompositingMode = CompositingMode.SourceOver; // this is the default, but just to be clear
graphics.DrawImage(newBitmap, 0, 0);
graphics.DrawImage(bitmap1, 0, 0);
newBitmap.Save(ima_path + "\Image2.png", ImageFormat.Png);
}
public static Bitmap resizeImage(Bitmap image, int width, int height)
{
var destinationRect = new Rectangle(0, 0, width, height);
var destinationImage = new Bitmap(width, height);
destinationImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destinationImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destinationRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destinationImage;
}
目标位图
好像是第一张图
======================================= 我在 clear canvas.
中找到了一个新算法baseImageGraphicProvider.ImageGraphic.PixelData.ForEachPixel(
(n, x, y, i) =>
{
// and this is why the base and overlay slices must be unsigned precisely coincident
var patientLocation = baseImageSopProvider.Frame.ImagePlaneHelper.ConvertToPatient(new PointF(x, y));
var overlayCoordinate = overlayImageSopProvider.Frame.ImagePlaneHelper.ConvertToImagePlane(patientLocation);
var baseValue = (ushort) baseImageGraphicProvider.ImageGraphic.PixelData.GetPixel(i);
var overlayValue = overlayImageGraphicProvider.ImageGraphic.PixelData.GetPixel((int) overlayCoordinate.X, (int) overlayCoordinate.Y);
// the fusion operator: output = underlyingGrey*(1-alpha) + overlayingColour*(alpha) (see DICOM 2009 PS 3.4 N.2.4.3)
var compositeColor = ToRgbVectorFromGrey(baseValue)*(1 - opacity) + ToRgbVector(colorMap[overlayValue])*opacity;
pixelData[3*n] = (byte) compositeColor.X;
pixelData[3*n + 1] = (byte) compositeColor.Y;
pixelData[3*n + 2] = (byte) compositeColor.Z;
});
我觉得这个算法是
var compositeColor = ToRgbVectorFromGrey(baseValue)*(1 - opacity) + ToRgbVector(colorMap[overlayValue])*opacity;
从 greycolor (1-opactiy) + 调色板(在我的例子中是红色调色板)*opacity Returns 每个像素的值中获取原始像素 rgb。
可能是bitmap1
缺少alpha通道,所以绘制的时候会覆盖掉所有的东西。例如,您可能想要考虑将 newBitmap
完全设为红色,并将颜色通道映射到 alpha 通道。 IE。 newBitmap.SetPixel(i, j, Color.FromArgb((int)r, 1, 0, 0));
并切换渲染顺序,以便最后绘制 newBitmap
。
此外,不要忘记释放所有创建的位图和图形对象。
您还可以考虑创建一个自定义函数来融合像素数据,即从左右图像中获取 16 位值并使用一些自定义函数来生成颜色值,因为这应该允许更大如何灵活地可视化数据。但要实现这一点,您需要访问原始 16 位像素数据,并且可能需要为所述 16 位数据编写您自己的调整大小函数。这通常还涉及某种窗口函数以将 16 位数据映射到 8 位值。
您可能还需要某种配准功能来准确组合每个数据集,因为通常无法保证它们仅通过调整大小就能正确对齐。
您可能还想查看 Fast work with bitmaps 以获得任何类型的渲染速度。