仿射变换可以将矩阵形状转换为平行四边形。可以挤压形状,但是必须保持两边平行。常见的是旋转、缩放、平移变换。缩放和平移比较简单,本文重点推导旋转缩放变换矩阵。
任意一点 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)
可以看成 ( x 0 , 0 ) (x_0, 0) (x0,0)向量和 ( 0 , y 0 ) (0,y_0) (0,y0)向量相加,对 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)
绕原点逆时针旋转 θ \theta θ,相当于 ( x 0 , 0 ) , ( 0 , y 0 ) (x_0,0),(0,y_0) (x0,0),(0,y0)
绕原点逆时针旋转 θ \theta θ 后的向量相加。
x 轴为图片宽度方向,y轴为高度方向。
因此 ( x 0 , y 0 ) (x_0, y_0) (x0,y0) 点逆时针旋转 θ \theta θ 后的坐标为
( x 1 y 1 ) = ( x 0 cos θ + y 0 sin θ , − x 0 sin θ + y 0 cos θ ) = ( cos θ sin θ − sin θ cos θ ) ( x 0 y 0 ) \begin{aligned} \begin{pmatrix} x_1 \\ y_1\\ \end{pmatrix} = (x_0 \cos \theta + y_0 \sin \theta, -x_0\sin \theta + y_0 \cos \theta) = \begin{pmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{pmatrix} \begin{pmatrix} x_0 \\ y_0\\ \end{pmatrix} \end{aligned} (x1y1)=(x0cosθ+y0sinθ,−x0sinθ+y0cosθ)=(cosθ−sinθsinθcosθ)(x0y0)
旋转矩阵为
( cos θ sin θ − sin θ cos θ ) . \begin{aligned} \begin{pmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{pmatrix} . \end{aligned} (cosθ−sinθsinθcosθ).
上面是绕原点旋转,如果是绕任意一点旋转呢? 假设旋转中心center为
( c x , c y ) (c_x, c_y) (cx,cy)。 我们把坐标原点移动到 ( c x , c y ) (c_x, c_y) (cx,cy) , 旧坐标系任意点(x,
y)在新坐标系下则为 ( x − c x , y − c y ) (x-c_x, y-c_y) (x−cx,y−cy)。
因此在新坐标系下绕原点逆时针旋转 θ \theta θ ,即
( x ∗ y ∗ ) = ( cos θ sin θ − sin θ cos θ ) ( x − c x y − c y ) \begin{aligned} \begin{pmatrix} x^*\\ y^*\\ \end{pmatrix} = \begin{pmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{pmatrix} \begin{pmatrix} x-c_x \\ y-c_y \\ \end{pmatrix} \end{aligned} (x∗y∗)=(cosθ−sinθsinθcosθ)(x−cxy−cy)
新坐标系下旋转后的点 ( x ∗ , y ∗ ) (x^*, y^*) (x∗,y∗)在旧坐标系下则为 ( x ∗ + c x , y ∗ + c y ) (x^* + c_x, y^* + c_y) (x∗+cx,y∗+cy)
。 因此旧坐标系下绕 ( c x , c y ) (c_x, c_y) (cx,cy) 逆时针旋转 θ \theta θ 后的点为
( x ′ y ′ ) = ( cos θ sin θ − sin θ cos θ ) ( x − c x y − c y ) + ( c x c y ) = ( cos θ x + sin θ y − c x cos θ − c y sin θ + c x − sin θ x + cos θ y + c x sin θ − c y cos θ + c y ) = ( cos θ sin θ ( 1 − cos θ ) c x − c y sin θ − sin θ cos θ c x sin θ + ( 1 − cos θ ) c y ) ( x y 1 ) \begin{aligned} \begin{pmatrix} x'\\ y'\\ \end{pmatrix} =& \begin{pmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{pmatrix} \begin{pmatrix} x-c_x \\ y-c_y \\ \end{pmatrix} + \begin{pmatrix} c_x\\ c_y\\ \end{pmatrix} \\ =& \begin{pmatrix} \cos\theta x + \sin\theta y - c_x\cos\theta - c_y\sin\theta + c_x \\ -\sin\theta x + \cos\theta y + c_x\sin\theta - c_y\cos\theta + c_y \\ \end{pmatrix} \\ =& \begin{pmatrix} \cos\theta & \sin\theta & (1 - \cos\theta)c_x - c_y\sin\theta \\ -\sin\theta & \cos\theta & c_x\sin\theta + (1-\cos\theta)c_y \\ \end{pmatrix} \begin{pmatrix} x\\ y\\ 1\\ \end{pmatrix} \end{aligned} (x′y′)===(cosθ−sinθsinθcosθ)(x−cxy−cy)+(cxcy)(cosθx+sinθy−cxcosθ−cysinθ+cx−sinθx+cosθy+cxsinθ−cycosθ+cy)(cosθ−sinθsinθcosθ(1−cosθ)cx−cysinθcxsinθ+(1−cosθ)cy) xy1
现在再考虑缩放,分2种情况:
(1) 旋转后以原点为中心缩放 scale, 记 s c a l e ∗ cos θ = α scale * \cos \theta = \alpha scale∗cosθ=α ,
s c a l e ∗ sin θ = β scale * \sin \theta = \beta scale∗sinθ=β ,则
( x ′ y ′ ) = ( s c a l e 0 0 s c a l e ) ( cos θ sin θ ( 1 − cos θ ) c x − c y sin θ − sin θ cos θ c x sin θ + ( 1 − cos θ ) c y ) ( x y 1 ) = ( α β ( s c a l e − α ) c x − β c y − β α β c x + ( s c a l e − α ) c y ) ( x y 1 ) \begin{aligned} \begin{pmatrix} x'\\ y'\\ \end{pmatrix} =& \begin{pmatrix} scale & 0\\ 0 & scale \end{pmatrix} \begin{pmatrix} \cos\theta & \sin\theta & (1 - \cos\theta)c_x - c_y\sin\theta \\ -\sin\theta & \cos\theta & c_x\sin\theta + (1-\cos\theta)c_y \\ \end{pmatrix} \begin{pmatrix} x\\ y\\ 1\\ \end{pmatrix} \\ =& \begin{pmatrix} \alpha & \beta & (scale - \alpha)c_x - \beta c_y \\ -\beta & \alpha & \beta c_x + (scale-\alpha)c_y \\ \end{pmatrix} \begin{pmatrix} x\\ y\\ 1\\ \end{pmatrix} \end{aligned} (x′y′)==(scale00scale)(cosθ−sinθsinθcosθ(1−cosθ)cx−cysinθcxsinθ+(1−cosθ)cy) xy1 (α−ββα(scale−α)cx−βcyβcx+(scale−α)cy) xy1
(2) 旋转后以 ( c x , c y ) (c_x, c_y) (cx,cy) 为中心点缩放,分2步:
第1步,先按上面(1)变换,此时 ( c x , c y ) (c_x, c_y) (cx,cy)点变为了 ( s c a l e ∗ c x , s c a l e ∗ c y ) (scale * c_x, scale * c_y) (scale∗cx,scale∗cy)
;第2步 x分量平移 c x − s c a l e ∗ c x c_x - scale * c_x cx−scale∗cx ,y
分量平移 c y − s c a l e ∗ c y c_y - scale * c_y cy−scale∗cy。因此
( x ′ y ′ ) = ( α β ( s c a l e − α ) c x − β c y − β α β c x + ( s c a l e − α ) c y ) ( x y 1 ) + ( 0 0 c x − s c a l e ∗ c x 0 0 c y − s c a l e ∗ c y ) ( x y 1 ) = ( α β ( 1 − α ) c x − β c y − β α β c x + ( 1 − α ) c y ) ( x y 1 ) \begin{aligned} \begin{pmatrix} x'\\ y'\\ \end{pmatrix} =& \begin{pmatrix} \alpha & \beta & (scale - \alpha)c_x - \beta c_y \\ -\beta & \alpha & \beta c_x + (scale-\alpha)c_y \\ \end{pmatrix} \begin{pmatrix} x\\ y\\ 1\\ \end{pmatrix} + \begin{pmatrix} 0 & 0 & c_x - scale * c_x \\ 0 & 0 & c_y - scale * c_y \\ \end{pmatrix} \begin{pmatrix} x\\ y\\ 1\\ \end{pmatrix} \\ =& \begin{pmatrix} \alpha & \beta & (1 - \alpha)c_x - \beta c_y \\ -\beta & \alpha & \beta c_x + (1-\alpha)c_y \\ \end{pmatrix} \begin{pmatrix} x\\ y\\ 1\\ \end{pmatrix} \end{aligned} (x′y′)==(α−ββα(scale−α)cx−βcyβcx+(scale−α)cy) xy1 +(0000cx−scale∗cxcy−scale∗cy) xy1 (α−ββα(1−α)cx−βcyβcx+(1−α)cy) xy1
顺便提下,毛星云写的《OpenCV3 编程入门》旋转缩放矩阵是错的,写成了2*1矩阵;《学习OpenCV 3》中文版则有一个符号错误,把加号写成了减号。这2本书都没有推导过程,这也是我写这篇文章的原因。
原文链接
仿射变换中的旋转缩放变换矩阵推导