Pergunta

Eu sou portando uma biblioteca de rotinas de manipulação de imagem em C a partir de Java e eu estou recebendo algumas diferenças muito pequenas quando eu comparar os resultados. É razoável que essas diferenças estão nas diferentes línguas manipulação de valores float ou eu ainda tenho trabalho a fazer!

A rotina é Convolution com um kernel 3 x 3, que é operado em um bitmap representado por uma matriz linear de pixels, uma largura e uma profundidade. Você não precisa entender este código exatamente para responder a minha pergunta, é apenas aqui para referência.

código

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; 

Grampo restringe os valores das bandas para o intervalo [0..255] e Color.red é equivalente a (pixel & 0x00FF0000) >> 16.

O código C é assim;

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

É um pouco xOffsets diferentes fornece a xOffset para o elemento do kernel, por exemplo.

O ponto principal é que os meus resultados estão fora por no máximo um pouco. A seguir estão os valores 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

Você acredita que este é um problema com o meu código ou melhor, uma diferença na língua?

Atenciosamente,

Gav

Foi útil?

Solução

Depois de uma rápida olhada:

Você percebe que andar (int) r vontade o valor r em vez de arredondamento normalmente? no código c, você parece uso (int) (r + 0,5)

Outras dicas

Na sequência da resposta do Fortega, tente a função roundf() da matemática C biblioteca .

comportamento de ponto flutuante de Java é bastante preciso. O que eu espero estar acontecendo aqui é que o valor como sendo mantidos em registos com precisão estendida. IIRC, Java exige que a precisão é arredondado para a do tipo apropriado. Esta é tentar garantir que você sempre obter o mesmo resultado (detalhes completos nas JLS). compiladores C tenderá a deixar qualquer precisão adicional lá, até que o resultado em armazenados na memória principal.

Eu sugiro que você use casal em vez de float. Float quase nunca é a melhor escolha.

Isto pode ser devido a diferentes rodada padrão nas duas línguas. Eu não estou dizendo que eles têm (você precisa ler-se para determinar isso), mas é uma idéia.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top