加速ConvertToGrayScale方法

时间:2012-03-23 18:58:43

标签: c# image-processing

此方法中的b.GetPixel调用非常慢,是否有办法使用LockBits或其他方法加快此方法的速度?但我不知道如何使用指针来获取像素值等。

背景:我需要float[][],因为我在this问题中询问了加权随机化。

public static float[][] ConvertToGrayScale(this Bitmap bm)
{
    var b = new Bitmap(bm);
    var data = new List<float[]>();
    for (var i = 0; i < b.Width; i++)
    {
        var row = new List<float>();
        for (int x = 0; x < b.Height; x++)
        {
            var oc = b.GetPixel(i, x);
            var grayScale = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11));
            row.Add(grayScale);
        }
        data.Add(row.ToArray());
    }
    return data.ToArray();
}

修改

如Paul Sasik所述,我将代码更改为:

 public static GrayScaleResult ConvertToGrayScale(this Bitmap bm)
 {
     var result = new GrayScaleResult(bm);
     for (var x = 0; x < result.Width; x++)
     {
         for (int y = 0; y < result.Height; y++)
         {
             var oc = bm.GetPixel(x, y);
             // casting to int here - you can just use a 2d array of ints
             result.Data[x, y] = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11));
         }
     }
     return result;
 }

 public struct GrayScaleResult
 {
     public float[,] Data;
     public int Width;
     public int Height;
     public GrayScaleResult(Bitmap bm)
     {
         Width = bm.Width;
         Height = bm.Height;
         Data = new float[Width, Height];
     }
 }

我在优化之前和之后使用分析器检查了性能:

enter image description here

有趣的是,getHeight需要花费大量时间才能在位图对象中缓存?因此我也在结构中存储了Width和Height。

但结果不可能,可以吗?我的意思是瓶颈仍然是GetPixel,但为什么现在花费更多时间呢?我没有改变任何其他内容,底层位图仍然是相同的。

EDIT2

好的,发现它:问题出乎意料地删除了new Bitmap所以我再次添加了它:

 public static GrayScaleResult ConvertToGrayScale(this Bitmap b)
 {
     var bm = new Bitmap(b);
     var result = new GrayScaleResult(bm);
     ...

现在代码优化:

enter image description here

2 个答案:

答案 0 :(得分:2)

在尝试使用不安全的代码之前,您可以对当前代码进行一些优化:

public static float[,] ConvertToGrayScale2(this Bitmap bm)
{
    var data = new float[bm.Width, bm.Height];
    for (var i = 0; i < bm.Width; i++)
    {
        for (int x = 0; x < bm.Height; x++)
        {
            var oc = bm.GetPixel(i, x);
                            // casting to int here - you can just use a 2d array of ints
            data[i, x] = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11));
        }
    }
    return data;
}

优化:

  • 无需创建新的Bitmap即可使用。参考你传递的那个
  • 使用矩形浮点数组而不是通用列表
  • 这消除了许多额外的任务和一些集合创建/管理开销
  • 请带上一粒盐,而不是使用IDE

答案 1 :(得分:1)

为什么不预先创建阵列,而不是使用中间列表?您提前了解维度,因此可以保存为位图的每一行创建列表。这是我能发现的第一个明显的胜利。