سؤال

أنا أقوم بتنفيذ مكتبة إجراءات معالجة الصور إلى C من جافا وأنا أحصل على بعض الاختلافات الصغيرة للغاية عندما أقارن النتائج. هل من المعقول أن هذه الاختلافات موجودة بلغات مختلفة من القيم العائمة أو هل لا يزال لدي عمل للقيام به!

الروتين هو التنافس مع نواة 3 × 3، يتم تشغيله على صورة نقطية ممثلة بمجموعة خطية من البكسل، وعرض وعمق. لا تحتاج إلى فهم هذا الرمز بالضبط للإجابة على سؤالي، إنه هنا فقط للإشارة.

رمز جافا؛

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 مختلفة قليلا توفر Xoffet لعنصر النواة على سبيل المثال.

النقطة الرئيسية هي أن نتائجي بها على الأكثر قليلا. فيما يلي قيم البكسل؛

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

هل تعتقد أن هذه مشكلة في الرمز الخاص بي أو فرق بلغة بالأحرى؟

أطيب التحيات،

غاف

هل كانت مفيدة؟

المحلول

بعد نظرة سريعة:

هل تدرك أن (int) r سوف الكلمة قيمة r بدلا من تقريبها بشكل طبيعي؟ في رمز C، يبدو أنك تستخدم (int) (R + 0.5)

نصائح أخرى

أبعد إلى إجابة فورتيغا، حاول ال roundf() وظيفة من مكتبة الرياضيات C.

سلوك النقطة العائمة في جافا دقيق للغاية. ما أتوقع أن يحدث هنا هو أن القيمة التي يتم الاحتفاظ بها في السجلات بدقة ممتدة. IIRC، يتطلب Java أن يتم تقريب الدقة إلى هذا النوع المناسب. هذا هو محاولة التأكد من أنك تحصل دائما على نفس النتيجة (التفاصيل الكاملة في JLS). سيتم تحويل مترجمات C إلى ترك أي دقة إضافية هناك، حتى النتيجة المخزنة في الذاكرة الرئيسية.

أود أن أقترح عليك استخدام مزدوج بدلا من تعويم. تعويم ليس تقريبا الخيار الأفضل.

قد يكون هذا بسبب جولة افتراضية مختلفة باللغتين. أنا لا أقول إن لديهم (تحتاج إلى قراءة لتحديد ذلك)، لكنها فكرة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top