2014-12-02 2 views
0

Tihs - это код, который внедряет алгоритм алгоритма адаптивной гистограммы, вызываемый кнопкой в ​​основной форме C#, размер изображения составляет 1024 * 768. Проблема заключается в том что этот код слишком медленно, я не знаю, где я должен изменить, чтобы улучшить производительность ... Пожалуйста, дайте мне совет .... спасибо ..Почему мой код C# настолько медленный

private void AHE_BMP_advanced(Int32 halfblocksize) 
{ 
    //adaptive histogram equalization 
    Size imgsz = sourceBMP.Size; 
    //compute total number of pixels 
    double totalNum = imgsz.Height * imgsz.Width; 
    //temp image for storation 
    Bitmap tempImg = new Bitmap(imgsz.Width, imgsz.Height); 
    //region statistics 
    double[,] prob = new double[256, 3]; 
    Int32[,] mapping = new Int32[256, 3]; 
    double[] probSum = new double[3]; 

    for (int i = 0; i < imgsz.Height; i++) 
    { 
     for (int j = 0; j < imgsz.Width; j++) 
     { 
      //this.textBox2.Text = "i=" + i.ToString() + "j=" + j.ToString(); 

      for (int u = 0; u < 256; u++) { 
       for (int v = 0; v < 3; v++) { 
        prob[u, v] = 0; 
        mapping[u, v] = 0; 
       } 
      } 

      //produce ahe for this pixel: 
      for (int u = i - halfblocksize; u <= i + halfblocksize; u++) 
      { 
       for (int v = j - halfblocksize; v <= j + halfblocksize; v++) 
       { 
        //uv->hi,wi; 
        int hi, wi; 
        hi = u; 
        wi = v; 
        //mirror: 
        if (hi < 0) hi = -hi; 
        else if (hi >= imgsz.Height) 
         hi = 2 * (imgsz.Height - 1) - hi; 
        if (wi < 0) wi = -wi; 
        else if (wi >= imgsz.Width) 
         wi = 2 * (imgsz.Width - 1) - wi; 
        //get hist 

        prob[sBmpdata[wi,hi,0], 0] += 1; 
        prob[sBmpdata[wi,hi,1], 1] += 1; 
        prob[sBmpdata[wi,hi,2], 2] += 1; 
       } 
      } 
      //get ahe value: 
      //probSum init: 
      probSum[0] = 0; 
      probSum[1] = 0; 
      probSum[2] = 0; 

      for (int k = 0; k < 256; k++) 
      {       
       this.textBox2.Text += "prob[" + k.ToString()+ ",0]=" + 
        prob[k,0].ToString()+"\r\n"; 

       prob[k, 0] /= totalNum; 
       prob[k, 1] /= totalNum; 
       prob[k, 2] /= totalNum; 
       //Sum 
       probSum[0] += prob[k, 0]; 
       probSum[1] += prob[k, 1]; 
       probSum[2] += prob[k, 2]; 
       if(i==40&&j==40) 
       //mapping(INT32) 
       mapping[k, 0] = Convert.ToInt32(255.0 * probSum[0]); 
       mapping[k, 1] = Convert.ToInt32(255.0 * probSum[1]); 
       mapping[k, 2] = Convert.ToInt32(255.0 * probSum[2]); 
      } 

      tempImg.SetPixel(j, i, 
       Color.FromArgb(mapping[sBmpdata[j,i,0], 0], 
       mapping[sBmpdata[j,i,1], 1], mapping[sBmpdata[j,i,2], 2])); 
     } 
    } 

    this.pictureBox1.Image = tempImg; 

} 
+4

Вы устали от каких-либо профилирующих инструментов? – chead23

+0

Я нашел многомерные массивы 'prob [u, v]' медленными. Попробуйте изменить их на неровные массивы 'prob [u] [v]'. – Henrik

+1

Что выглядит O (n^4), в зависимости от размера полублока и размера вашего изображения, это может быть медленным. – amdev

ответ

3

SetPixel

SetPixel очень медленно. Посмотрите на использование LockBits. MSDN имеет хороший пример.

Объединения строк внутри цикла

Этой линия внутри цикла также неэффективны, поскольку он создает 256 строк для каждого пикселя, поэтому 201 миллионов строк выделены, что должны быть дорогими!

for (int k = 0; k < 256; k++) 
    this.textBox2.Text += "prob[" + k.ToString()+ ",0]=" + prob[k,0].ToString()+"\r\n"; 

Если это отладка, вывести его из, 201 миллионов строк отладки текста не является полезным для вас. Вам это нужно, вам лучше писать в файл, так как в противном случае для хранения финальной строки потребуется много RAM RAM.

+0

Этот код имеет множество проблем и производительность с помощью SetPixel является самым маленьким здесь. O (n^3) конкатенации строк, например. –

+0

@AlexJoukovsky Откуда вы знаете, вы профилировали код? –

+0

@SamGreenhalgh SetPixel очень медленный, но конкатенация строк медленнее. И не должно быть профиля, чтобы видеть асимптотику этого. –

1

Использование SetPixel на самом деле является довольно неэффективным способом работы с данными изображения. Если вы хотите сканировать весь образ, я бы предложил манипулировать данными изображения напрямую, используя класс BitmapData.

// Create a new bitmap. 
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg"); 

// Lock the bitmap's bits. 
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
System.Drawing.Imaging.BitmapData bmpData = 
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, 
    bmp.PixelFormat); 

// Get the address of the first line. 
IntPtr ptr = bmpData.Scan0; 

// Declare an array to hold the bytes of the bitmap. 
int bytes = Math.Abs(bmpData.Stride) * bmp.Height; 
byte[] rgbValues = new byte[bytes]; 

// Copy the RGB values into the array. 
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); 

// Set every third value to 255. A 24bpp bitmap will look red. 
for (int counter = 2; counter < rgbValues.Length; counter += 3) 
rgbValues[counter] = 255; 

// Copy the RGB values back to the bitmap 
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); 

// Unlock the bits. 
bmp.UnlockBits(bmpData); 

// Draw the modified image. 
e.Graphics.DrawImage(bmp, 0, 150); 
0

Ну, я думаю, вы должны написать

private void AHE_BMP_advanced(Int32 halfblocksize) 
    { 
     this.pictureBox1.Image = GetAHE_BMP_advanced(halfblocksize, sourceBMP.Size, sBmpdata); 
    } 

где GetAHE_BMP_advanced является

private static Bitmap GetAHE_BMP_advanced(int halfblocksize, Size sourceBmpSize, int[,,] sourceBmpData) 
    { 
     const int m = 256; 
     const int n = 3; 
     //adaptive histogram equalization 
     Size imgsz = sourceBmpSize; 
     //compute total number of pixels 
     double totalNum = imgsz.Height * imgsz.Width; 

     var colors = new Color[sourceBmpSize.Width, sourceBmpSize.Height]; 
     for (int i = 0; i < imgsz.Height; i++) 
     { 
      for (int j = 0; j < imgsz.Width; j++) 
      { 
       double[,] prob = new double[m, n]; 
       int[,] mapping = new int[m, n]; 

       //produce ahe for this pixel: 
       for (int u = i - halfblocksize; u <= i + halfblocksize; u++) 
       { 
        for (int v = j - halfblocksize; v <= j + halfblocksize; v++) 
        { 
         int hi = u; 
         int wi = v; 
         //mirror: 
         if (hi < 0) hi = -hi; 
         else if (hi >= imgsz.Height) 
          hi = 2 * (imgsz.Height - 1) - hi; 
         if (wi < 0) wi = -wi; 
         else if (wi >= imgsz.Width) 
          wi = 2 * (imgsz.Width - 1) - wi; 
         //get hist 

         prob[sourceBmpData[wi, hi, 0], 0] += 1; 
         prob[sourceBmpData[wi, hi, 1], 1] += 1; 
         prob[sourceBmpData[wi, hi, 2], 2] += 1; 
        } 
       } 

       double[] probSum = new double[n]; 

       for (int k = 0; k < m; k++) 
       { 

        prob[k, 0] /= totalNum; 
        prob[k, 1] /= totalNum; 
        prob[k, 2] /= totalNum; 
        //Sum 
        probSum[0] += prob[k, 0]; 
        probSum[1] += prob[k, 1]; 
        probSum[2] += prob[k, 2]; 
        if (i == 40 && j == 40) //mapping(INT32) 
        { 
         mapping[k, 0] = Convert.ToInt32(255.0 * probSum[0]); 
         mapping[k, 1] = Convert.ToInt32(255.0 * probSum[1]); 
         mapping[k, 2] = Convert.ToInt32(255.0 * probSum[2]); 
        } 
       } 

       colors[i, j] = Color.FromArgb(mapping[sourceBmpData[j, i, 0], 0], 
               mapping[sourceBmpData[j, i, 1], 1], 
               mapping[sourceBmpData[j, i, 2], 2]); 
      } 
     } 

     return BitmapHelper.CreateBitmap(colors); 
    } 

где BitmapHelper является:

общественный статический класс BitmapHelper { общественного STRUCT Pixel: IEquatable {

 // ReSharper disable UnassignedField.Compiler 
     public byte Blue; 
     public byte Green; 
     public byte Red; 

     public bool Equals(Pixel other) 
     { 
      return Red == other.Red && Green == other.Green && Blue == other.Blue; 
     } 
    } 

    public static Color[,] GetPixels(Bitmap two) 
    { 
     return ProcessBitmap(two, pixel => Color.FromArgb(pixel.Red, pixel.Green, pixel.Blue)); 
    } 

    public static float[,] GetBrightness(Bitmap two) 
    { 
     return ProcessBitmap(two, pixel => Color.FromArgb(pixel.Red, pixel.Green, pixel.Blue).GetBrightness()); 
    } 

    public static unsafe T[,] ProcessBitmap<T>(Bitmap bitmap, Func<Pixel, T> func) 
    { 
     var lockBits = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, 
            bitmap.PixelFormat); 
     int padding = lockBits.Stride - (bitmap.Width * sizeof(Pixel)); 

     int width = bitmap.Width; 
     int height = bitmap.Height; 

     var result = new T[height, width]; 

     var ptr = (byte*)lockBits.Scan0; 

     for (int i = 0; i < height; i++) 
     { 
      for (int j = 0; j < width; j++) 
      { 
       var pixel = (Pixel*)ptr; 
       result[i, j] = func(*pixel); 
       ptr += sizeof(Pixel); 
      } 
      ptr += padding; 
     } 

     bitmap.UnlockBits(lockBits); 

     return result; 
    } 

    public static Bitmap CreateBitmap(Color[,] colors) 
    { 
     const int bytesPerPixel = 4, stride = 8; 
     int width = colors.GetLength(0); 
     int height = colors.GetLength(1); 
     byte[] bytes = new byte[width*height*bytesPerPixel]; 


     int n = 0; 
     for (int i = 0; i < width; i++) 
     { 
      for (int j = 0; j < height; j++) 
      { 
       bytes[n++] = colors[i, j].R; 
       bytes[n++] = colors[i, j].G; 
       bytes[n++] = colors[i, j].B; 
       bytes[n++] = colors[i, j].A; 
      } 
     } 

     return CreateBitmap(bytes, width, height, stride, PixelFormat.Format32bppArgb); 
    } 

    public static Bitmap CreateBitmap(byte[] data, int width, int height, int stride, PixelFormat format) 
    { 
     var arrayHandle = GCHandle.Alloc(data, GCHandleType.Pinned); 
     var bmp = new Bitmap(width, height, stride, format, arrayHandle.AddrOfPinnedObject()); 
     arrayHandle.Free(); 
     return bmp; 
    } 
} 
Смежные вопросы