在圖像仿射變換中,我們可以用Matrix來進行圖像的平移介蛉、縮放萌庆、旋轉(zhuǎn)、錯切币旧,對應Android代碼中就是以下接口的復合操作:
set/pre/post Translate(...)
set/pre/post Scale(...)
set/pre/post Rotate(...)
set/pre/post Skew(...)
原理部分很多文章都有介紹践险,這里先簡要的說明下。如下是四種變換對應的控制參數(shù):
進行圖像變換的時候,可以理解為圖像中每一個二維坐標點的矩陣變換:
上圖對應二維坐標點的平移(Translate)巍虫、縮放(Scale)彭则、旋轉(zhuǎn)(Rotate)變換的矩陣運算表達式,只要左乘對應的矩陣表達式即可占遥。
重點:pre和post的理解
網(wǎng)上有很多文章講的不準確俯抖,只停留在現(xiàn)象和結(jié)果上總結(jié),很容易對讀者造成誤解瓦胎,我也深受其害芬萍。其實從本質(zhì)上理解就不難了。
變換矩陣初始為單位矩陣搔啊,每一次post/pre調(diào)用都是對前一次矩陣的左乘/右乘運算柬祠,最后生成結(jié)果的變換矩陣。
設M為原始矩陣负芋,S為變換矩陣漫蛔,M'為變換后的矩陣,
pre(S)相當于矩陣的右乘:M' = M ? S
post(S)相當于矩陣的左乘:M' = S ? M
我們舉一個復合變換的例子:圖片以中心點旋轉(zhuǎn)90度旧蛾,一般的操作步驟為:
- 坐標原點平移到中心點
- 以中心點為圓心旋轉(zhuǎn)90度
- 將坐標原點平移到原來的位置
其中每一步操作都可以對應一次矩陣的運算莽龟,即左乘對應的變換矩陣。則代碼可表示為
Matrix matrix = new Matrix();// 單位矩陣
matrix.postTranslate(-width/2, -height/2);// 左乘平移變換矩陣锨天,坐標原點平移到中心點
matrix.postRotate(90);// 左乘旋轉(zhuǎn)變換矩陣轧房,旋轉(zhuǎn)90度
matrix.postTranslate(width/2, height/2);// 左乘平移變換矩陣,將坐標原點平移到原來的位置
我們設原始矩陣為M绍绘,平移為T,旋轉(zhuǎn)為R迟赃,單位矩陣為I陪拘,最終結(jié)果為M'。
上述過程用矩陣可表達為:
Matrix matrix = new Matrix();// M' = M = I
matrix.postTranslate(-width/2, -height/2);// M' = T1*I
matrix.postRotate(90);// M' = R*(T1*I)
matrix.postTranslate(width/2, height/2);// M' = T2*(R*(T1*I))
矩陣運算滿足:
- 結(jié)合律纤壁,即(AB)C = A(BC)
- 和單位矩陣相乘結(jié)果不變左刽,即A*I = A
所以上述運算結(jié)果為M' = T2*(R*(T1*I)) = T2*R*T1。
這個M'是結(jié)果的變換矩陣酌媒,會左乘到點坐標上欠痴,來完成圖像的變換。
在Android中如Canvas
的drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
會指定一個Matrix對象參數(shù)秒咨,就是做這個左乘操作的喇辽。
我們設圖像上的點為P,變換后的點為P'雨席,則P' = M'*P = (T2*R*T1)*P菩咨。因為矩陣點乘滿足結(jié)合律,我們可以按照最接近P的操作先運算,可以寫成P' = (T2*(R*(T1*P))):
- P' = T1*P --> 坐標原點平移到中心點
- P' = R*(T1*P)*P --> 旋轉(zhuǎn)90度
- P' = T2*(R(T1*P)*P) --> 將坐標原點平移到原來的位置
我們可以知道抽米,其實post/pre就是矩陣的左乘/右乘操作特占,無論怎么組合,只要最終的M'一樣云茸,則對圖像的變換過程也是一樣的是目。
可以通過post/pre來修改變換矩陣生成的順序,而不影響最后的變換結(jié)果标捺。
上述的例子我們還可以這么寫:
Matrix matrix = new Matrix();// M' = M = I
matrix.postRotate(90);// M' = R*I
matrix.preTranslate(-width/2, -height/2);// M' = T1*(R*I)
matrix.postTranslate(width/2, height/2);// M' = T2*(T1*(R*I))
因為滿足結(jié)合律和單位矩陣相乘結(jié)果不變懊纳,M' = T2*(T1*(R*I)) = T2*T1*R,和第一種方式生成的M'一樣宜岛。
post/pre改變的只是變換矩陣生成的先后順序长踊,每一步過程都相當于表達式中的小括號,因為滿足結(jié)合律萍倡,表達式可以統(tǒng)一簡化成從右到左的變換過程身弊,這樣就能清楚最終對圖像做的具體變換操作。只要變換矩陣M'一樣列敲,變換結(jié)果就一樣阱佛。
為什么叫post/pre,如何理解戴而?
我們知道post是左乘凑术,pre是右乘,死記可以所意,理解了更好淮逊。pre字面上是previous提前的意思,因為pre操作為右乘更靠近P扶踊,我們按照接近P的操作先運算就相當于"提前"了泄鹏;而post為左乘,越靠近左邊秧耗,越“延后”運算备籽。
參考文章:http://www.gcssloop.com/customview/Matrix_Basic
不難吧,理解了就能靈活運用了分井,如果愛情有這么簡單就好了车猬。