我正在尝试实现双线性插值函数,但由于某种原因我得到了糟糕的输出.我似乎无法弄清楚什么是错的,任何帮助走上正轨都将受到赞赏.
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);
}
Run Code Online (Sandbox Code Playgroud)

输入图像(4像素宽和高)

我的输出

预期输出(Photoshop的双线性插值)
Photoshop的算法假设每个源像素的颜色都在像素的中心,而您的算法假定颜色在其中.与Photoshop相比,这会使您的结果向上和向左移动半个像素.
看它的另一种方法是,你的算法的x坐标范围映射(0, srcWidth)到(0, dstWidth),而Photoshop的映射(-0.5, srcWidth-0.5)来(-0.5, dstWidth-0.5),并在y坐标相同.
代替:
double sx = x * rx;
double sy = y * ry;
Run Code Online (Sandbox Code Playgroud)
您可以使用:
double sx = (x + 0.5) * rx - 0.5;
double sy = (y + 0.5) * ry - 0.5;
Run Code Online (Sandbox Code Playgroud)
得到类似的结果.请注意,这可以给你一个负值sx和sy.
| 归档时间: |
|
| 查看次数: |
3438 次 |
| 最近记录: |