Улучшение алгоритма компоновки изображений c # .NET - PullRequest
0 голосов
/ 26 сентября 2011

Мне было интересно, сможет ли кто-нибудь пролить свет на улучшения, которые я могу сделать, чтобы ускорить этот алгоритм компоновки.Для этого нужно сделать 3 снимка, чтобы разделить их, чтобы получить 1-й канал изображения Красный, 2-й канал изображения Зеленый и 3-й канал изображения Синий и объединить их в 1 новое изображение.Теперь это работает, но мучительно медленно.Причина, по которой я думаю, что пиксель за пиксельной обработкой это должно делать для всех компонентов изображения.

Процесс состоит в том, чтобы:

Для всех изображений: извлечь соответствующие значения RG и 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++;

}

Для справки приведем метод фильтрации красного канала, относительно одинакового для синего и зеленого:

Ответы [ 2 ]

3 голосов
/ 26 сентября 2011

Переместите эти

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

вне циклов for!

Другие очень важные моменты:

  • избегать использования GetPixel - это ОЧЕНЬ МЕДЛЕННО!

  • Оформить заказ LockBits и т. Д. - вот какДоступ на уровне пикселей обычно выполняется в .NET

  • Рассмотрите возможность использования сторонней библиотеки (бесплатной или коммерческой) ... в некоторых есть встроенный оптимизированный метод, позволяющий вам работатьпытаясь достичь ...

1 голос
/ 26 сентября 2011

Я полностью согласен с тем, что Яхья перечислил в своем ответе для улучшения производительности.Я хотел бы добавить еще один момент относительно производительности.Вы можете использовать класс Parallel .Net Framework, чтобы распараллелить выполнение ваших циклов 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);
}

Надеюсь, этот ответ даст вам стартпункт для улучшения вашего кода.

...