📄 warpimage.cpp
字号:
///////////////////////////////////////////////////////////////////////////
//
// NAME
// WarpImage.cpp -- warp an image either through a global parametric
// transform or a local (per-pixel) transform
//
// SEE ALSO
// WarpImage.h longer description of functions
//
// DESIGN
// For cubic interpolation, we have a choice of several (variants of)
// interpolation functions. In general, we can use any family
// of 4-tap filters. In particular, we will use piecewise-cubic
// functions that are interpolating and constant and linear preserving.
//
// We furthermore make the restriction that the interpolant is C1
// (not all interpolants do this). This leaves us with only one
// degree of freedom: the slope at (x=1), which we call "a".
//
// For the implementation, we form a LUT for the cubic interpolation
// function, and initialize it at the beginning of each image warp
// (in case "a" has changed).
//
// Copyright ?Richard Szeliski, 2001. See Copyright.h for more details
//
///////////////////////////////////////////////////////////////////////////
#include "Image.h"
#include "Transform.h"
#include "WarpImage.h"
#include <math.h>
#include <vector>
//
// Bilinear interpolation: cascade horizontal and vertical resamplings
//
static inline float ResampleLinear(float v0, float v1, float f)
{
return v0 + f * (v1 - v0);
}
template <class T>
static inline T ResampleBiLinear(T src[], int oH, int oV, float xf, float yf)
{
// Resample a pixel using bilinear interpolation
float h1 = ResampleLinear(src[0 ], src[ oH], xf);
float h2 = ResampleLinear(src[oV], src[oV+oH], xf);
float v = ResampleLinear(h1, h2, yf);
return (T) v;
}
//
// Bicubic interpolation: cascade horizontal and vertical resamplings
//
static const int cubicLUTsize = 256;
static float cubicInterp[cubicLUTsize][4];
static void InitializeCubicLUT(float a)
{
float zero = 0.0; // not implemented yet
float error = 1.0f / zero;
}
static inline float ResampleCubic(float v0, float v1, float v2, float v3, float f)
{
int fi = int(f*cubicLUTsize);
float *c = cubicInterp[fi];
float v = c[0]*v0 + c[1]*v1 + c[2]*v2 + c[3]*v3;
return v;
}
template <class T>
static T ResampleBiCubic(T src[], int oH, int oV, float xf, float yf)
{
// Resample a pixel using bilinear interpolation
float h[4];
for (int i = 0; i < 4; i++)
{
int j = (i-1)*oV;
h[i] = ResampleCubic(src[j-oH], src[j], src[j+oH], src[j+2*oH], xf);
}
float v = ResampleCubic(h[0], h[1], h[2], h[3], yf);
return (T) v;
}
//
// Resample a complete line, given the source pixel addresses
//
template <class T>
void WarpLine(CImageOf<T> src, T* dstP, float *xyP, int n, int nBands,
EWarpInterpolationMode interp, T minVal, T maxVal)
{
// Determine the interpolator's "footprint"
const int o0 = int(interp)/2; // negative extent
const int o1 = int(interp) - o0; // positive extent
const int oH = nBands; // horizonal offset between pixels
const int oV = &src.Pixel(0, 1, 0) -
&src.Pixel(0, 0, 0); // vertical offset between pixels
CShape sh = src.Shape();
// Resample a single output scanline
for (int i = 0; i < n; i++, dstP += nBands, xyP += 2)
{
// Round down pixel coordinates
int x = int(floor(xyP[0]));
int y = int(floor(xyP[1]));
// Check if all participating pixels are in bounds
if (! (sh.InBounds(x-o0, y-o0) && sh.InBounds(x+o1, y+o1)))
{
for (int j = 0; j < nBands; j++)
dstP[j] = 0;
continue;
}
T* srcP = &src.Pixel(x, y, 0);
// Nearest-neighbor: just copy pixels
if (interp == eWarpInterpNearest)
{
for (int j = 0; j < nBands; j++)
dstP[j] = srcP[j];
continue;
}
float xf = xyP[0] - x;
float yf = xyP[1] - y;
// Bilinear and bi-cubic
if (interp == eWarpInterpLinear)
{
for (int j = 0; j < nBands; j++)
dstP[j] = __max(minVal, __min(maxVal,
ResampleBiLinear(&srcP[j], oH, oV, xf, yf)));
}
if (interp == eWarpInterpCubic)
{
for (int j = 0; j < nBands; j++)
dstP[j] = __max(minVal, __min(maxVal,
ResampleBiCubic(&srcP[j], oH, oV, xf, yf)));
}
}
}
//
// Resample a complete image, given source pixel addresses
//
template <class T>
void WarpLocal(CImageOf<T> src, CImageOf<T>& dst,
CFloatImage uv, bool relativeCoords,
EWarpInterpolationMode interp, float cubicA)
{
// Check that dst is of the right shape
CShape sh(uv.Shape().width, uv.Shape().height, src.Shape().nBands);
dst.ReAllocate(sh);
// Allocate a row buffer for coordinates
int n = sh.width;
std::vector<float> rowBuf;
rowBuf.resize(n*2);
// Precompute the cubic interpolant
if (interp == eWarpInterpCubic)
InitializeCubicLUT(cubicA);
// Process each row
for (int y = 0; y < sh.height; y++)
{
float *uvP = &uv .Pixel(0, y, 0);
float *xyP = (relativeCoords) ? &rowBuf[0] : uvP;
T *dstP = &dst.Pixel(0, y, 0);
// Convert to absolute coordinates if necessary
if (relativeCoords)
{
for (int x = 0; x < n; x++)
{
xyP[2*x+0] = x + uvP[2*x+0];
xyP[2*x+1] = y + uvP[2*x+1];
}
}
// Resample the line
WarpLine(src, dstP, xyP, n, sh.nBands, interp, src.MinVal(), src.MaxVal());
}
}
//
// Resample a complete image, given dst->src pixel transformation
//
template <class T>
void WarpGlobal(CImageOf<T> src, CImageOf<T>& dst,
CTransform3x3 M,
EWarpInterpolationMode interp, float cubicA)
{
// Not implemented yet, since haven't decided on semantics of M yet...
// Check that dst is of a valid shape
if (dst.Shape().width == 0)
dst.ReAllocate(src.Shape());
CShape sh = dst.Shape();
// Allocate a row buffer for coordinates
int n = sh.width;
std::vector<float> rowBuf;
rowBuf.resize(n*2);
// Precompute the cubic interpolant
if (interp == eWarpInterpCubic)
InitializeCubicLUT(cubicA);
// Process each row
for (int y = 0; y < sh.height; y++)
{
float *xyP = &rowBuf[0];
T *dstP = &dst.Pixel(0, y, 0);
// Compute pixel coordinates
float X0 = (float) (M[0][1]*y + M[0][2]);
float dX = (float) M[0][0];
float Y0 = (float) (M[1][1]*y + M[1][2]);
float dY = (float) M[1][0];
float Z0 = (float) (M[2][1]*y + M[2][2]);
float dZ = (float) M[2][0];
bool affine = (dZ == 0.0);
float Zi = 1.0f / Z0; // TODO: doesn't guard against divide by 0
if (affine)
{
X0 *= Zi, dX *= Zi, Y0 *= Zi, dY *= Zi;
}
for (int x = 0; x < n; x++)
{
xyP[2*x+0] = X0 * Zi;
xyP[2*x+1] = Y0 * Zi;
X0 += dX;
Y0 += dY;
if (! affine)
{
Z0 += dZ;
Zi = 1.0f / Z0;
}
}
// Resample the line
WarpLine(src, dstP, xyP, n, sh.nBands, interp, src.MinVal(), src.MaxVal());
}
}
// Instantiate the code
void WarpInstantiate(void)
{
CByteImage i1;
CFloatImage uv1;
WarpLocal(i1, i1, uv1, false, eWarpInterpLinear, 1.0f);
CTransform3x3 M;
WarpGlobal(i1, i1, M, eWarpInterpLinear, 1.0f);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -