改进图像合成算法c#.NET

时间:2011-09-26 08:44:34

标签: c# .net image image-processing

我想知道是否有人可以对我在改进合成算法方面所做的改进有所了解。做了什么是将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;
}

2 个答案:

答案 0 :(得分:3)

移动这些

    Bitmap Rcomp = new Bitmap(QRE2ImgComp[0]);
    Bitmap Gcomp = new Bitmap(QRE2ImgComp[1]);
    Bitmap Bcomp = new Bitmap(QRE2ImgComp[2]);
在for循环之外

其他非常重要的一点:

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

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

  • 考虑使用第三方库(免费或商业)...有几个内置的优化方法可以实现您想要实现的目标...

答案 1 :(得分:1)

我完全同意Yahia在提高绩效的答案中列出的观点。我想再补充一点关于性能的观点。您可以使用.Net Framework的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);
}

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