【问题标题】:Improving Image compositing Algorithm c# .NET改进图像合成算法 c# .NET
【发布时间】:2011-11-25 01:02:03
【问题描述】:

我想知道是否有人可以阐明我可以在使这种合成算法更快方面所做的改进。所做的是将 3 张图像拆分为第 1 张图像红色通道、第 2 张图像绿色通道和第 3 张图像蓝色通道,然后将它们合成为 1 张新图像。现在它可以工作了,但速度非常慢。我认为它必须对所有图像组件进行逐像素处理的原因。

流程是:

对于所有图像: 提取各自的 R G 和 B 值 -> 合成 1 个图像 -> 保存新图像。

foreach (Image[] QRE2ImgComp in QRE2IMGArray)
{
    Globals.updProgress = "Processing frames: " + k + " of " + QRE2IMGArray.Count + " frames done.";
    QRMProgressUpd(EventArgs.Empty);

    Image RedLayer = GetRedImage(QRE2ImgComp[0]);
    QRE2ImgComp[0] = RedLayer;

    Image GreenLayer = GetGreenImage(QRE2ImgComp[1]);
    QRE2ImgComp[1] = GreenLayer;

    Image BlueLayer = GetBlueImage(QRE2ImgComp[2]);
    QRE2ImgComp[2] = BlueLayer;


    Bitmap composite = new Bitmap(QRE2ImgComp[0].Height, QRE2ImgComp[0].Width);

    Color Rlayer,Glayer,Blayer;
    byte R, G, B;

    for (int y = 0; y < composite.Height; y++)
    {
        for (int x = 0; x < composite.Width; x++)
        {
            //pixelColorAlpha = composite.GetPixel(x, y);

            Bitmap Rcomp = new Bitmap(QRE2ImgComp[0]);
            Bitmap Gcomp = new Bitmap(QRE2ImgComp[1]);
            Bitmap Bcomp = new Bitmap(QRE2ImgComp[2]);

            Rlayer = Rcomp.GetPixel(x, y);
            Glayer = Gcomp.GetPixel(x, y);
            Blayer = Bcomp.GetPixel(x, y);

            R = (byte)(Rlayer.R);
            G = (byte)(Glayer.G);
            B = (byte)(Blayer.B);
            composite.SetPixel(x, y, Color.FromArgb((int)R, (int)G, (int)B));
        }
    }


    Globals.updProgress = "Saving frame...";
    QRMProgressUpd(EventArgs.Empty);
    Image tosave = composite;
    Globals.QRFrame = tosave;
    tosave.Save("C:\\QRItest\\E" + k + ".png", ImageFormat.Png);
    k++;

}

这里供参考的是蓝色和绿色相对相同的红色通道过滤方法:

public Image GetRedImage(Image sourceImage)
{
    Bitmap bmp = new Bitmap(sourceImage);
    Bitmap redBmp = new Bitmap(sourceImage.Width, sourceImage.Height);

        for (int x = 0; x < bmp.Width; x++)
        {
            for (int y = 0; y < bmp.Height; y++)
            {
                Color pxl = bmp.GetPixel(x, y);
                Color redPxl = Color.FromArgb((int)pxl.R, 0, 0);

                redBmp.SetPixel(x, y, redPxl);
            }
        }
        Image tout = (Image)redBmp;

        return tout;
}

【问题讨论】:

标签: c# .net image image-processing


【解决方案1】:

移动这些

    Bitmap Rcomp = new Bitmap(QRE2ImgComp[0]);
    Bitmap Gcomp = new Bitmap(QRE2ImgComp[1]);
    Bitmap Bcomp = new Bitmap(QRE2ImgComp[2]);

在 for 循环之外!

其他非常重要的点:

  • 避免使用GetPixel - 它非常慢!

  • Checkout LockBits 等 - 这就是 .NET 中通常进行像素级访问的方式

  • 考虑使用第 3 方库(免费或商业)...有一些内置优化方法来完成您想要实现的目标...

【讨论】:

    【解决方案2】:

    我完全同意 Yahia 在他的回答中列出的提高性能的点。关于性能,我想再补充一点。您可以使用 .Net 框架的 Parallel 类来并行执行 for 循环。下面的示例使用LockBits 方法和Parallel 类来提高性能(假设每像素32 位(PixelFormat.Format32bppArgb)):

    public unsafe static Bitmap GetBlueImagePerf(Image sourceImage)
    {
      int width = sourceImage.Width;
      int height = sourceImage.Height;
    
      Bitmap bmp = new Bitmap(sourceImage);
      Bitmap redBmp = new Bitmap(width, height, bmp.PixelFormat);
    
      BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
      BitmapData bd2 = redBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);
      byte* source = (byte*)bd.Scan0.ToPointer();
      byte* target = (byte*)bd2.Scan0.ToPointer();
    
      int stride = bd.Stride;
    
      Parallel.For(0, height, (y1) =>
      {
        byte* s = source + (y1 * stride);
        byte* t = target + (y1 * stride);
        for (int x = 0; x < width; x++)
        {
          // use t[1], s[1] to access green channel
          // use t[2], s[2] to access red channel
          t[0] = s[0]; 
          t += 4;       // Add bytes per pixel to current position.
          s += 4;       // For other pixel formats this value is different.
        }
      });
    
      bmp.UnlockBits(bd);
      redBmp.UnlockBits(bd2);
    
    
      return redBmp;
    }
    
    public unsafe static void DoImageConversion()
    {
      Bitmap RedLayer   = GetRedImagePerf(Image.FromFile("image_path1"));
      Bitmap GreenLayer = GetGreenImagePerf(Image.FromFile("image_path2"));
      Bitmap BlueLayer  = GetBlueImagePerf(Image.FromFile("image_path3"));
    
      Bitmap composite =
        new Bitmap(RedLayer.Width, RedLayer.Height, RedLayer.PixelFormat);      
    
      BitmapData bd = composite.LockBits(new Rectangle(0, 0, RedLayer.Width, RedLayer.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
      byte* comp = (byte*)bd.Scan0.ToPointer();
    
      BitmapData bdRed = RedLayer.LockBits(new Rectangle(0, 0, RedLayer.Width, RedLayer.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
      BitmapData bdGreen = GreenLayer.LockBits(new Rectangle(0, 0, RedLayer.Width, RedLayer.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
      BitmapData bdBlue = BlueLayer.LockBits(new Rectangle(0, 0, RedLayer.Width, RedLayer.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    
      byte* red = (byte*)bdRed.Scan0.ToPointer();
      byte* green = (byte*)bdGreen.Scan0.ToPointer();
      byte* blue = (byte*)bdBlue.Scan0.ToPointer();
    
      int stride = bdRed.Stride;
    
      Parallel.For(0, bdRed.Height, (y1) =>
      {
        byte* r = red + (y1 * stride);
        byte* g = green + (y1 * stride);
        byte* b = blue + (y1 * stride);
        byte* c = comp + (y1 * stride);
    
        for (int x = 0; x < bdRed.Width; x++)
        {
          c[0] = b[0];
          c[1] = g[1];
          c[2] = r[2];
    
          r += 4; // Add bytes per pixel to current position.
          g += 4; // For other pixel formats this value is different.
          b += 4; // Use Image.GetPixelFormatSize to get number of bits per pixel
          c += 4;
        }
      });
    
      composite.Save("save_image_path", ImageFormat.Jpeg);
    }
    

    希望,这个答案可以为您提供改进代码的起点。

    【讨论】:

      猜你喜欢
      • 2015-11-19
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 2012-11-22
      • 2020-04-18
      • 1970-01-01
      • 2010-10-02
      相关资源
      最近更新 更多