Ускорьте метод ConvertToGrayScale - PullRequest
1 голос
/ 23 марта 2012

Вызов b.GetPixel в этом методе довольно медленный, есть ли способ ускорить этот метод с помощью LockBits или что-то в этом роде?Но я не знаю, как работать с указателями, чтобы получить значение пикселя и т. Д.

Справочная информация: мне нужен float[][] из-за взвешенной рандомизации, которую я задал в этом вопросе.

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();
}

РЕДАКТИРОВАТЬ

Как упомянуто ниже от Пола Сасика, я изменил код на этот:

 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 занимает много времени, поэтому кажется, что он не кэшируется в растровом объекте?Из-за этого я также сохранил ширину и высоту в структуре.

Но результат не может быть, не так ли?Я имею в виду, что узкое место все еще 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 ]

2 голосов
/ 23 марта 2012

Перед тем, как использовать небезопасный код, вы можете внести ряд изменений в свой текущий код:

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;
}

Оптимизации:

  • Нет необходимости создавать новый битовый образ для работыот.Ссылка на тот, который вы передаете
  • Используйте прямоугольный массив с плавающей точкой, а не общие списки
  • Это избавит вас от многих дополнительных назначений и некоторых накладных расходов на создание / управление коллекцией
  • Пожалуйста, примитес зерном соли, не используя IDE
1 голос
/ 23 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...