为什么我的c#代码这么慢

时间:2014-12-02 08:40:36

标签: c# performance

Tihs是一个实现自适应直方图均衡算法的代码,由c#主窗体中的按钮调用,图像大小约为1024 * 768。问题是这段代码太慢了,我不知道应该在哪里修改以提高性能...请给我一些建议....谢谢..

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;

}

3 个答案:

答案 0 :(得分:3)

SetPixel

SetPixel非常慢。查看使用LockBitsMSDN有很好的例子。

循环内的字符串连接

循环中的这一行效率也很低,因为它为每个像素创建了256个字符串,因此分配了2.0亿个字符串,这些代价很高!

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

如果要进行调试,请将其取出,2.0亿行调试文本对您无用。它你需要它你最好写一个文件,否则它将需要许多GB的ram来存储最后的字符串。

答案 1 :(得分: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);

答案 2 :(得分: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     {         public 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;
    }
}