Question

Je suis le portage d'une bibliothèque de routines de manipulation d'images en C de Java et je reçois des différences très petites quand je compare les résultats. Est-il raisonnable que ces différences sont dans les différentes langues de manipulation des valeurs de flotteur ou dois-je encore du travail à faire!

La routine est convolution avec un noyau de 3 x 3, il est utilisé sur un bitmap représenté par un réseau linéaire de pixels, une largeur et une profondeur. Vous devez comprendre pas ce code exactement à répondre à ma question, il est juste ici pour référence.

code 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 limite les valeurs de bandes à l'intervalle [0..255] et Color.red est équivalente à (pixel & 0x00FF0000) >> 16.

Le code C va comme ceci;

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

Il est un peu différent xOffsets fournit les xOffset pour l'élément du noyau par exemple.

Le point principal est que mes résultats sont par au plus un peu. Ci-dessous sont des valeurs de pixel;

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

Croyez-vous que cela est un problème avec mon code ou plutôt une différence dans la langue?

Cordialement,

Gav

Était-ce utile?

La solution

Après un rapide coup d'oeil:

vous vous rendez compte que (int) r étage volonté de la valeur r au lieu de l'arrondissement normalement? dans le code c, vous semblez utiliser (int) (r + 0,5)

Autres conseils

Suite à la réponse de Fortega, essayez la fonction roundf() du calcul C bibliothèque .

Le comportement à virgule flottante Java est tout à fait précis. Ce que je pense à se produire ici est que la valeur comme étant conservée dans les registres avec précision étendue. IIRC, Java exige que la précision est arrondie à celle du type approprié. Ceci est d'essayer de vous assurer que vous obtenez toujours le même résultat (les détails du JLS). compilateurs C auront tendance à laisser toute précision supplémentaire là-bas, jusqu'à ce que le résultat dans stocké dans la mémoire principale.

Je vous suggère d'utiliser double au lieu de flotter. Flotteur est presque jamais le meilleur choix.

Cela peut être dû à différents tour par défaut dans les deux langues. Je ne dis pas qu'ils ont (vous avez besoin de lire pour déterminer cela), mais il est une idée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top