Я работаю над медианным фильтром, используя инструкции avx avx2 и OpenMP.Ввод изображения 4K.Время от времени алгоритм работает с одним цветовым компонентом пикселя, взятым из входных данных.
Мой размер фильтра равен 5*5 = 25
.Для медианного фильтра я должен отсортировать эти unsigned char
числа, а затем взять среднее.Я использую метод слияния Odd-Even от Batcher, и он работает нормально.
Я нахожусь в той точке, где мне нужно максимально ускорить алгоритм.Я тестировал программу несколько раз и в среднем получил результат 3,08 секунды
Визуализация алгоритма сортировки: как видите, весь процесс сортировки можно разбить на 15 меньших шагов.
У меня есть функция верхнего уровня, которую я вызываю из main с именем MedianFiltering
, которая берет всю информацию, необходимую для фильтрации, и записывает ее обратно с помощью указателя.Когда эта функция вызывается, она создает все необходимые векторы управления для следующих двух функций:
_mm256_blendv_epi8()
и _mm256_permute2f128_si256()
Создание всех необходимых векторов управления
Iесть 40 следующей строки (все названы по-разному)
__m256i vectorControl= _mm256_lddqu_si256((__m256i *)controlArray);
что-то вроде:
__m256i vmaskBlendControlFromMinMaxandWorkingOn4 = _mm256_lddqu_si256((__m256i *)maskBlendControlFromMinMaxandWorkingOn4);
__m256i vmaskBlendControlFromMinandMax5 = _mm256_lddqu_si256((__m256i *)maskBlendControlFromMinandMax5);
__m256i vmaskBlendControlFromMinMaxandWorkingOn5 = _mm256_lddqu_si256((__m256i *)maskBlendControlFromMinMaxandWorkingOn5);
__m256i vmaskBlendControlFromMinandMax6 = _mm256_lddqu_si256((__m256i *)maskBlendControlFromMinandMax6);
__m256i vmaskBlendControlFromMinandMax7 = _mm256_lddqu_si256((__m256i *)maskBlendControlFromMinandMax7);
__m256i vmaskBlendControlFromMinMaxandWorkingOn7 = _mm256_lddqu_si256((__m256i *)maskBlendControlFromMinMaxandWorkingOn7);
Я думаю, мне не нужно публиковать все это, вы получите идею.
Алгоритм
затем процесс сортировки:
//stepping on every row
for (int row = 0; row < imgHeight; row++)
{
stepping on every column of the picture
for (int col = 0; col < imgWidth; col++)
{
OneColorChanelWidth calculatedMedians[3] = { 0 };
//calculating each color of a single pixel
for (int rgba = 0; rgba < 3; rgba++)
{
OneColorChanelWidth calcMedian[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255 };
for (int fy = 0; fy < FILTER_W; fy++)
{
for (int fx = 0; fx < FILTER_H; fx++)
{
calcMedian[fy * 5 + fx] = *(imgSrcExt + (row + fy)*imgWidthF * 3 + (col + fx) * 3 + rgba);
}
}
__m256i vinput = _mm256_lddqu_si256((__m256i *)calcMedian);
*Sorting the calcMedian array all the 15 steps are here the result is stored in workingOn*
*(imgDstMedian + row*imgWidth * 3 + col * 3 + rgba) = workingOn.m256i_u8[12];
}
}
}
Точка зрения с высоты птичьего полета:
void MedianFiltering(arguments)
{
Creating all the required control vectors
Algorithm
return;
}
Поскольку я могу использовать OpenMP, распараллеливаниеможет быть хорошо, чтобы улучшить скорость обработки.Я поставил #pragma omp parallel for
перед циклом for
, который считается по строкам, но ничего не изменилось.Затем я поставил его перед тем, который считает по строкам, без увеличения скорости.
После этого я думаю о том, может быть, проблема в том, что все потоки, которые начинают работать, используют одни и те же векторы управления (все они читаютсяпожалуйста, скажите мне, может ли это привести к тому, что распараллеливание не может иметь никакого значения.
Я провел эксперимент: я поместил эту прагму распараллеливания в разные места кода и запускаю тесты, но, к сожалению, нииз экспериментов показали высокую скорость улучшения. На самом деле 3,08 секунды были самым низким временем, которое я получил, но это может быть достигнуто без какого-либо параллелизата.
Есть ли способ использовать распараллеливание для улучшения моего времени обработки? ДругойЭто может привести к повторному процессу сортировки, но в данный момент я не заинтересован в этом.