Страницы

Поиск по вопросам

четверг, 23 января 2020 г.

Оптимизация алгортима перебора пикселей WPF C#

#c_sharp #wpf #изображения


Здравствуйте, есть метод получения массива яркостей из BitmapSource для дальнейшего
анализа:

public const float CoeffColor = ((float)100 / 255 * 3) / 10000;
//...
arrayPixelsImage = new byte[SizeArrayPixels];
source.CopyPixels(arrayPixelsImage, StriteImage, 0); //typeof(source) == BitmapSource
float[,] massBrightness = new float[WidthImage, HeightImage];
Parallel.For(0, WidthImage, x =>
{
    for (int y = 0; y < HeightImage; y++)
    {
        int indx = y * WidthImage * 4 + 4 * x;
        float brightness = (float)(arrayPixelsImage[indx] + arrayPixelsImage[indx
+ 1] + arrayPixelsImage[indx + 2]) * CoeffColor;
        massBrightness[x, y] = brightness;
    }
});
return massBrightness;


Интересует то, как можно его оптимизировать, в плане времени выполнения?
    


Ответы

Ответ 1



Погонял алгоритм на fullHD jpeg'e. У меня на нём выходит чуть боле 2млн итераций суммарно.(внешний параллельный + внутренний) И тут, я боюсь оптимизировать особо не получится. Примерные затраты по коду: int indx = y * WidthImage * 4 + 4 * x; -25% float brightness = (float)(arrayPixelsImage[indx] + arrayPixelsImage[indx + 1] + arrayPixelsImage[indx + 2]) * CoeffColor; -70% massBrightness[x, y] = brightness;-3% сам цикл -2% Учитывая общее кол-во итераций не лишним будет отметить, что накладные расходы на создание нового таска на каждой итерации Parallel.For практически нивелируют выигрыш от использования распараллеливания при сравнении с последовательным циклом с таким же кол-вом итераций. Т.е. цикл с 2М итераций с тем же телом выполняется почти за то же кол-во тиков. Резюмируя свои мысли по поводу оптимизации данного кода: На C# вряд ли удастся достичь хотя бы 2-х кратного прироста производительности. Можно оптимизировать все вычисления и операции доступа/присвоения, но максимум, чего удастся добиться это 30% прироста на "удачном" прогоне по отношению к среднему результату до оптимизации. Если учесть что винда система отнюдь не реального времени то даже оптимизированный вариант может ( и достаточно часто будет) отрабатывать дольше чем средне время для не оптимизированного варианта. Если нужно "лопатить" большие объёмы данных и по другому никак при этом выполняя на каждом кванте (единице данных) достаточно простые/быстрые операции то я рекомендую смотреть вам в сторону использования ресурсов GPU (OpenCL или CUDA) Для всех остальных случаев я бы смотрел в сторону упрощения алгоритма или уменьшения числа операций. Например понижал бы разрешение изображения пока это не сильно сказывается на результате. Ощутимо упростить что-либо в этих 3-х строчках кода вряд ли получится. Поэтому думайте как уменьшить число итераций.

Ответ 2



writeableBitmap.Lock(); /* в отдельных потоках выполняете обработку. дожидаетесь завершения потоков. */ writeableBitmap.AddDirtyRect(...); writeableBitmap.Unlock(); также посмотрите реализацию методов в проекте Microsoft Win2D

Комментариев нет:

Отправить комментарий