質問

私は、JavaからCにイメージ操作ルーチンのライブラリを移植していると私は結果を比較するとき、私はいくつかの非常に小さな違いを取得しています。それはこれらの違いは、浮動小数点値の異なる言語扱いにされているか、私はまだやるべき仕事を持っていないことに合理的です!

ルーチンは、画素の線形アレイ、幅および深さによって表されるビットマップ上で動作'S、3×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; 

クランプ[0..255]の範囲にバンド値を制限し、Color.redは(ピクセル&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プロパティを提供しています。

主なポイントは、私の結果は、せいぜい1ビットだけ出ているということです。以下の画素値である。

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コンパイラは、メインメモリに記憶され、その結果まで、そこに余分な精度を残す傾向がある。

私はあなたが二重の代わりにフロートの使用を示唆しています。フロートはほとんど最良の選択になることはありません。

これは、二つの言語の異なるデフォルトのラウンドが原因である可能性があります。私は(あなたがそれを決定するまで読む必要がある)、彼らが持って言っていないんだけど、それはアイデアだ。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top