原理:详细参见https://en.wikipedia.org/wiki/Bicubic_interpolation
在数学上,双立方插值是2个变量函数在方形网格上立方插值的一个扩展,在图像处理中,双立方插值考虑插值像素点周围16个像素,当不在乎算法执行速度时,一般选择双立方插值,相对最近邻域插值和二次线性插值,双立方插值具有较少的插值畸变(artifacts ,不知道翻译成什么好)。
双立方插值与最近邻域插值和二次线性插值的比较如下图:
假设在(0,0),(1,0),(0,1),(1,1)单位正方形四个顶点函数值f 及其偏导数 f x , f y f y 和 f x y f x y f_{x}, {\displaystyle f_{y}} f_y 和 {\displaystyle f_{xy}} f_{xy} fx,fyfy和fxyfxy已知,那么,单位正方形内部任意点的插值可以表示为:
p ( x , y ) = ∑ i = 0 3 ∑ j = 0 3 a i j x i y j p(x,y) = \sum\limits_{i=0}^3 \sum_{j=0}^3 a_{ij} x^i y^j p(x,y)=i=0∑3j=0∑3aijxiyj
因此插值问题变成求解16个参数的问题,四个点 ( 0 , 0 ) , ( 1 , 0 ) , ( 0 , 1 ) , 和 ( 1 , 1 ) (0,0), {\displaystyle (1,0)} , {\displaystyle (0,1)}, 和{\displaystyle } (1,1) (0,0),(1,0),(0,1),和(1,1)代入上式可得:
f ( 0 , 0 ) = p ( 0 , 0 ) = a 00 , f ( 1 , 0 ) = p ( 1 , 0 ) = a 00 + a 10 + a 20 + a 30 , f ( 0 , 1 ) = p ( 0 , 1 ) = a 00 + a 01 + a 02 + a 03 , f ( 1 , 1 ) = p ( 1 , 1 ) = ∑ i = 0 3 ∑ j = 0 3 a i j . {\displaystyle f(0,0)=p(0,0)=a_{00},}\newline {\displaystyle f(1,0)=p(1,0)=a_{00}+a_{10}+a_{20}+a_{30},} \newline {\displaystyle f(0,1)=p(0,1)=a_{00}+a_{01}+a_{02}+a_{03},}\newline {\displaystyle f(1,1)=p(1,1)=\textstyle \sum \limits _{i=0}^{3}\sum \limits _{j=0}^{3}a_{ij}.} f(0,0)=p(0,0)=a00,f(1,0)=p(1,0)=a00+a10+a20+a30,f(0,1)=p(0,1)=a00+a01+a02+a03,f(1,1)=p(1,1)=i=0∑3j=0∑3aij.
根据4个点x和y方向上的偏导数,可得8个方程:
f x ( 0 , 0 ) = p x ( 0 , 0 ) = a 10 , f x ( 1 , 0 ) = p x ( 1 , 0 ) = a 10 + 2 a 20 + 3 a 30 , f x ( 0 , 1 ) = p x ( 0 , 1 ) = a 10 + a 11 + a 12 + a 13 , f x ( 1 , 1 ) = p x ( 1 , 1 ) = ∑ i = 1 3 ∑ j = 0 3 a i j i , f y ( 0 , 0 ) = p y ( 0 , 0 ) = a 01 , f y ( 1 , 0 ) = p y ( 1 , 0 ) = a 01 + a 11 + a 21 + a 31 , f y ( 0 , 1 ) = p y ( 0 , 1 ) = a 01 + 2 a 02 + 3 a 03 , f y ( 1 , 1 ) = p y ( 1 , 1 ) = ∑ i = 0 3 ∑ j = 1 3 a i j j . {\displaystyle f_{x}(0,0)=p_{x}(0,0)=a_{10},}\newline {\displaystyle f_{x}(1,0)=p_{x}(1,0)=a_{10}+2a_{20}+3a_{30},}\newline {\displaystyle f_{x}(0,1)=p_{x}(0,1)=a_{10}+a_{11}+a_{12}+a_{13},}\newline {\displaystyle f_{x}(1,1)=p_{x}(1,1)=\textstyle \sum \limits _{i=1}^{3}\sum \limits _{j=0}^{3}a_{ij}i,}\newline {\displaystyle f_{y}(0,0)=p_{y}(0,0)=a_{01},}\newline {\displaystyle f_{y}(1,0)=p_{y}(1,0)=a_{01}+a_{11}+a_{21}+a_{31},} \newline{\displaystyle f_{y}(0,1)=p_{y}(0,1)=a_{01}+2a_{02}+3a_{03},}\newline {\displaystyle f_{y}(1,1)=p_{y}(1,1)=\textstyle \sum \limits _{i=0}^{3}\sum \limits _{j=1}^{3}a_{ij}j.}\newline fx(0,0)=px(0,0)=a10,fx(1,0)=px(1,0)=a10+2a20+3a30,fx(0,1)=px(0,1)=a10+a11+a12+a13,fx(1,1)=px(1,1)=i=1∑3j=0∑3aiji,fy(0,0)=py(0,0)=a01,fy(1,0)=py(1,0)=a01+a11+a21+a31,fy(0,1)=py(0,1)=a01+2a02+3a03,fy(1,1)=py(1,1)=i=0∑3j=1∑3aijj.
四个点上的二阶混合偏导数(mixed partial derivative)可得四个方程:
f x y ( 0 , 0 ) = p x y ( 0 , 0 ) = a 11 , f x y ( 1 , 0 ) = p x y ( 1 , 0 ) = a 11 + 2 a 21 + 3 a 31 , f x y ( 0 , 1 ) = p x y ( 0 , 1 ) = a 11 + 2 a 12 + 3 a 13 , f x y ( 1 , 1 ) = p x y ( 1 , 1 ) = ∑ i = 1 3 ∑ j = 1 3 a i j i j . {\displaystyle f_{xy}(0,0)=p_{xy}(0,0)=a_{11},}\newline {\displaystyle f_{xy}(1,0)=p_{xy}(1,0)=a_{11}+2a_{21}+3a_{31},} \newline {\displaystyle f_{xy}(0,1)=p_{xy}(0,1)=a_{11}+2a_{12}+3a_{13},}\newline {\displaystyle f_{xy}(1,1)=p_{xy}(1,1)=\textstyle \sum \limits _{i=1}^{3}\sum \limits _{j=1}^{3}a_{ij}ij.} fxy(0,0)=pxy(0,0)=a11,fxy(1,0)=pxy(1,0)=a11+2a21+3a31,fxy(0,1)=pxy(0,1)=a11+2a12+3a13,fxy(1,1)=pxy(1,1)=i=1∑3j=1∑3aijij.
上面的四个混合偏导数还可以表示为:
p x ( x , y ) = ∑ i = 1 3 ∑ j = 0 3 a i j i x i − 1 y j , p y ( x , y ) = ∑ i = 0 3 ∑ j = 1 3 a i j x i j y j − 1 , p x y ( x , y ) = ∑ i = 1 3 ∑ j = 1 3 a i j i x i − 1 j y j − 1 . {\displaystyle p_{x}(x,y)=\textstyle \sum \limits _{i=1}^{3}\sum \limits _{j=0}^{3}a_{ij}ix^{i-1}y^{j},}\newline {\displaystyle p_{y}(x,y)=\textstyle \sum \limits _{i=0}^{3}\sum \limits _{j=1}^{3}a_{ij}x^{i}jy^{j-1},}\newline {\displaystyle p_{xy}(x,y)=\textstyle \sum \limits _{i=1}^{3}\sum \limits _{j=1}^{3}a_{ij}ix^{i-1}jy^{j-1}.} px(x,y)=i=1∑3j=0∑3aijixi−1yj,py(x,y)=i=0∑3j=1∑3aijxijyj−1,pxy(x,y)=i=1∑3j=1∑3aijixi−1jyj−1.
将 a i j a_{ij} aij组合成一个向量:
α = [ a 00 a 10 a 20 a 30 a 01 a 11 a 21 a 31 a 02 a 12 a 22 a 32 a 03 a 13 a 23 a 33 ] T \alpha=\left[\begin{matrix}a_{00}&a_{10}&a_{20}&a_{30}&a_{01}&a_{11}&a_{21}&a_{31}&a_{02}&a_{12}&a_{22}&a_{32}&a_{03}&a_{13}&a_{23}&a_{33}\end{matrix}\right]^T α=[a00a10a20a30a01a11a21a31a02a12a22a32a03a13a23a33]T令:
x = [ f ( 0 , 0 ) f ( 1 , 0 ) f ( 0 , 1 ) f ( 1 , 1 ) f x ( 0 , 0 ) f x ( 1 , 0 ) f x ( 0 , 1 ) f x ( 1 , 1 ) f y ( 0 , 0 ) f y ( 1 , 0 ) f y ( 0 , 1 ) f y ( 1 , 1 ) f x y ( 0 , 0 ) f x y ( 1 , 0 ) f x y ( 0 , 1 ) f x y ( 1 , 1 ) ] T , {\displaystyle x=\left[{\begin{matrix}f(0,0)&f(1,0)&f(0,1)&f(1,1)&f_{x}(0,0)&f_{x}(1,0)&f_{x}(0,1)&f_{x}(1,1)&f_{y}(0,0)&f_{y}(1,0)&f_{y}(0,1)&f_{y}(1,1)&f_{xy}(0,0)&f_{xy}(1,0)&f_{xy}(0,1)&f_{xy}(1,1)\end{matrix}}\right]^{T},} x=[f(0,0)f(1,0)f(0,1)f(1,1)fx(0,0)fx(1,0)fx(0,1)fx(1,1)fy(0,0)fy(1,0)fy(0,1)fy(1,1)fxy(0,0)fxy(1,0)fxy(0,1)fxy(1,1)]T,
上面的16个式子可以写成 A α = x A\alpha=x Aα=x,求解这个线性方程组可得 a i j a_{ij} aij。
A A A的逆矩阵如下:
A − 1 = [ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 − 3 3 0 0 − 2 − 1 0 0 0 0 0 0 0 0 0 0 2 − 2 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 − 3 3 0 0 − 2 − 1 0 0 0 0 0 0 0 0 0 0 2 − 2 0 0 1 1 0 0 − 3 0 3 0 0 0 0 0 − 2 0 − 1 0 0 0 0 0 0 0 0 0 − 3 0 3 0 0 0 0 0 − 2 0 − 1 0 9 − 9 − 9 9 6 3 − 6 − 3 6 − 6 3 − 3 4 2 2 1 − 6 6 6 − 6 − 3 − 3 3 3 − 4 4 − 2 2 − 2 − 2 − 1 − 1 2 0 − 2 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 2 0 − 2 0 0 0 0 0 1 0 1 0 − 6 6 6 − 6 − 4 − 2 4 2 − 3 3 − 3 3 − 2 − 1 − 2 − 1 4 − 4 − 4 4 2 2 − 2 − 2 2 − 2 2 − 2 1 1 1 1 ] {\displaystyle A^{-1}=\left[{\begin{matrix}1&0&0&0&0&0&0&0&0&0&0&0&0&0&0&0\\0&0&0&0&1&0&0&0&0&0&0&0&0&0&0&0\\-3&3&0&0&-2&-1&0&0&0&0&0&0&0&0&0&0\\2&-2&0&0&1&1&0&0&0&0&0&0&0&0&0&0\\0&0&0&0&0&0&0&0&1&0&0&0&0&0&0&0\\0&0&0&0&0&0&0&0&0&0&0&0&1&0&0&0\\0&0&0&0&0&0&0&0&-3&3&0&0&-2&-1&0&0\\0&0&0&0&0&0&0&0&2&-2&0&0&1&1&0&0\\-3&0&3&0&0&0&0&0&-2&0&-1&0&0&0&0&0\\0&0&0&0&-3&0&3&0&0&0&0&0&-2&0&-1&0\\9&-9&-9&9&6&3&-6&-3&6&-6&3&-3&4&2&2&1\\-6&6&6&-6&-3&-3&3&3&-4&4&-2&2&-2&-2&-1&-1\\2&0&-2&0&0&0&0&0&1&0&1&0&0&0&0&0\\0&0&0&0&2&0&-2&0&0&0&0&0&1&0&1&0\\-6&6&6&-6&-4&-2&4&2&-3&3&-3&3&-2&-1&-2&-1\\4&-4&-4&4&2&2&-2&-2&2&-2&2&-2&1&1&1&1\end{matrix}}\right]} A−1=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡10−320000−309−620−64003−2000000−96006−40000000030−96−206−400000000009−600−6401−2100000−36−302−4200−110000003−300−220000000003−630−24−20000000000−33002−2000010−32−206−410−320000003−200−64003−200000000−103−210−320000000000−32003−2000001−210−24−201−21000000−11002−200−11000000000−12−101−2100000000001−100−11⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
另外,上面的16个方程的简明表示:
[ f ( 0 , 0 ) f ( 0 , 1 ) f y ( 0 , 0 ) f y ( 0 , 1 ) f ( 1 , 0 ) f ( 1 , 1 ) f y ( 1 , 0 ) f y ( 1 , 1 ) f x ( 0 , 0 ) f x ( 0 , 1 ) f x y ( 0 , 0 ) f x y ( 0 , 1 ) f x ( 1 , 0 ) f x ( 1 , 1 ) f x y ( 1 , 0 ) f x y ( 1 , 1 ) ] = [ 1 0 0 0 1 1 1 1 0 1 0 0 0 1 2 3 ] [ a 00 a 01 a 02 a 03 a 10 a 11 a 12 a 13 a 20 a 21 a 22 a 23 a 30 a 31 a 32 a 33 ] [ 1 1 0 0 0 1 1 1 0 1 0 2 0 1 0 3 ] , {\displaystyle {\begin{bmatrix}f(0,0)&f(0,1)&f_{y}(0,0)&f_{y}(0,1)\\f(1,0)&f(1,1)&f_{y}(1,0)&f_{y}(1,1)\\f_{x}(0,0)&f_{x}(0,1)&f_{xy}(0,0)&f_{xy}(0,1)\\f_{x}(1,0)&f_{x}(1,1)&f_{xy}(1,0)&f_{xy}(1,1)\end{bmatrix}}={\begin{bmatrix}1&0&0&0\\1&1&1&1\\0&1&0&0\\0&1&2&3\end{bmatrix}}{\begin{bmatrix}a_{00}&a_{01}&a_{02}&a_{03}\\a_{10}&a_{11}&a_{12}&a_{13}\\a_{20}&a_{21}&a_{22}&a_{23}\\a_{30}&a_{31}&a_{32}&a_{33}\end{bmatrix}}{\begin{bmatrix}1&1&0&0\\0&1&1&1\\0&1&0&2\\0&1&0&3\end{bmatrix}},} ⎣⎢⎢⎡f(0,0)f(1,0)fx(0,0)fx(1,0)f(0,1)f(1,1)fx(0,1)fx(1,1)fy(0,0)fy(1,0)fxy(0,0)fxy(1,0)fy(0,1)fy(1,1)fxy(0,1)fxy(1,1)⎦⎥⎥⎤=⎣⎢⎢⎡1100011101020103⎦⎥⎥⎤⎣⎢⎢⎡a00a10a20a30a01a11a21a31a02a12a22a32a03a13a23a33⎦⎥⎥⎤⎣⎢⎢⎡1000111101000123⎦⎥⎥⎤,
等式右边两边左乘 [ 1 0 0 0 1 1 1 1 0 1 0 0 0 1 2 3 ] {\begin{bmatrix}1&0&0&0\\1&1&1&1\\0&1&0&0\\0&1&2&3\end{bmatrix}} ⎣⎢⎢⎡1100011101020103⎦⎥⎥⎤的逆矩阵,然后右乘 [ 1 1 0 0 0 1 1 1 0 1 0 2 0 1 0 3 ] {\begin{bmatrix}1&1&0&0\\0&1&1&1\\0&1&0&2\\0&1&0&3\end{bmatrix}} ⎣⎢⎢⎡1000111101000123⎦⎥⎥⎤的逆矩阵,可得:
[ a 00 a 01 a 02 a 03 a 10 a 11 a 12 a 13 a 20 a 21 a 22 a 23 a 30 a 31 a 32 a 33 ] = [ 1 0 0 0 0 0 1 0 − 3 3 − 2 − 1 2 − 2 1 1 ] [ f ( 0 , 0 ) f ( 0 , 1 ) f y ( 0 , 0 ) f y ( 0 , 1 ) f ( 1 , 0 ) f ( 1 , 1 ) f y ( 1 , 0 ) f y ( 1 , 1 ) f x ( 0 , 0 ) f x ( 0 , 1 ) f x y ( 0 , 0 ) f x y ( 0 , 1 ) f x ( 1 , 0 ) f x ( 1 , 1 ) f x y ( 1 , 0 ) f x y ( 1 , 1 ) ] [ 1 0 − 3 2 0 0 3 − 2 0 1 − 2 1 0 0 − 1 1 ] , {\displaystyle {\begin{bmatrix}a_{00}&a_{01}&a_{02}&a_{03}\\a_{10}&a_{11}&a_{12}&a_{13}\\a_{20}&a_{21}&a_{22}&a_{23}\\a_{30}&a_{31}&a_{32}&a_{33}\end{bmatrix}}={\begin{bmatrix}1&0&0&0\\0&0&1&0\\-3&3&-2&-1\\2&-2&1&1\end{bmatrix}}{\begin{bmatrix}f(0,0)&f(0,1)&f_{y}(0,0)&f_{y}(0,1)\\f(1,0)&f(1,1)&f_{y}(1,0)&f_{y}(1,1)\\f_{x}(0,0)&f_{x}(0,1)&f_{xy}(0,0)&f_{xy}(0,1)\\f_{x}(1,0)&f_{x}(1,1)&f_{xy}(1,0)&f_{xy}(1,1)\end{bmatrix}}{\begin{bmatrix}1&0&-3&2\\0&0&3&-2\\0&1&-2&1\\0&0&-1&1\end{bmatrix}},} ⎣⎢⎢⎡a00a10a20a30a01a11a21a31a02a12a22a32a03a13a23a33⎦⎥⎥⎤=⎣⎢⎢⎡10−32003−201−2100−11⎦⎥⎥⎤⎣⎢⎢⎡f(0,0)f(1,0)fx(0,0)fx(1,0)f(0,1)f(1,1)fx(0,1)fx(1,1)fy(0,0)fy(1,0)fxy(0,0)fxy(1,0)fy(0,1)fy(1,1)fxy(0,1)fxy(1,1)⎦⎥⎥⎤⎣⎢⎢⎡10000010−33−2−12−211⎦⎥⎥⎤,
p ( x , y ) p(x,y) p(x,y)插值可由下式给出:
p ( x , y ) = [ 1 x x 2 x 3 ] [ a 00 a 01 a 02 a 03 a 10 a 11 a 12 a 13 a 20 a 21 a 22 a 23 a 30 a 31 a 32 a 33 ] [ 1 y y 2 y 3 ] . {\displaystyle p(x,y)={\begin{bmatrix}1&x&x^{2}&x^{3}\end{bmatrix}}{\begin{bmatrix}a_{00}&a_{01}&a_{02}&a_{03}\\a_{10}&a_{11}&a_{12}&a_{13}\\a_{20}&a_{21}&a_{22}&a_{23}\\a_{30}&a_{31}&a_{32}&a_{33}\end{bmatrix}}{\begin{bmatrix}1\\y\\y^{2}\\y^{3}\end{bmatrix}}.} p(x,y)=[1xx2x3]⎣⎢⎢⎡a00a10a20a30a01a11a21a31a02a12a22a32a03a13a23a33⎦⎥⎥⎤⎣⎢⎢⎡1yy2y3⎦⎥⎥⎤.
差分计算可以采用下面公式,参考:https://en.wikipedia.org/wiki/Finite_difference
f x ( x , y ) ≈ f ( x + h , y ) − f ( x − h , y ) 2 h f y ( x , y ) ≈ f ( x , y + k ) − f ( x , y − k ) 2 k f x x ( x , y ) ≈ f ( x + h , y ) − 2 f ( x , y ) + f ( x − h , y ) h 2 f y y ( x , y ) ≈ f ( x , y + k ) − 2 f ( x , y ) + f ( x , y − k ) k 2 f x y ( x , y ) ≈ f ( x + h , y + k ) − f ( x + h , y − k ) − f ( x − h , y + k ) + f ( x − h , y − k ) 4 h k {\displaystyle {\begin{aligned}f_{x}(x,y)&\approx {\frac {f(x+h,y)-f(x-h,y)}{2h}}\\f_{y}(x,y)&\approx {\frac {f(x,y+k)-f(x,y-k)}{2k}}\\f_{xx}(x,y)&\approx {\frac {f(x+h,y)-2f(x,y)+f(x-h,y)}{h^{2}}}\\f_{yy}(x,y)&\approx {\frac {f(x,y+k)-2f(x,y)+f(x,y-k)}{k^{2}}}\\f_{xy}(x,y)&\approx {\frac {f(x+h,y+k)-f(x+h,y-k)-f(x-h,y+k)+f(x-h,y-k)}{4hk}}\end{aligned}}} fx(x,y)fy(x,y)fxx(x,y)fyy(x,y)fxy(x,y)≈2hf(x+h,y)−f(x−h,y)≈2kf(x,y+k)−f(x,y−k)≈h2f(x+h,y)−2f(x,y)+f(x−h,y)≈k2f(x,y+k)−2f(x,y)+f(x,y−k)≈4hkf(x+h,y+k)−f(x+h,y−k)−f(x−h,y+k)+f(x−h,y−k)
h = 1 h=1 h=1
另外一种实现如下:
上面的实现对每个 p ( x , y ) p(x,y) p(x,y)都要求解一个线性方程,可以采用卷积方式达到同样的目的,卷积核如下:
W ( x ) = { ( a + 2 ) ∣ x ∣ 3 − ( a + 3 ) ∣ x ∣ 2 + 1 for ∣ x ∣ ≤ 1 , a ∣ x ∣ 3 − 5 a ∣ x ∣ 2 + 8 a ∣ x ∣ − 4 a for 1 < ∣ x ∣ < 2 , 0 otherwise , {\displaystyle W(x)={\begin{cases}(a+2)|x|^{3}-(a+3)|x|^{2}+1&{\text{for }}|x|\leq 1,\\a|x|^{3}-5a|x|^{2}+8a|x|-4a&{\text{for }}1<|x|<2,\\0&{\text{otherwise}},\end{cases}}} W(x)=⎩⎪⎨⎪⎧(a+2)∣x∣3−(a+3)∣x∣2+1a∣x∣3−5a∣x∣2+8a∣x∣−4a0for ∣x∣≤1,for 1<∣x∣<2,otherwise,
a = − 0.5 a=-0.5 a=−0.5。
上式可以表示成矩阵形式:
p ( t ) = 1 2 [ 1 t t 2 t 3 ] [ 0 2 0 0 − 1 0 1 0 2 − 5 4 − 1 − 1 3 − 3 1 ] [ f − 1 f 0 f 1 f 2 ] {\displaystyle p(t)={\tfrac {1}{2}}{\begin{bmatrix}1&t&t^{2}&t^{3}\\\end{bmatrix}}{\begin{bmatrix}0&2&0&0\\-1&0&1&0\\2&-5&4&-1\\-1&3&-3&1\\\end{bmatrix}}{\begin{bmatrix}f_{-1}\\f_{0}\\f_{1}\\f_{2}\\\end{bmatrix}}} p(t)=21[1tt2t3]⎣⎢⎢⎡0−12−120−53014−300−11⎦⎥⎥⎤⎣⎢⎢⎡f−1f0f1f2⎦⎥⎥⎤
对图像进行插值时,可以先进行x方向插值,然后再进行y方向插值。
b − 1 = p ( t x , f ( − 1 , − 1 ) , f ( 0 , − 1 ) , f ( 1 , − 1 ) , f ( 2 , − 1 ) ) , b 0 = p ( t x , f ( − 1 , 0 ) , f ( 0 , 0 ) , f ( 1 , 0 ) , f ( 2 , 0 ) ) , b 1 = p ( t x , f ( − 1 , 1 ) , f ( 0 , 1 ) , f ( 1 , 1 ) , f ( 2 , 1 ) ) , b 2 = p ( t x , f ( − 1 , 2 ) , f ( 0 , 2 ) , f ( 1 , 2 ) , f ( 2 , 2 ) ) , p ( x , y ) = p ( t y , b − 1 , b 0 , b 1 , b 2 ) . {\displaystyle b_{-1}=p(t_{x},f_{(-1,-1)},f_{(0,-1)},f_{(1,-1)},f_{(2,-1)}),}\newline {\displaystyle b_{0}=p(t_{x},f_{(-1,0)},f_{(0,0)},f_{(1,0)},f_{(2,0)}),} \newline {\displaystyle b_{1}=p(t_{x},f_{(-1,1)},f_{(0,1)},f_{(1,1)},f_{(2,1)}),} \newline {\displaystyle b_{2}=p(t_{x},f_{(-1,2)},f_{(0,2)},f_{(1,2)},f_{(2,2)}),}\newline {\displaystyle p(x,y)=p(t_{y},b_{-1},b_{0},b_{1},b_{2}).}\newline b−1=p(tx,f(−1,−1),f(0,−1),f(1,−1),f(2,−1)),b0=p(tx,f(−1,0),f(0,0),f(1,0),f(2,0)),b1=p(tx,f(−1,1),f(0,1),f(1,1),f(2,1)),b2=p(tx,f(−1,2),f(0,2),f(1,2),f(2,2)),p(x,y)=p(ty,b−1,b0,b1,b2).
算法实现
方法一:
static inline void matrix_mul(float c[4][4], float a[4][4], float b[4][4])
{
int n, k;
for (n = 0; n < 4; n++)
{
for (k = 0; k < 4; k++)
{
c[n][k] = a[n][0] * b[0][k] + a[n][1] * b[1][k] + a[n][2] * b[2][k] + a[n][3] * b[3][k];
}
}
}
void img_resize_using_bicubic(uint8_2d* src, uint8_2d* dst)
{
int src_rows, src_cols;
int dst_rows, dst_cols;
int i, j;
if (!src || !dst)return;
uint8_t** src_arr;
uint8_t** dst_arr;
float xratio;
float yratio;
float x, y;
int xi, yi;
int xminus1, yminus1;
int xadd1, yadd1;
int xadd2, yadd2;
float u, v;
float u2, u3;
float v2, v3;
int val;
src_arr = src->arr;
dst_arr = dst->arr;
src_rows = src->rows;
src_cols = src->cols;
dst_rows = dst->rows;
dst_cols = dst->cols;
float m1[4][4] = { { 1, 0, 0, 0 },
{ 0, 0, 1, 0},
{-3, 3, -2,-1},
{ 2,-2, 1, 1} };
float m0[4][4] = { { 1, 0, -3, 2 },
{ 0, 0, 3, -2 },
{ 0, 1, -2, 1 },
{ 0, 0, -1, 1 } };
float d[4][4];
float a[4][4];
xratio = (float)src_cols / (float)dst_cols;
yratio = (float)src_rows / (float)dst_rows;
int v00, v01, v02, v03;
int v10, v11, v12, v13;
int v20, v21, v22, v23;
int v30, v31, v32, v33;
float tmp[4];
for (i = 0; i < dst_rows; i++)
{
for (j = 0; j < dst_cols; j++)
{
x = xratio*j;
y = yratio*i;
xi = (int)x;
yi = (int)y;
u = x - xi;
v = y - yi;
xminus1 = xi - 1;
yminus1 = yi - 1;
xadd1 = xi + 1;
yadd1 = yi + 1;
xadd2 = xi + 2;
yadd2 = yi + 2;
if (xi >= src_cols)xi = src_cols - 1;
if (yi >= src_rows)yi = src_rows - 1;
if (xminus1 < 0)xminus1 = 0;
if (yminus1 < 0)yminus1 = 0;
if (xadd1 >= src_cols)xadd1 = src_cols - 1;
if (yadd1 >= src_rows)yadd1 = src_rows - 1;
if (xadd2 >= src_cols)xadd2 = src_cols - 1;
if (yadd2 >= src_rows)yadd2 = src_rows - 1;
v00 = src_arr[yminus1][xminus1];
v01 = src_arr[yminus1][xi];
v02 = src_arr[yminus1][xadd1];
v03 = src_arr[yminus1][xadd2];
v10 = src_arr[yi][xminus1];
v11 = src_arr[yi][xi];
v12 = src_arr[yi][xadd1];
v13 = src_arr[yi][xadd2];
v20 = src_arr[yadd1][xminus1];
v21 = src_arr[yadd1][xi];
v22 = src_arr[yadd1][xadd1];
v23 = src_arr[yadd1][xadd2];
v30 = src_arr[yadd2][xminus1];
v31 = src_arr[yadd2][xi];
v32 = src_arr[yadd2][xadd1];
v33 = src_arr[yadd2][xadd2];
d[0][0] = v11;//f00
d[0][1] = v21;//f01
d[1][0] = v12;//f10
d[1][1] = v22;//f11
//d[0][2] = (v21-v01)/2.0;//fy00
//d[0][3] = (v31-v11)/2.0;//fy01
//d[1][2] = (v22-v02)/2.0;//fy10;
//d[1][3] = (v32-v12)/2.0;//fy11;
//d[2][0] = (v12-v10)/2.0;//fx00;
//d[2][1] = (v22-v20)/2.0;//fx01;
//d[3][0] = (v13-v11)/2.0;//fx10;
//d[3][1] = (v23-v21)/2.0;//fx11;
//这里采用sobel算子求一阶偏导数,为了避免引入一些噪声
d[0][2] = (v20 + 2*v21+v22 - v00 - 2*v01- v02) / 8.0;//fy00
d[0][3] = (v30 + 2*v31+v32 - v10 - 2*v11- v12) / 8.0;//fy01
d[1][2] = (v21 + 2*v22+v23 - v01 - 2*v02- v03) / 8.0;//fy10;
d[1][3] = (v31 + 2*v32+v33 - v11 - 2*v12- v13) / 8.0;//fy11;
d[2][0] = (v02 + 2*v12+v22 - v00 - 2*v10 - v20) / 8.0;//fx00;
d[2][1] = (v12 + 2*v22+v32 - v10 - 2*v20 - v30) / 8.0;//fx01;
d[3][0] = (v03 + 2*v13+v23 - v01 - 2*v11 - v21) / 8.0;//fx10;
d[3][1] = (v13 + 2*v23+v33 - v11 - 2*v21 - v31) / 8.0;//fx11;
d[2][2] = (v22+v00-v02-v20) / 4.0; //fxy00
d[2][3] = (v32+v10-v30-v12) / 4.0; //fxy01;
d[3][2] = (v23+v01-v03-v21) / 4.0; //fxy10;
d[3][3] = (v33+v11-v13-v31) / 4.0; //fxy11
matrix_mul(a, d, m0);
matrix_mul(d, m1, a);
u2 = u*u;
u3 = u2*u;
v2 = v*v;
v3 = v2*v;
tmp[0] = d[0][0] + d[0][1] * v + d[0][2] * v2 + d[0][3] * v3;
tmp[1] = d[1][0] + d[1][1] * v + d[1][2] * v2 + d[1][3] * v3;
tmp[2] = d[2][0] + d[2][1] * v + d[2][2] * v2 + d[2][3] * v3;
tmp[3] = d[3][0] + d[3][1] * v + d[3][2] * v2 + d[3][3] * v3;
val = tmp[0] + tmp[1] * u + tmp[2] * u2 + tmp[3] * u3;
if (val < 0)val = 0;
if (val > 255)val = 255;
dst_arr[i][j] = val;
}
}
}
方法二:
static inline void matrix_mul1(float c[4], float a[4][4], float b[4])
{
int n;
for (n = 0; n < 4; n++)
{
c[n] = a[n][0] * b[0] + a[n][1] * b[1] + a[n][2] * b[2] + a[n][3] * b[3];
}
}
void img_resize_using_bicubic1(uint8_2d* src, uint8_2d* dst)
{
int src_rows, src_cols;
int dst_rows, dst_cols;
int i, j;
if (!src || !dst)return;
uint8_t** src_arr;
uint8_t** dst_arr;
float xratio;
float yratio;
float x, y;
int xi, yi;
int xminus1, yminus1;
int xadd1, yadd1;
int xadd2, yadd2;
float u, v;
float u2, u3;
float v2, v3;
int val;
src_arr = src->arr;
dst_arr = dst->arr;
src_rows = src->rows;
src_cols = src->cols;
dst_rows = dst->rows;
dst_cols = dst->cols;
float m[4][4] = { { 0, 2, 0, 0},
{ -1, 0, 1, 0},
{ 2, -5, 4, -1},
{ -1, 3, -3, 1}};
xratio = (float)src_cols / (float)dst_cols;
yratio = (float)src_rows / (float)dst_rows;
float tmp[4];
float pix[4];
float b[4];
for (i = 0; i < dst_rows; i++)
{
for (j = 0; j < dst_cols; j++)
{
x = xratio*j;
y = yratio*i;
xi = (int)x;
yi = (int)y;
u = x - xi;
v = y - yi;
xminus1 = xi - 1;
yminus1 = yi - 1;
xadd1 = xi + 1;
yadd1 = yi + 1;
xadd2 = xi + 2;
yadd2 = yi + 2;
if (xi >= src_cols)xi = src_cols - 1;
if (yi >= src_rows)yi = src_rows - 1;
if (xminus1 < 0)xminus1 = 0;
if (yminus1 < 0)yminus1 = 0;
if (xadd1 >= src_cols)xadd1 = src_cols - 1;
if (yadd1 >= src_rows)yadd1 = src_rows - 1;
if (xadd2 >= src_cols)xadd2 = src_cols - 1;
if (yadd2 >= src_rows)yadd2 = src_rows - 1;
u2 = u*u;
u3 = u2*u;
v2 = v*v;
v3 = v2*v;
pix[0] = src_arr[yminus1][xminus1];
pix[1] = src_arr[yminus1][xi];
pix[2] = src_arr[yminus1][xadd1];
pix[3] = src_arr[yminus1][xadd2];
matrix_mul1(tmp, m, pix);
b[0] = 0.5*(tmp[0] + tmp[1] * u + tmp[2] * u2 + tmp[3] * u3);
pix[0] = src_arr[yi][xminus1];
pix[1] = src_arr[yi][xi];
pix[2] = src_arr[yi][xadd1];
pix[3] = src_arr[yi][xadd2];
matrix_mul1(tmp, m, pix);
b[1] = 0.5*(tmp[0] + tmp[1] * u + tmp[2] * u2 + tmp[3] * u3);
pix[0] = src_arr[yadd1][xminus1];
pix[1] = src_arr[yadd1][xi];
pix[2] = src_arr[yadd1][xadd1];
pix[3] = src_arr[yadd1][xadd2];
matrix_mul1(tmp, m, pix);
b[2] = 0.5*(tmp[0] + tmp[1] * u + tmp[2] * u2 + tmp[3] * u3);
pix[0] = src_arr[yadd2][xminus1];
pix[1] = src_arr[yadd2][xi];
pix[2] = src_arr[yadd2][xadd1];
pix[3] = src_arr[yadd2][xadd2];
matrix_mul1(tmp, m, pix);
b[3] = 0.5*(tmp[0] + tmp[1] * u + tmp[2] * u2 + tmp[3] * u3);
matrix_mul1(tmp, m, b);
val = 0.5*(tmp[0] + tmp[1] * v + tmp[2] * v2 + tmp[3] * v3);
if (val < 0)val = 0;
if (val > 255)val = 255;
dst_arr[i][j] = val;
}
}
}
测试代码:
void test_bicubic_resize(dai_image* img, float factor)
{
uint8_2d* r = NULL;
uint8_2d* g = NULL;
uint8_2d* b = NULL;
uint8_2d* r1 = NULL;
uint8_2d* g1 = NULL;
uint8_2d* b1 = NULL;
dai_image* img1 = NULL;
if (!img)return;
split_img_data(img, &r, &g, &b);
int w, h;
int w1, h1;
w = img->width;
h = img->height;
w1 = factor*w;
h1 = factor*h;
r1 = create_uint8_2d(h1, w1);
g1 = create_uint8_2d(h1, w1);
b1 = create_uint8_2d(h1, w1);
if (factor < 1.0)
{
real_2d* kernel = create_gaussian_kernel(1.4);
real_2d* r2 = uint8_to_real(r->data, r->cols, r->rows);
gaussian_blur(r2, kernel, 0);
real_2d* g2 = uint8_to_real(g->data, g->cols, g->rows);
gaussian_blur(g2, kernel, 0);
real_2d* b2 = uint8_to_real(b->data, b->cols, b->rows);
gaussian_blur(b2, kernel, 0);
destroy_uint8_2d(&r);
destroy_uint8_2d(&g);
destroy_uint8_2d(&b);
r = real_to_uint8(r2);
g = real_to_uint8(g2);
b = real_to_uint8(b2);
}
img_resize_using_bicubic(r, r1);
img_resize_using_bicubic(g, g1);
img_resize_using_bicubic(b, b1);
merge_img_data(r1, g1, b1, &img1);
if (img1)
{
img1->type = EJPEG;
dai_save_image("resize_bicubic.jpg",img1);
dai_destroy_image(&img1);
}
destroy_uint8_2d(&r);
destroy_uint8_2d(&g);
destroy_uint8_2d(&b);
destroy_uint8_2d(&r1);
destroy_uint8_2d(&g1);
destroy_uint8_2d(&b1);
}
对于scale小于1.0的情况,需要先进行低通滤波然后再进行亚采样插值,split_img_data和merge_img_data可以参看本人上一篇关于二次线性插值的博客。