Frage

Ich bin Portierung eine Bibliothek von Bildverarbeitungsroutinen in C von Java und ich bin immer einige sehr kleine Unterschiede, wenn ich die Ergebnisse vergleichen. Ist es sinnvoll, dass diese Unterschiede Umgang mit Float-Werten in den verschiedenen Sprachen sind oder habe ich noch Arbeit zu tun!

Die Routine wird Faltung mit einem 3 x 3 Kernel, dann ist es auf einem Bitmap betrieben durch eine lineare Anordnung von Pixeln dargestellt wird, eine Breite und eine Tiefe. Sie müssen diesen Code nicht genau zu verstehen, meine Frage zu beantworten, ist es als Referenz nur hier ist.

Java-Code;

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 beschränkt die Werte Bänder auf den Bereich [0..255] und Color.red ist äquivalent zu (Pixel & 0x00FF0000) >> 16.

Der C-Code lautet wie folgt;

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) ;
        }
    }

Es ist ein wenig anders xOffsets stellt die xOffset für das Kernel-Element zum Beispiel.

Der wichtigste Punkt ist, dass meine Ergebnisse sind out um höchstens ein Bit. Die folgenden sind Pixelwerte;

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

Glauben Sie, das ist ein Problem mit meinem Code oder eher ein Unterschied in der Sprache?

Mit freundlichen Grüßen

Gav

War es hilfreich?

Lösung

Nach einem kurzen Blick:

tun Sie erkennen, dass (int) r Willen Boden der Wert r, anstatt es normalerweise der Rundung? in dem C-Code, Sie scheinen (int) (r + 0,5)

zu verwenden,

Andere Tipps

Im Anschluss an Fortega Antwort, versuchen die roundf() Funktion aus der C math Bibliothek .

Java Floating-Point-Verhalten ist sehr präzise. Was erwarte ich hier zu geschehen ist, dass der Wert als in den Registern mit erweiterter Genauigkeit gehalten wird. IIRC, erfordert Java, dass die Genauigkeit der von den entsprechenden Typ abgerundet ist. Dies ist zu versuchen, sicherzustellen, dass Sie immer das gleiche Ergebnis (weitere Informationen in der JLS) erhalten. C-Compiler wird dazu neigen, jede zusätzliche Präzision dort zu lassen, bis das Ergebnis gespeichert in dem Hauptspeicher.

Ich würde vorschlagen, dass Sie doppelt statt float verwenden. Float ist so gut wie nie die beste Wahl.

Dies könnte aufgrund unterschiedlicher Standard-Runde in den beiden Sprachen sein. Ich sage nicht, dass sie (Sie müssen, dass lesen, um zu bestimmen), aber es ist eine Idee.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top