繁体   English   中英

卷积滤波器 - Float Precision C Vs Java

[英]Convolution Filter - Float Precision C Vs Java

我正在将一个图像处理例程库从Java移植到C中,当我比较结果时,我得到了一些非常小的差异。 这些差异在于不同语言对浮动值的处理是否合理,还是我还有工作要做!

例程是使用3 x 3内核的卷积,它在由线性像素阵列,宽度和深度表示的位图上操作。 您无需完全理解这段代码来回答我的问题,它只是供参考。

Java代码;

for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                int offset = (y*width)+x;
                if(x % (width-1) == 0 || y % (height-1) == 0){
                    input.setPixel(x, y, 0xFF000000); // Alpha channel only for border
                } else {
                    float r = 0;
                    float g = 0;
                    float b = 0;
                    for(int kx = -1 ; kx <= 1; kx++ ){
                        for(int ky = -1 ; ky <= 1; ky++ ){
                            int pixel = pix[offset+(width*ky)+kx];
                            int t1 = Color.red(pixel);
                            int t2 = Color.green(pixel);
                            int t3 = Color.blue(pixel);

                            float m = kernel[((ky+1)*3)+kx+1];

                            r += Color.red(pixel) * m;
                            g += Color.green(pixel) * m;
                            b += Color.blue(pixel) * m;                     
                        }
                    }
                    input.setPixel(x, y, Color.rgb(clamp((int)r), clamp((int)g), clamp((int)b)));
                }
            }
        }
        return input; 

Clamp将波段的值限制在[0..255]范围内,Color.red相当于(pixel&0x00FF0000)>> 16。

C代码是这样的;

for(x=1;x<width-1;x++){
        for(y=1; y<height-1; y++){
            offset = x + (y*width);
            rAcc=0;
            gAcc=0;
            bAcc=0;
            for(z=0;z<kernelLength;z++){
                xk = x + xOffsets[z];
                yk = y + yOffsets[z];
                kOffset = xk + (yk * width);

                rAcc += kernel[z] * ((b1[kOffset] & rMask)>>16);
                gAcc += kernel[z] * ((b1[kOffset] & gMask)>>8);
                bAcc += kernel[z] * (b1[kOffset] & bMask);
            }

            // Clamp values
            rAcc = rAcc > 255 ? 255 : rAcc < 0 ? 0 : rAcc;
            gAcc = gAcc > 255 ? 255 : gAcc < 0 ? 0 : gAcc;
            bAcc = bAcc > 255 ? 255 : bAcc < 0 ? 0 : bAcc;


            // Round the floats
                    r = (int)(rAcc + 0.5);
            g = (int)(gAcc + 0.5);
            b = (int)(bAcc + 0.5);

            output[offset] = (a|r<<16|g<<8|b) ;
        }
    }

它有点不同xOffsets为内核元素提供了xOffset。

重点是我的结果最多只有一点。 以下是像素值;

FF205448 expected
FF215449 returned
44 wrong
FF56977E expected
FF56977F returned
45 wrong
FF4A9A7D expected
FF4B9B7E returned
54 wrong
FF3F9478 expected
FF3F9578 returned
74 wrong
FF004A12 expected
FF004A13 returned

你认为这是我的代码的问题,还是相反的语言差异?

亲切的问候,

GAV

快速浏览一下:

你是否意识到(int)r会将r值置于底层而不是正常舍入? 在c代码中,你似乎使用(int)(r + 0.5)

继Fortega的回答之后,尝试C数学库中的roundf()函数

Java的浮点行为非常精确。 我期望在这里发生的是将值保存在寄存器中并具有更高的精度。 IIRC,Java要求精度四舍五入到相应类型的精度。 这是为了确保您始终获得相同的结果(JLS中的完整详细信息)。 C编译器会在那里留下任何额外的精度,直到结果存储到主存储器中。

我建议你使用double而不是float。 Float几乎不是最好的选择。

这可能是由于两种语言中的默认轮次不同。 我不是说他们有(你需要阅读以确定),但这是一个想法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM