Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bilinear Interpolation, something wrong with my implementation

Tags:

c++

I am trying to implement a bilinear interpolation function, but for some reason I am getting bad output. I cant seem to figure out what's wrong, any help getting on the right track will be appreciated.

double lerp(double c1, double c2, double v1, double v2, double x)
{
if( (v1==v2) ) return c1;
double inc = ((c2-c1)/(v2 - v1)) * (x - v1);
double val = c1 + inc;
return val;
};

void bilinearInterpolate(int width, int height)
{
// if the current size is the same, do nothing
if(width == GetWidth() && height == GetHeight())
    return;

//Create a new image
std::unique_ptr<Image2D> image(new Image2D(width, height));

// x and y ratios
double rx = (double)(GetWidth()) / (double)(image->GetWidth()); // oldWidth / newWidth
double ry = (double)(GetHeight()) / (double)(image->GetHeight());   // oldWidth / newWidth


// loop through destination image
for(int y=0; y<height; ++y)
{
    for(int x=0; x<width; ++x)
    {
        double sx = x * rx;
        double sy = y * ry;

        uint xl = std::floor(sx);
        uint xr = std::floor(sx + 1);
        uint yt = std::floor(sy);
        uint yb = std::floor(sy + 1);

        for (uint d = 0; d < image->GetDepth(); ++d)
        {
            uchar tl    = GetData(xl, yt, d);
            uchar tr    = GetData(xr, yt, d);
            uchar bl    = GetData(xl, yb, d);
            uchar br    = GetData(xr, yb, d);
            double t    = lerp(tl, tr, xl, xr, sx);
            double b    = lerp(bl, br, xl, xr, sx);
            double m    = lerp(t, b, yt, yb, sy);
            uchar val   = std::floor(m + 0.5);
            image->SetData(x,y,d,val);
        }
    }
}

//Cleanup
mWidth = width; mHeight = height;
std::swap(image->mData, mData);
}

Input Image (4 pixels wide and high)

Input Image (4 pixels wide and high)

My Output

My Output

Expected Output (Photoshop's Bilinear Interpolation)

Expected Output (Photoshop's Bilinear Interpolation)

like image 554
aCuria Avatar asked Jan 17 '23 14:01

aCuria


1 Answers

Photoshop's algorithm assumes that each source pixel's color is in the center of the pixel, while your algorithm assumes that the color is in its topleft. This causes your results to be shifted half a pixel up and left compared to Photoshop.

Another way to look at it is that your algorithm maps the x coordinate range (0, srcWidth) to (0, dstWidth), while Photoshop maps (-0.5, srcWidth-0.5) to (-0.5, dstWidth-0.5), and the same in y coordinate.

Instead of:

double sx = x * rx;
double sy = y * ry;

You can use:

double sx = (x + 0.5) * rx - 0.5;
double sy = (y + 0.5) * ry - 0.5;

to get similar results. Note that this can give you a negative value for sx and sy.

like image 54
interjay Avatar answered Jan 25 '23 22:01

interjay