Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Image processing SIMD像素对比度:像素与其相邻像素之间的差异总和(uint16\t颜色分量、浮点和)?_Image Processing_Assembly_X86_Sse_Avx - Fatal编程技术网

Image processing SIMD像素对比度:像素与其相邻像素之间的差异总和(uint16\t颜色分量、浮点和)?

Image processing SIMD像素对比度:像素与其相邻像素之间的差异总和(uint16\t颜色分量、浮点和)?,image-processing,assembly,x86,sse,avx,Image Processing,Assembly,X86,Sse,Avx,使用SIMD/assembler用绝对值(最大差值)减去2个uint16s并将结果加(+=)到浮点的最佳方法是什么 类似于这个C'ish的例子 c0 += fabs((float)a0 - (float)b0); // C is Float accumulator, a+b pixels 其中a和b是无符号16位字,c是浮点。只有1个字->浮点转换,而不是3个 应用程序一次处理尽可能多的完整RGB像素上的原始16位无符号整数图像数据 是否可能在Skylake Xeon E3-1275 v5上

使用SIMD/assembler用绝对值(最大差值)减去2个uint16s并将结果加(+=)到浮点的最佳方法是什么

类似于这个C'ish的例子

c0 += fabs((float)a0 - (float)b0);  // C is Float accumulator, a+b pixels
其中a和b是无符号16位字,c是浮点。只有1个字->浮点转换,而不是3个

应用程序一次处理尽可能多的完整RGB像素上的原始16位无符号整数图像数据

是否可能在Skylake Xeon E3-1275 v5上使用AVX2/SSE4.2


5分钟评论限制??无法保存或重新编辑

你确定你需要浮球吗? Uint16不能累积超过1个减法。我想做一个邻里对比计算,所以我需要求和至少8个差异。深度为D的邻域中有(2D+1)^2-1个邻域。我还希望能够平方的差异,这是一个uint32可以太小。我认为浮标看起来也更平滑

这里有一点更多的背景知识,关于什么已经起作用以及我想如何改进它

为了澄清这一点,我当前的C代码计算固定主像素与8个或更多相邻像素之间的每通道差异。它有一个5层的嵌套循环结构: 图像中每个像素的Y行和X列(3600万) 通道,R.G&B为环路3 循环4和5用于邻域的行和列

对于每个主像素 清除R、G和B蓄能器 对于每个邻居,
向红色浮动蓄能器添加abs(主红色-nabr红色) 绿色和蓝色也一样 将累积值复制到主存储器

我的下一步是将通道移动到5级,并使用SIMD同时执行所有3个减法,R、G和B。每个MMX寄存器有48位/像素和128位可用,可以一次完成2位而不是1位

Skylake Xeon上的AVX2中有512位寄存器,可以完成10个。我正在寻找一个很好的策略来平衡复杂性和性能,并进一步了解这些向量操作

我需要R,G和B累加器为每个“主”像素。然后将RGB移动到与uint16/通道原始RGB文件具有相同XY分辨率的“浮动图像”中。对每个像素执行相同的对比度计算

关于无符号整数绝对值的问题:做两次饱和减法。一个结果是零,另一个是绝对值。将它们与逻辑OR组合。在将16b整数解包到32b整数或浮点之前,这样做是最便宜的

在从word解包到dword之前,我们肯定要进行减法运算,所以只有一个值需要解包。执行单个非饱和减法,然后稍后再对其进行排序(例如,在转换为FP后将符号位掩蔽为零)是行不通的。存在一个范围问题:有符号的int16\u t不能保持两个uint16\u t值之间差的完整范围。UINT16_MAX将环绕,看起来像-1->abs的差1。另外,它的缺点是需要一个标志来扩展解包

与AVX2一样,由于某些指令的车道内行为和其他指令的交叉车道行为,将数据解包到不同的矢量宽度是最令人头痛的问题

vpunpcklwd
在每个128b车道内解包,与
vpackusdw
匹配。
vpmovzxwd ymm,xmm
没有单一的指令反转,因此我将使用
punpck
指令,前提是您可以用这种方式安排浮点数。(使用PMOVZX,您不能直接从上半部分开始。您必须
vextract128
/
vpmovzx

#包括
//未经测试
__m256添加pixdiff(uuuM256 c[2]、uuuM256i a、uuuM256i b)
{
__m256i ab=_mm256_subs_epu16(a,b);//0或abs(a-b)
__m256i ba=_mm256_subs_epu16(b,a);//abs(a-b)或0
__m256i abs_ab_diff=_mm256_或_si256(ab,ba);
__m256i低单元=_mm256_unplo_epi16(abs_ab_diff,_mm256_setzero_si256());
__m256i hi_uints=_mm256_unpachi_epi16(abs_ab_diff,_mm256_setzero_si256());
__m256低浮点数=_mm256_cvtepi32_ps(低浮点数);
__m256高浮点数=_mm256_cvtepi32_ps(高浮点数);
//如果数据可能未对齐,请使用load and store intrinsic。
c[0]=\u mm256\u add\u ps(c[0],lo\u float);
c[1]=\u mm256\u add\u ps(c[1],高位浮动);
返回c[0];
}
它,在门闩上。要在循环中使用,最好手动将其内联。您不希望一个愚蠢的编译器实际使用内存中的数组对两个浮点向量进行引用调用。我只是将其包装在一个函数中,以保持其简单性并隐藏加载/存储

请注意,
uint16
输入的一个向量产生两个浮点结果向量。我们可以一次操作整数向量128b,但一次操作256b意味着我们得到3个INSN(不计算负载)+2个解包的2个结果,而不是6个INSN+2个pmovzx。这里有相当多的并行性:两个减法可以并行进行,并且有两个解包和转换的依赖链。(不过,Skylake只有一个随机端口,因此您无法同时获得两个解包。这是一条道内指令,与其他跨道指令一样,它的延迟为3。如果您需要将浮点保持在与int相同的顺序,而不仅仅是重新打包回INT,那么并行性将很重要最后的顺序相同。)

Vector FP add在Skylake上的延迟增加到4(在以前的Intel设计中为3),但吞吐量增加到每时钟两个。(它在FMA装置上运行。没错,skylake的FMA的延迟降低到了4c)


我假设您实际上并不想要SAD(一个累加器代表所有差异),因为您是以标量形式编写
c0
,而不是
c

如果你想要一个悲伤的(绝对差异的总和),那
#include <immintrin.h>

// untested
__m256 add_pixdiff(__m256 c[2], __m256i a, __m256i b)
{
    __m256i ab = _mm256_subs_epu16(a, b);  // 0        or abs(a-b)
    __m256i ba = _mm256_subs_epu16(b, a);  // abs(a-b) or 0
    __m256i abs_ab_diffs = _mm256_or_si256(ab, ba);

    __m256i lo_uints = _mm256_unpacklo_epi16(abs_ab_diffs, _mm256_setzero_si256());
    __m256i hi_uints = _mm256_unpackhi_epi16(abs_ab_diffs, _mm256_setzero_si256());

    __m256 lo_floats = _mm256_cvtepi32_ps(lo_uints);
    __m256 hi_floats = _mm256_cvtepi32_ps(hi_uints);

    // use load and store intrinsics if the data might not be aligned.
    c[0] = _mm256_add_ps(c[0], lo_floats);
    c[1] = _mm256_add_ps(c[1], hi_floats);
    return c[0];
 }
// probably convert the image to planar outside the loop
// rather than dealing with packed components on the fly,
// since you read the same src pixel many times
// (comparing it to a different dst pixel each time).

for (dst_row) {
    for (dst_col) {
        for (r, g, b) {  
            // if you convert to planar, make this the outer-most loop for cache reasons
            for (src_row) {
                for (src_col) {
                    accumulate stuff;
                }
            }
        }
        result[drow][dcol].r = sum over some range of red   src rows X cols;
        result[drow][dcol].g = sum over some range of green src rows X cols;
        result[drow][dcol].b = sum over some range of blue  src rows X cols;
    }
}