根据变换矩阵的不同,可以分为三种变形方法,分别是:仿射变换、相似变换、刚性变换。其中刚性变换的效果是最好的,这边主要讲最简单的仿射变换,其余的只要替换一下变换矩阵即可实现。
坐标变换一般分为:绕中心的旋转变换 + 平移变换。
l v ( v ) = ( v − p ∗ ) M + q ∗ l_v(v) = (v - p_*)M + q_* lv(v)=(v−p∗)M+q∗
输入 v v v,将其平移到旋转变换中心 p ∗ p_* p∗,利用矩阵 M M M做旋转和拉伸变换,如何将变换后的坐标平移到变换后目标的中心 q ∗ q_* q∗。
一般的坐标变换只要一个方程,进行线性变换就可以了。
很显然,之前的公式并不适用于多个控制点,所以我们要利用最小二乘法了。其中 p p p为变换前的控制点, q q q为变换后的控制点。
输入一个 v v v,他到各个控制点 p i p_i pi的距离不同,我们假设距离越近的控制点对他影响就越大
每个控制点对输入的影响权重如下,其中 α \alpha α一般取1:
w i = 1 ∣ p i − v ∣ 2 α w_i = \frac{1}{|p_i -v|^{2\alpha}} wi=∣pi−v∣2α1
变换中心 p ∗ , q ∗ p_*,q_* p∗,q∗计算如下:
p ∗ = ∑ ( w i p i ) ∑ w i p_* = \frac{\sum (w_ip_i)}{\sum w_i} p∗=∑wi∑(wipi) , q ∗ = ∑ ( w i q i ) ∑ w i q_* = \frac{\sum (w_iq_i)}{\sum w_i} q∗=∑wi∑(wiqi)
式中分母 ∑ w i {\sum w_i} ∑wi是用来归一化权重因子的,以计算最佳形变中心,对于每个点,都有一个新的变换中心,这是由距离不同导致的。
我们要求的是,在该权重分配下,变换矩阵M是什么。
我们假设在M的作用下,对控制点 p i p_i pi进行变换,结果需要为 q i q_i qi,则最小二乘可以写为 ∑ ∣ p ˉ i M − q ˉ i ∣ 2 \sum |\bar p_i M - \bar q_i|^2 ∑∣pˉiM−qˉi∣2。其中 p ˉ i = p i − p ∗ \bar p_i =p_i - p_* pˉi=pi−p∗, q ˉ i = q i − q ∗ \bar q_i =q_i - q_* qˉi=qi−q∗
由于根据影响权重的不同,我们要求距离近的控制点影响要大一些,故最终的加权最小二乘表达式如下:
∑ w i ∣ p ˉ i M − q ˉ i ∣ 2 \sum w_i|\bar p_i M - \bar q_i|^2 ∑wi∣pˉiM−qˉi∣2
在线性代数中,我们求解形如 A x = b Ax=b Ax=b的正规方程最小二乘解,可得:
x = ( A T A ) − 1 A T b x = (A^TA)^{-1}A^Tb x=(ATA)−1ATb
故有 M = ( ∑ p i T w i p i ) − 1 ∑ w i p i T q i M = (\sum p_i^T w_i p_i)^{-1} \sum w_i p_i^T q_i M=(∑piTwipi)−1∑wipiTqi
对于加权最小二乘,假设 A x = b Ax=b Ax=b,两边添加权重矩阵则有 W A x = W b WAx=Wb WAx=Wb,同乘 A T A^T AT,则有 A T W A x = A T W b A^TWAx=A^TWb ATWAx=ATWb,两边再同乘 ( A T W A ) − 1 (A^TWA)^{-1} (ATWA)−1可得解
则解为 x = ( A T W A ) − 1 A T W b x = (A^TWA)^{-1}A^TWb x=(ATWA)−1ATWb,其中 w w w是权重矩阵。
有了旋转矩阵M的表达式后,我们得到变形的表达式:
l v ( v ) = ( v − p ∗ ) M + q ∗ = ( v − p ∗ ) ( ∑ p i T w i p i ) − 1 ∑ w i p i T q i + q ∗ l_v(v) = (v - p_*)M + q_* = (v - p_*)(\sum p_i^T w_i p_i)^{-1} \sum w_i p_i^T q_i + q_* lv(v)=(v−p∗)M+q∗=(v−p∗)(∑piTwipi)−1∑wipiTqi+q∗
CVfpoint MLS(CVfpoint t , CVVECTORS_F32 pList, CVVECTORS_F32 qList)
{
CVfpoint fv;
double A[2][2], B[2][2], M[2][2];
int num = pList->dataNum;
float *w = CV_malloc0(num * sizeof(float));
CVfpoint* p = pList->datap;
CVfpoint* q = qList->datap;
//计算各个控制顶点的权重,也就是计算点t到各个顶点的距离1/sqr(d)
for (int i = 0; i < num; i++)
{
float temp;
if (p[i].x != t.x || p[i].y != t.y)
temp = 1 / ((p[i].x - t.x) * (p[i].x - t.x) + (p[i].y - t.y) * (p[i].y - t.y));
else//如果t为控制顶点,那么需要把该控制顶点的权重设置为无穷大
temp = 100000;
w[i] = temp;
}
CVfpoint pc, qc;
//q为目标图像的控制点的位置,我们的目标是找到t在q中的对应位置
double px = 0, py = 0, qx = 0, qy = 0, tw = 0;
for (int i = 0; i < num; i++)
{
px += w[i] * p[i].x;//所有控制顶点p的加权位置
py += w[i] * p[i].y;
qx += w[i] * q[i].x;//所有控制顶点q的加权位置
qy += w[i] * q[i].y;
tw += w[i];//总权重
}
pc.x = px / tw;
pc.y = py / tw;
qc.x = qx / tw;
qc.y = qy / tw;
//初始化
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
{
A[i][j] = 0;
B[i][j] = 0;
M[i][j] = 0;
}
for (int i = 0; i < num; i++)
{
double P[2] = { p[i].x - pc.x,p[i].y - pc.y };//P
double PT[2][1];//P^T
PT[0][0] = p[i].x - pc.x;
PT[1][0] = p[i].y - pc.y;
double Q[2] = { q[i].x - qc.x,q[i].y - qc.y };//Q
double T[2][2];
//T = P^T * P : 列乘行=矩阵
T[0][0] = PT[0][0] * P[0];
T[0][1] = PT[0][0] * P[1];
T[1][0] = PT[1][0] * P[0];
T[1][1] = PT[1][0] * P[1];
//A = wi * (P^T * P)
for (int k = 0; k < 2; k++)
for (int j = 0; j < 2; j++)
{
A[k][j] += w[i] * T[k][j];
}
// T = P^T * Q
T[0][0] = PT[0][0] * Q[0];
T[0][1] = PT[0][0] * Q[1];
T[1][0] = PT[1][0] * Q[0];
T[1][1] = PT[1][0] * Q[1];
//B = wi * (P^T * Q)
for (int k = 0; k < 2; k++)
for (int j = 0; j < 2; j++)
{
B[k][j] += w[i] * T[k][j];
}
}
CV_free0(w);
// 求 A^-1
double det = A[0][0] * A[1][1] - A[0][1] * A[1][0];
if (det < 0.0000001)
{
fv.x = t.x + qc.x - pc.x;
fv.y = t.y + qc.y - pc.y;
return fv;
}
double temp1, temp2, temp3, temp4;
temp1 = A[1][1] / det;
temp2 = -A[0][1] / det;
temp3 = -A[1][0] / det;
temp4 = A[0][0] / det;
A[0][0] = temp1;
A[0][1] = temp2;
A[1][0] = temp3;
A[1][1] = temp4;
// M = A^-1 * B
M[0][0] = A[0][0] * B[0][0] + A[0][1] * B[1][0];
M[0][1] = A[0][0] * B[0][1] + A[0][1] * B[1][1];
M[1][0] = A[1][0] * B[0][0] + A[1][1] * B[1][0];
M[1][1] = A[1][0] * B[0][1] + A[1][1] * B[1][1];
// V = t - p*
double V[2] = { t.x - pc.x,t.y - pc.y };
double R[2][1];
// R = M * V
R[0][0] = V[0] * M[0][0] + V[1] * M[1][0];//lv(x)总计算公式
R[1][0] = V[0] * M[0][1] + V[1] * M[1][1];
// R + q*
fv.x = R[0][0] + qc.x;
fv.y = R[1][0] + qc.y;
// Ax = b ==> x = (A^T*A)^-1 * A^T b
return fv;
}
注意:是相似变形,和矩阵相似变换 P − 1 A P = B P^{-1}AP=B P−1AP=B不是一个概念。
仿射变形包含了非均匀缩放,因此其变形效果不是很好。相似变形是仿射变形的一个特殊子集,它的变形效果只包含平移、旋转和均匀缩放。对于均匀缩放,即有相同的特征值,即可分解为 M = λ R M = λ R M=λR形式,其中λ为放缩系数,R为旋转矩阵。所以只要限制转换矩阵 M M M,使其满足 M T M = λ 2 R T R = λ 2 I M^TM =λ^2 R^TR=λ^2I MTM=λ2RTR=λ2I即可。旋转矩阵 R R R的形式必然如下:
R = ( c − s s c ) R = \left(\begin{matrix} c & -s \\ s & c \end{matrix} \right) R=(cs−sc)
要使矩阵 M M M满足上述条件,可令 M = ( M 1 , M 2 ) M=(M_1 , M_2) M=(M1,M2),其中 M 2 = M 1 ⊥ M_2 = M_1^⊥ M2=M1⊥
符号⊥表示垂直的意思,如对于向量 ( x , y ) (x,y) (x,y),其垂直向量 ( x , y ) ⊥ = ( − y , x ) (x,y)^⊥=(−y,x) (x,y)⊥=(−y,x),有向量 x ( − y ) + y x = 0 x(-y)+yx=0 x(−y)+yx=0。上述 M 2 = M 1 ⊥ M_2 = M_1^⊥ M2=M1⊥表示矩阵 M M M两列是正交的,了解矩阵施密特正交化的应该很容易理解。
加权最小二乘形式如下:
∑ w i ∣ ( p ˉ i − p ˉ i ⊥ ) M − ( q ˉ i − q ˉ i ⊥ ) ∣ 2 \sum w_i| \left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) M - \left(\begin{matrix} \bar q_i \\ -\bar q_i^⊥ \end{matrix} \right) |^2 ∑wi∣(pˉi−pˉi⊥)M−(qˉi−qˉi⊥)∣2
令 P = ( p ˉ i − p ˉ i ⊥ ) P =\left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) P=(pˉi−pˉi⊥),它实际上是一个矩阵,其中若令 p ˉ i = ( x i , y i ) \bar p_i=(x_i,y_i) pˉi=(xi,yi)。则令 p ˉ i ⊥ = ( − y i , x i ) \bar p_i^⊥=(-y_i,x_i) pˉi⊥=(−yi,xi),
即,有 ( p ˉ i − p ˉ i ⊥ ) = ( x i y i y i − x i ) \left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) = \left(\begin{matrix} x_i & y_i \\ y_i & -x_i \end{matrix} \right) (pˉi−pˉi⊥)=(xiyiyi−xi),他用来表示 p ˉ i \bar p_i pˉi及其法向向量,在原式中,经过 M M M矩阵的变换,形如下
P M = λ P R = λ ( x i y i y i − x i ) ( c − s s c ) = ( x i c + y i s − x i s + y i c y i c − x i s − y i c − x i c ) PM=λPR =λ\left(\begin{matrix} x_i & y_i \\ y_i & -x_i \end{matrix} \right) \left(\begin{matrix} c & -s \\ s & c \end{matrix} \right) = \left(\begin{matrix} x_ic+y_is & -x_is+y_ic \\ y_ic-x_is & -y_ic-x_ic \end{matrix} \right) PM=λPR=λ(xiyiyi−xi)(cs−sc)=(xic+yisyic−xis−xis+yic−yic−xic)
我们可以令 P M = Q = ( q ˉ i − q ˉ i ⊥ ) PM=Q=\left(\begin{matrix} \bar q_i \\ -\bar q_i^⊥ \end{matrix} \right) PM=Q=(qˉi−qˉi⊥),这样就表示了两个垂直方向都被放缩了相同的倍数,至于为什么垂直要取负号,大概是因为图像坐标和我们习惯的数学坐标(视觉坐标)是相反的。
即为了求解方程组 P M = Q PM=Q PM=Q,类似的有 M = ( P T W P ) − 1 P T W Q M=(P^TWP)^{-1}P^TWQ M=(PTWP)−1PTWQ
P T W P = ∑ w i ( p ˉ i T ( − p ˉ i ⊥ ) T ) ( p ˉ i − p ˉ i ⊥ ) = ∑ w i ( p ˉ i T p ˉ i + p i ⊥ ( p ˉ i ⊥ ) T ) P^TWP =\sum w_i \left(\begin{matrix} \bar p_i^T & (-\bar p_i^⊥)^T \end{matrix} \right) \left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) =\sum w_i ( \bar p_i^T \bar p_i+p_i^⊥ (\bar p_i^⊥)^T) PTWP=∑wi(pˉiT(−pˉi⊥)T)(pˉi−pˉi⊥)=∑wi(pˉiTpˉi+pi⊥(pˉi⊥)T)
p i T p ˉ i = ( x i 2 x i y i y i x i y i 2 ) p_i^T \bar p_i=\left(\begin{matrix} x_i^2 & x_iy_i \\ y_ix_i & y_i^2 \end{matrix} \right) piTpˉi=(xi2yixixiyiyi2) , p i ⊥ ( p ˉ i ⊥ ) T = ( y i 2 − y i x i − x i y i x i 2 ) p_i^⊥ (\bar p_i^⊥)^T=\left(\begin{matrix} y_i^2 & -y_ix_i \\ -x_iy_i & x_i^2 \end{matrix} \right) pi⊥(pˉi⊥)T=(yi2−xiyi−yixixi2)
则有 p ˉ i T p ˉ i + p i ⊥ ( p ˉ i ⊥ ) T = ( y i 2 + x i 2 0 0 x i 2 + y i 2 ) = ( x i 2 + y i 2 ) ( 1 0 0 1 ) \bar p_i^T \bar p_i+p_i^⊥ (\bar p_i^⊥)^T=\left(\begin{matrix} y_i^2+x_i^2 & 0 \\ 0 & x_i^2+y_i^2 \end{matrix} \right)=(x_i^2+y_i^2)\left(\begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix} \right) pˉiTpˉi+pi⊥(pˉi⊥)T=(yi2+xi200xi2+yi2)=(xi2+yi2)(1001)故 ( P T W P ) − 1 = 1 ∑ w i p ˉ i p ˉ i T ( 1 0 0 1 ) (P^TWP)^{-1}=\frac{1}{\sum w_i \bar p_i \bar p_i^T}\left(\begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix} \right) (PTWP)−1=∑wipˉipˉiT1(1001)
根据该条件得到相似变形的转换矩阵 M M M如下:
M = 1 μ s ∑ w i ( p ˉ i − p ˉ i ⊥ ) ( q ˉ i − q ˉ i ⊥ ) T M = \frac{1}{\mu_s}\sum w_i \left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) \left(\begin{matrix} \bar q_i & -\bar q_i^⊥ \end{matrix} \right)^T M=μs1∑wi(pˉi−pˉi⊥)(qˉi−qˉi⊥)T
其中 μ s = ∑ w i p ˉ i p ˉ i T \mu_s = \sum w_i \bar p_i \bar p_i^T μs=∑wipˉipˉiT,左边 1 μ s \frac{1}{\mu_s} μs1乘单位矩阵即 ( P T W P ) − 1 (P^TWP)^{-1} (PTWP)−1,右边由于 P = ( x i y i y i − x i ) P= \left(\begin{matrix} x_i & y_i \\ y_i & -x_i \end{matrix} \right) P=(xiyiyi−xi)是一个对称矩阵,故有 P T = P P^T=P PT=P,而 Q Q Q则写成行向量转置的形式
刚性变形,也就是说变形不含任何缩放效果,我们进一步限制转换矩阵 M M M使其满足 M T M = I M^TM = I MTM=I,这样可以得到刚性变形。
在相似变形中,我们求得 M = 1 μ s ∑ w i ( p ˉ i − p ˉ i ⊥ ) ( q ˉ i − q ˉ i ⊥ ) T M = \frac{1}{\mu_s}\sum w_i \left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) \left(\begin{matrix} \bar q_i & -\bar q_i^⊥ \end{matrix} \right)^T M=μs1∑wi(pˉi−pˉi⊥)(qˉi−qˉi⊥)T,我们只要能求出其放缩系数 λ λ λ,将其除以该系数即可得到刚性变形的矩阵了
P T Q = ( p ˉ i − p ˉ i ⊥ ) ( q ˉ i T ( − q ˉ i ⊥ ) T ) = ( p ˉ i q ˉ i T p ˉ i ( − q ˉ i ⊥ ) T − p ˉ i ( q ˉ i ⊥ ) T p ˉ i ( q ˉ i ⊥ ) T ) P^TQ=\left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) \left(\begin{matrix} \bar q_i^T & (-\bar q_i^⊥)^T \end{matrix} \right)= \left(\begin{matrix} \bar p_i\bar q_i^T & \bar p_i(-\bar q_i^⊥)^T \\ -\bar p_i(\bar q_i^⊥)^T & \bar p_i(\bar q_i^⊥)^T \end{matrix} \right) PTQ=(pˉi−pˉi⊥)(qˉiT(−qˉi⊥)T)=(pˉiqˉiT−pˉi(qˉi⊥)Tpˉi(−qˉi⊥)Tpˉi(qˉi⊥)T)
我们知道,矩阵元素每一列的模长为拉伸系数 μ s λ \mu_sλ μsλ,取第一列可得:
μ s λ = ( p ˉ i q ˉ i T ) 2 + ( p ˉ i ( q ˉ i ⊥ ) T ) 2 \mu_sλ =\sqrt{(\bar p_i\bar q_i^T)^2+(\bar p_i(\bar q_i^⊥)^T)^2} μsλ=(pˉiqˉiT)2+(pˉi(qˉi⊥)T)2则 1 λ = μ s ( p ˉ i q ˉ i T ) 2 + ( p ˉ i ( q ˉ i ⊥ ) T ) 2 \frac{1}{λ }=\frac{\mu_s}{\sqrt{(\bar p_i\bar q_i^T)^2+(\bar p_i(\bar q_i^⊥)^T)^2}} λ1=(pˉiqˉiT)2+(pˉi(qˉi⊥)T)2μs
故可得,刚性变形的 M M M矩阵解如下
M = 1 λ M 相 似 变 形 = 1 ( ∑ w i p ˉ i q ˉ i T ) 2 + ( ∑ w i p ˉ i ( q ˉ i ⊥ ) T ) 2 ∑ w i ( p ˉ i − p ˉ i ⊥ ) ( q ˉ i − q ˉ i ⊥ ) T M=\frac{1}{λ } M_{相似变形} = \frac{1}{\sqrt{(\sum w_i\bar p_i\bar q_i^T)^2+(\sum w_i\bar p_i(\bar q_i^⊥)^T)^2}}\sum w_i \left(\begin{matrix} \bar p_i \\ -\bar p_i^⊥ \end{matrix} \right) \left(\begin{matrix} \bar q_i & -\bar q_i^⊥ \end{matrix} \right)^T M=λ1M相似变形=(∑wipˉiqˉiT)2+(∑wipˉi(qˉi⊥)T)21∑wi(pˉi−pˉi⊥)(qˉi−qˉi⊥)T
注:所有参考资料的公式都有误,我重新推导的才是对的。
最终项目:基于移动最小二乘的图像变形
卡通图像变形算法
图像处理(十九)基于移动最小二乘的图像变形