如何融合两个 16 位图像

Posted

技术标签:

【中文标题】如何融合两个 16 位图像【英文标题】:how to fusion two 16 bit images 【发布时间】:2022-01-16 18:33:36 【问题描述】:

我正在开发一个结合了 PET 和 CT 的 DICOM 查看器项目。

进展

    将两个 dicom 文件之一的大小调整为较大的一个。

    并改变一个dicom文件的颜色

    并合并两个dicom文件

示例 dicom bitmap1

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;
        



目标位图

它看起来像第一张照片。

======================================= 我在透明画布中发现了一种新算法。

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;

从 graycolor(1-opactiy)+调色板(在我的例子中为红色调色板)获取原始像素 rgb *opacity 返回每个像素的值。

https://github.com/ClearCanvas/ClearCanvas/blob/master/ImageViewer/AdvancedImaging/Fusion/Tests/FusionColorCompositingTest.cs

【问题讨论】:

var graphics = Graphics.FromImage(target); 这将在目标上绘制,但您保存 newBitmap。 @TaWI 更正了结果。图片 假设您想在屏幕上绘制它,并且可以访问位图或原始像素数据。那么数据是来自 dicom 文件还是其他文件都无关紧要。所以一个更好的标题可能是“如何融合位图”或“”。 @JonasH 谢谢 【参考方案1】:

很可能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 以获得任何类型的渲染速度。

【讨论】:

我带来了用于融合像素数据的自定义函数。我正在进一步研究 clearcanvas github。我不确定我这样做是否正确。

以上是关于如何融合两个 16 位图像的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个像 Apple Music 艺术家页面上那样的融合导航栏

图像融合基于matlab低频融合策略小波图像融合含Matlab源码 2319期

图像融合基于matlab低频融合策略小波图像融合含Matlab源码 2319期

图像融合基于matlab DCT域多焦点图像融合含Matlab源码 1973期

如何使用 UIImage 加载 16 位图像?

如何使用JavaScript中的select将两个过滤器融合到一个表中?