插值
插值,是根据已知的数据序列(可以理解为你坐标中一系列离散的点),找到其中的规律,然后根据找到的这个规律,来对其中尚未有数据记录的点
应用
- 对缺失的数据进行补偿
- 对图像进行放大缩小
通用公式

 如上图,该公式为通用公式。可以看到,该公式为线性变化
常见的传统插值方法有
最邻近插值(0阶线性插值)
解释:取相邻最近的值。实际中可用四舍五入操作
 这是最简单的一种插值方法,不需要计算,在待求象素的四邻象素中,将距离待求象素最近邻的像素灰度赋给待求象素。设为待求象素坐标(x+u,y+v) ,【注:x,y为整数, u,v为大于零小于1的小数】则待求象素灰度的值 f(x+u,y+v)为 ,选取距离插入的像素点(x+u, y+v)最近的一个像素点,用它的像素点的灰度值代替插入的像素点。
特点:最近邻插值法虽然计算量较小,但可能会造成插值生成的图像灰度上的不连续,在灰度变化的地方可能出现明显的锯齿状。
线性插值
解释:根据公式计算得出中间值,只有一个未知量。若两边界之差为最小单位时,则与最邻近插值一致
 
 上图是一个一维线性插值的定量示意图,x0 和 x1 都是原有的坐标点,灰度值分别对应为 y0 和 y1。而灰度值未知的插值点 x,根据线性插值法约束,在 (x0, y0) 和 (x1, y1) 构成的一次函数上,其灰度值 y 即为
 
双线性插值
解释:双线性插值常见于二维平面,通过坐标关系,求解xy。核心思想是在两个方向上分别进行一次线性插值.
 
 上图是一个二维双线性插值的定量俯视示意图 (点位稍有变动但不影响),我们换个顺序。先由像素坐标点 (x0, y0) 和 (x1, y0) 在 x 轴向作一维线性插值得到 f(x, y0)、由像素坐标点 (x0, y1) 和 (x1, y1) 在 x 轴向作一维线性插值得到 f(x, y1):
 
 
 然后再由 (x, y0) 和 (x, y1) 在 y 轴向作一维线性插值得到插值点 (x, y) 的灰度值 f(x, y):
 
 合并上式,得到最终的双线性插值结果:
 
 特点:双线性内插法的计算比最邻近点法复杂,计算量较大,但没有灰度不连续的缺点,结果基本令人满意。它具有低通滤波性质,使高频分量受损,图像轮廓可能会有一点模糊。
e.g.
// 二维图像缩放
void imagePixelProcess(BYTE* destData, int destW, int destH, BYTE* srcData, int srcW, int srcH, bool redFull, int* idList, int channel /*= 3*/)
{
	auto funcImageNearestScale = [destData, srcData, destW, srcW, channel](int destX, int destY, double scaleX, double scaleY) -> void
	{
		// NOTE 缩放,公式:destX * rx = srcW, destY * ry = srcH
		int srcX = std::round(scaleX * destX), srcY = std::round(scaleY * destY);
		memcpy(destData + (destY * destW + destX) * channel, srcData + (srcY * srcW + srcX) * channel, sizeof(BYTE) * channel);
	};
	auto funcDrawReconstructionArea = [destData, destW, srcW, idList, channel](int destX, int destY, double scaleX, double scaleY) -> void
	{
		int srcX = std::round(scaleX * destX), srcY = std::round(scaleY * destY);
		int lSrcX = destX < 1 ? 0 : std::ceil(scaleX * destX - scaleX), rSrcX = destX == (destW - 1) ? srcW - 1 : std::floor(scaleX * destX + scaleX);
		for (int i = lSrcX; i <= rSrcX; i++)
		{
			if (idList[srcY * srcW + i] != -1)
			{
				destData[(destY * destW + destX) * channel] = 0;
				destData[(destY * destW + destX) * channel + 1] = 0;
			}
		}
	};
	auto funcRedFullImage = [destData, destW, channel](int destX, int destY) -> void
	{
		auto redPxielIndex = (destY * destW + destX) * channel;
		if (destData[redPxielIndex] == 255 && destData[redPxielIndex + 1] == 255 && destData[redPxielIndex + 2] == 255)
		{
			destData[redPxielIndex + 1] = 0;
			destData[redPxielIndex + 2] = 0;
		}
	};
	double rx = srcW / (double)destW, ry = srcH / (double)destH;
	memcpy(destData, srcData, sizeof(BYTE) * channel);
	for (int destY = 0; destY < destH; destY++)
	{
		for (int destX = 0; destX < destW; destX++)
		{
			funcImageNearestScale(destX, destY, rx, ry);
			if (idList != nullptr)
			{
				funcDrawReconstructionArea(destX, destY, rx, ry);
			}
			if (redFull)
			{
				funcRedFullImage(destX, destY);
			}
		}
	}
	destData += (destW * destH) * channel;
}
双三次插值
略,用到时详解
参考文章
[1] 【图像处理】详解 最近邻插值、线性插值、双线性插值、双三次插值
 [2] 常用线性插值的介绍和应用(双线性插值,三线性插值,平滑曲线插值
 [3] 常用的三种插值算法



















