【OpenCV基础】第二十课:像素重映射

像素重映射,cv::remap,最近邻插值,双线性插值

Posted by x-jeff on June 29, 2021

本文为原创文章,未经本人允许,禁止转载。转载请注明出处。

1.像素重映射

简单点说,像素重映射就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像。例如:

2.相关API

1
2
3
4
5
6
7
8
9
void remap( 
	InputArray src, 
	OutputArray dst,
	InputArray map1, 
	InputArray map2,
	int interpolation, 
	int borderMode = BORDER_CONSTANT,
	const Scalar& borderValue = Scalar()
);

参数解释:

  1. InputArray src:输入图像。
  2. OutputArray dst:输出图像。大小和map1相同,图像类型和src相同。
  3. InputArray map1:$x$坐标的映射表或$(x,y)$坐标对的映射表。图像类型可为CV_16SC2CV_32FC1CV_32FC2。个人理解:当map1为$x$坐标的映射表时,其图像类型应该是单通道,即CV_32FC1;而当map1为$(x,y)$坐标对的映射表时,其图像类型应该是双通道,即CV_16SC2CV_32FC2
  4. InputArray map2:$y$坐标的映射表。图像类型可为CV_16UC1CV_32FC1或者为空(即none,当map1为$(x,y)$坐标对的映射表时,map2可为空)。
  5. int interpolation:插值方法。
  6. int borderMode图像边缘处理方式
  7. const Scalar& borderValue:填充边缘所用的像素值。

3.常见的插值方法

在放大图像时,通常需要进行插值操作:

OpenCV提供的插值方法有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//! interpolation algorithm
enum InterpolationFlags{
    /** nearest neighbor interpolation */
    INTER_NEAREST        = 0,
    /** bilinear interpolation */
    INTER_LINEAR         = 1,
    /** bicubic interpolation */
    INTER_CUBIC          = 2,
    /** resampling using pixel area relation. It may be a preferred method for image decimation, as
    it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST
    method. */
    INTER_AREA           = 3,
    /** Lanczos interpolation over 8x8 neighborhood */
    INTER_LANCZOS4       = 4,
    /** Bit exact bilinear interpolation */
    INTER_LINEAR_EXACT = 5,
    /** mask for interpolation codes */
    INTER_MAX            = 7,
    /** flag, fills all of the destination image pixels. If some of them correspond to outliers in the
    source image, they are set to zero */
    WARP_FILL_OUTLIERS   = 8,
    /** flag, inverse transformation

    For example, #linearPolar or #logPolar transforms:
    - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$
    - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$
    */
    WARP_INVERSE_MAP     = 16
};

3.1.INTER_NEAREST

INTER_NEAREST为最近邻插值,会选择最近的点。

如上图所示,黑色的X表示需要插入的值,它会选择距离它最近的$P_{x+1,y}$的值来作为它的值。

当插入的值距离四个点都相等时,会选择距离最近的左上角的值:

3.2.INTER_LINEAR

这里的INTER_LINEAR指的是双线性插值。

假设我们想得到未知函数$f$在点$P(x,y)$的值,假设我们已知函数$f$在$Q_{11}=(x_1,y_1),Q_{12}=(x_1,y_2),Q_{21}=(x_2,y_1),Q_{22}=(x_2,y_2)$四个点的值。

先计算函数$f$在点$R_1,R_2$的值:

\[f(R_1) \approx \frac{x_2-x}{x_2-x_1} f(Q_{11})+\frac{x-x_1}{x_2-x_1} f(Q_{21})\] \[f(R_2) \approx \frac{x_2-x}{x_2-x_1} f(Q_{12}) + \frac{x-x_1}{x_2-x_1} f(Q_{22})\]

然后估计函数$f$在点$P$的值:

\[\begin{align} f(P) & \approx \frac{y_2-y}{y_2-y_1} f(R_1) + \frac{y-y_1}{y_2-y_1} f(R_2) \\& = \frac{y_2-y}{y_2-y_1} ( \frac{x_2-x}{x_2-x_1} f(Q_{11})+\frac{x-x_1}{x_2-x_1} f(Q_{21}) ) + \frac{y-y_1}{y_2-y_1} ( \frac{x_2-x}{x_2-x_1} f(Q_{12}) + \frac{x-x_1}{x_2-x_1} f(Q_{22}) ) \\&= \frac{1}{(x_2-x_1)(y_2-y_1)} ( f(Q_{11})(x_2-x)(y_2-y) + f(Q_{21})(x-x_1)(y_2-y) + f(Q_{12})(x_2-x)(y-y_1)+f(Q_{22})(x-x_1)(y-y_1) ) \\&= \frac{1}{(x_2-x_1)(y_2-y_1)} \begin{bmatrix} x_2-x & x-x_1 \end{bmatrix} \begin{bmatrix} f(Q_{11}) & f(Q_{12}) \\ f(Q_{21}) & f(Q_{22}) \end{bmatrix} \begin{bmatrix} y_2-y \\ y-y_1 \end{bmatrix} \end{align}\]

仔细观察上面的公式不难发现,其实$P$点的值等于周围四个点与$P$点所构成的四个对角矩形面积的加权平均:

4.代码地址

  1. 像素重映射

5.参考资料

  1. opencv中插值算法详解