X86 使用AVX AVX2和OpenMP进行中值滤波

X86 使用AVX AVX2和OpenMP进行中值滤波,x86,openmp,vectorization,avx,avx2,X86,Openmp,Vectorization,Avx,Avx2,我正在使用avx avx2指令和OpenMP开发中值滤波器。输入为4K图片。该算法一次处理从输入中提取的像素的单一颜色分量 我的过滤器大小是5*5=25。要进行中值滤波,我必须对这些无符号字符数字进行排序,然后取中间的一个。我使用的是Batcher的奇偶合并排序,这很好 我需要尽可能地加快算法的速度。我对程序进行了多次测试,平均结果是3.08秒 排序算法的可视化:如您所见,整个排序过程可分为15个较小的步骤。 我有一个从main调用的顶级函数,名为MedianFiltering,它获取进行过

我正在使用avx avx2指令和OpenMP开发中值滤波器。输入为4K图片。该算法一次处理从输入中提取的像素的单一颜色分量

我的过滤器大小是
5*5=25
。要进行中值滤波,我必须对这些
无符号字符
数字进行排序,然后取中间的一个。我使用的是Batcher的奇偶合并排序,这很好

我需要尽可能地加快算法的速度。我对程序进行了多次测试,平均结果是3.08秒

排序算法的可视化:如您所见,整个排序过程可分为15个较小的步骤。


我有一个从main调用的顶级函数,名为
MedianFiltering
,它获取进行过滤所需的所有信息,并使用指针将其写回。调用此函数时,将为以下两个函数创建所有必需的控制向量:

\u mm256\u blendv\u epi8()
\u mm256\u permute2f128\u si256()

创建所有必需的控制向量 下一行我有40个(名字都不一样)

比如:

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

因为我可以使用OpenMP,所以并行化可以很好地提高处理速度。我将
#pragma omp parallel for
放在
for
循环的前面,该循环按行计数,但没有任何更改。然后我把它放在按行计数的前面,没有速度增益

在这之后,我想可能问题是,所有开始使用相同控制向量的线程(它们都是顺便读取的)请告诉我,这是否会导致并行化无法产生任何影响

我做了一个实验:我将这个并行化pragma放在代码中的不同位置并运行测试,但不幸的是,没有一个实验显示出高速改进事实上,3.08秒是我得到的最低时间,但这可以在没有任何并行化的情况下实现。


有没有一种方法可以使用并行化来提高我的处理时间?另一种方法将涉及重做排序过程,但我目前对此不感兴趣。

您应该能够在排序网络中使用和
\u mm256\u blendv\u epi8()
,而不是
\u mm256\u max\u epu8
作为比较器。对于压缩RGB,您可能能够并行处理所有3个颜色分量,并在最后解压缩向量。或者,将整个图像解压为平面格式,然后分别对每个组件进行中值滤波,这可能是一个成功。我使用这些最小值和最大值函数进行比较,然后使用blendv将这些向量放在一起。您可以使用
vshufps
或者
vpaligner
组合来自两个向量的数据效率(1个单位)高于
vblendvb
(2个单位)。或者
vpblendd
非常好,如果您可以使用32位粒度的混合
vpblendw
仅在Intel上的端口5上运行(如shuffles),但它是一个单uop。我将在本周末试用它们。
//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;
}