0

I just implemented bicubic interpolation for resizing images. I have a test image 6x6 pixels (grayscale), its columns are black and white (x3). I am comparing the results of my code with the results from the tool ffmpeg and they are not correct. I can not understand why, I think I may be calculating the neighbourhood of pixels wrong or maybe the distance of the resized pixel to the original ones. Can someone look into my code (I will simplify it for better reading) and tell me where the error is?

    // Iterate through each line
    for(int lin = 0; lin < dstHeight; lin++){
        // Original coordinates
        float linInOriginal = (lin - 0.5) / scaleHeightRatio;

        // Calculate original pixels coordinates to interpolate
        int linTopFurther = clamp(floor(linInOriginal) - 1, 0, srcHeight - 1);
        int linTop = clamp(floor(linInOriginal), 0, srcHeight - 1);
        int linBottom = clamp(ceil(linInOriginal), 0, srcHeight - 1);
        int linBottomFurther = clamp(ceil(linInOriginal) + 1, 0, srcHeight - 1);

        // Calculate distance to the top left pixel
        float linDist = linInOriginal - floor(linInOriginal);

        // Iterate through each column
        for(int col = 0; col < dstWidth; col++){
            // Original coordinates
            float colInOriginal = (col - 0.5) / scaleWidthRatio;

            // Calculate original pixels coordinates to interpolate
            int colLeftFurther = clamp(floor(colInOriginal) - 1, 0, srcWidth - 1);
            int colLeft = clamp(floor(colInOriginal), 0, srcWidth - 1);
            int colRight = clamp(ceil(colInOriginal), 0, srcWidth - 1);
            int colRightFurther = clamp(ceil(colInOriginal) + 1, 0, srcWidth - 1);

            // Calculate distance to the top left pixel
            float colDist = colInOriginal - floor(colInOriginal);

            // Gets the original pixels values
            // 1st row
            uint8_t p00 = srcSlice[0][linTopFurther * srcWidth + colLeftFurther];
            // ...

            // 2nd row
            uint8_t p01 = srcSlice[0][linTop * srcWidth + colLeftFurther];
            // ...

            // 3rd row
            // ...

            // 4th row
            // ...

            // Bilinear interpolation operation
            // Y
            float value = cubicInterpolate(
                cubicInterpolate(static_cast<float>(p00), static_cast<float>(p10), static_cast<float>(p20), static_cast<float>(p30), colDist),
                cubicInterpolate(static_cast<float>(p01), static_cast<float>(p11), static_cast<float>(p21), static_cast<float>(p31), colDist),
                cubicInterpolate(static_cast<float>(p02), static_cast<float>(p12), static_cast<float>(p22), static_cast<float>(p32), colDist),
                cubicInterpolate(static_cast<float>(p03), static_cast<float>(p13), static_cast<float>(p23), static_cast<float>(p33), colDist),
                linDist);

            dstSlice[0][lin * dstWidth + col] = double2uint8_t(clamp(value, 0.0f, 255.0f));
        }
    }
Pedro Pereira
  • 312
  • 5
  • 21
  • 1
    I'm not sure I understand the code fully, but just in case: a) did you consider different pixel formats? especially packed and planar. b) the inner "Iterate through each column" loop, are you sure it will be "dstWidth" and not dstStride (aka linesize) ? – the kamilz Mar 07 '18 at 07:39
  • @thekamilz I am sure it is not a pixel format problem since, for the sake of code simplicity, I resample the image to yuv444 planar before scaling. so, during this process I am only working with a plane at a time. Do you have any snippet of bicubic algorithm of your own that I can give it a look? – Pedro Pereira Mar 07 '18 at 08:09
  • 1
    No, I don't have any bicubic algorithm of myself, since ffmpeg already has it I'm actually using ffmpeg's implementation. But in past we develop some 8bit yuv to 10bit yuv and vice versa format conversion functions and send ffmpeg as patches similar to `planarToP010Wrapper` on `swscale_unscaled.c` on under `libswscale` folder (FFmpeg source). – the kamilz Mar 07 '18 at 11:52
  • @thekamilz either way, thank you for your time – Pedro Pereira Mar 07 '18 at 13:33
  • I think you already seen this but just in case: https://github.com/yglukhov/bicubic-interpolation-image-processing – the kamilz Mar 07 '18 at 14:00

1 Answers1

0

I was forgetting to set the values of the second degree variables of the interpolation matrix. They were set to 0, so the resulting interpolation would resemble the bilinear interpolation.

Pedro Pereira
  • 312
  • 5
  • 21