Android笔记——Matrix
轉自:http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#translate
Matrix的數學原理
在Android中,如果你用Matrix進行過圖像處理,那么一定知道Matrix這個類。Android中的Matrix是一個3 x 3的矩陣,其內容如下:
?
Matrix的對圖像的處理可分為四類基本變換:
Translate?????????? 平移變換
Rotate??????????????? 旋轉變換
Scale????????????????? 縮放變換
Skew????????????????? 錯切變換
?
從字面上理解,矩陣中的MSCALE用于處理縮放變換,MSKEW用于處理錯切變換,MTRANS用于處理平移變換,MPERSP用于處理透視變換。實際中當然不能完全按照字面上的說法去理解Matrix。同時,在Android的文檔中,未見到用Matrix進行透視變換的相關說明,所以本文也不討論這方面的問題。
?
針對每種變換,Android提供了pre、set和post三種操作方式。其中
set用于設置Matrix中的值。
pre是先乘,因為矩陣的乘法不滿足交換律,因此先乘、后乘必須要嚴格區分。先乘相當于矩陣運算中的右乘。
post是后乘,因為矩陣的乘法不滿足交換律,因此先乘、后乘必須要嚴格區分。后乘相當于矩陣運算中的左乘。
?
除平移變換(Translate)外,旋轉變換(Rotate)、縮放變換(Scale)和錯切變換(Skew)都可以圍繞一個中心點來進行,如果不指定,在默認情況下是圍繞(0, 0)來進行相應的變換的。
?
下面我們來看看四種變換的具體情形。由于所有的圖形都是有點組成,因此我們只需要考察一個點相關變換即可。
?
一、?平移變換
假定有一個點的坐標是?,將其移動到?,再假定在x軸和y軸方向移動的大小分別為:
如下圖所示:
不難知道:
如果用矩陣來表示的話,就可以寫成:
?
?
二、?旋轉變換
?
2.1??? 圍繞坐標原點旋轉:
假定有一個點?,相對坐標原點順時針旋轉后的情形,同時假定P點離坐標原點的距離為r,如下圖:
那么,
如果用矩陣,就可以表示為:
?
2.2??? 圍繞某個點旋轉
如果是圍繞某個點順時針旋轉,那么可以用矩陣表示為:
可以化為:
很顯然,
1.???
??是將坐標原點移動到點后,?的新坐標。
2.?????
是將上一步變換后的,圍繞新的坐標原點順時針旋轉?。
3.?????
經過上一步旋轉變換后,再將坐標原點移回到原來的坐標原點。
?
所以,圍繞某一點進行旋轉變換,可以分成3個步驟,即首先將坐標原點移至該點,然后圍繞新的坐標原點進行旋轉變換,再然后將坐標原點移回到原先的坐標原點。
?
三、?縮放變換
理論上而言,一個點是不存在什么縮放變換的,但考慮到所有圖像都是由點組成,因此,如果圖像在x軸和y軸方向分別放大k1和k2倍的話,那么圖像中的所有點的x坐標和y坐標均會分別放大k1和k2倍,即
用矩陣表示就是:
縮放變換比較好理解,就不多說了。
?
四、?錯切變換
錯切變換(skew)在數學上又稱為Shear mapping(可譯為“剪切變換”)或者Transvection(縮并),它是一種比較特殊的線性變換。錯切變換的效果就是讓所有點的x坐標(或者y坐標)保持不變,而對應的y坐標(或者x坐標)則按比例發生平移,且平移的大小和該點到x軸(或y軸)的垂直距離成正比。錯切變換,屬于等面積變換,即一個形狀在錯切變換的前后,其面積是相等的。
比如下圖,各點的y坐標保持不變,但其x坐標則按比例發生了平移。這種情況將水平錯切。
下圖各點的x坐標保持不變,但其y坐標則按比例發生了平移。這種情況叫垂直錯切。
?
假定一個點經過錯切變換后得到,對于水平錯切而言,應該有如下關系:
用矩陣表示就是:
擴展到3 x 3的矩陣就是下面這樣的形式:
?
同理,對于垂直錯切,可以有:
在數學上嚴格的錯切變換就是上面這樣的。在Android中除了有上面說到的情況外,還可以同時進行水平、垂直錯切,那么形式上就是:
?
五、?對稱變換
除了上面講到的4中基本變換外,事實上,我們還可以利用Matrix,進行對稱變換。所謂對稱變換,就是經過變化后的圖像和原圖像是關于某個對稱軸是對稱的。比如,某點?經過對稱變換后得到,
如果對稱軸是x軸,難么,
用矩陣表示就是:
如果對稱軸是y軸,那么,
用矩陣表示就是:
如果對稱軸是y = x,如圖:
那么,
很容易可以解得:
用矩陣表示就是:
同樣的道理,如果對稱軸是y = -x,那么用矩陣表示就是:
?
特殊地,如果對稱軸是y = kx,如下圖:
那么,
很容易可解得:
用矩陣表示就是:
當k = 0時,即y = 0,也就是對稱軸為x軸的情況;當k趨于無窮大時,即x = 0,也就是對稱軸為y軸的情況;當k =1時,即y = x,也就是對稱軸為y = x的情況;當k = -1時,即y = -x,也就是對稱軸為y = -x的情況。不難驗證,這和我們前面說到的4中具體情況是相吻合的。
?
如果對稱軸是y = kx + b這樣的情況,只需要在上面的基礎上增加兩次平移變換即可,即先將坐標原點移動到(0, b),然后做上面的關于y = kx的對稱變換,再然后將坐標原點移回到原來的坐標原點即可。用矩陣表示大致是這樣的:
需要特別注意:在實際編程中,我們知道屏幕的y坐標的正向和數學中y坐標的正向剛好是相反的,所以在數學上y = x和屏幕上的y = -x才是真正的同一個東西,反之亦然。也就是說,如果要使圖片在屏幕上看起來像按照數學意義上y = x對稱,那么需使用這種轉換:
要使圖片在屏幕上看起來像按照數學意義上y = -x對稱,那么需使用這種轉換:
?
關于對稱軸為y = kx?或y = kx + b的情況,同樣需要考慮這方面的問題。
第二部分?代碼驗證
在第一部分中講到的各種圖像變換的驗證代碼如下,一共列出了10種情況。如果要驗證其中的某一種情況,只需將相應的代碼反注釋即可。試驗中用到的圖片:
其尺寸為162 x 251。
其尺寸為162 x 251。
1 <span style="font-size:13px;"></span><pre name="code" class="java">package com.pat.testtransformmatrix; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.graphics.Canvas; 8 import android.graphics.Matrix; 9 import android.os.Bundle; 10 import android.util.Log; 11 import android.view.MotionEvent; 12 import android.view.View; 13 import android.view.Window; 14 import android.view.WindowManager; 15 import android.view.View.OnTouchListener; 16 import android.widget.ImageView; 17 18 public class TestTransformMatrixActivity extends Activity 19 implements 20 OnTouchListener 21 { 22 private TransformMatrixView view; 23 @Override 24 public void onCreate(Bundle savedInstanceState) 25 { 26 super.onCreate(savedInstanceState); 27 requestWindowFeature(Window.FEATURE_NO_TITLE); 28 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 29 30 view = new TransformMatrixView(this); 31 view.setScaleType(ImageView.ScaleType.MATRIX); 32 view.setOnTouchListener(this); 33 34 setContentView(view); 35 } 36 37 class TransformMatrixView extends ImageView 38 { 39 private Bitmap bitmap; 40 private Matrix matrix; 41 public TransformMatrixView(Context context) 42 { 43 super(context); 44 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sophie); 45 matrix = new Matrix(); 46 } 47 48 @Override 49 protected void onDraw(Canvas canvas) 50 { 51 // 畫出原圖像 52 canvas.drawBitmap(bitmap, 0, 0, null); 53 // 畫出變換后的圖像 54 canvas.drawBitmap(bitmap, matrix, null); 55 super.onDraw(canvas); 56 } 57 58 @Override 59 public void setImageMatrix(Matrix matrix) 60 { 61 this.matrix.set(matrix); 62 super.setImageMatrix(matrix); 63 } 64 65 public Bitmap getImageBitmap() 66 { 67 return bitmap; 68 } 69 } 70 71 public boolean onTouch(View v, MotionEvent e) 72 { 73 if(e.getAction() == MotionEvent.ACTION_UP) 74 { 75 Matrix matrix = new Matrix(); 76 // 輸出圖像的寬度和高度(162 x 251) 77 Log.e("TestTransformMatrixActivity", "image size: width x height = " + view.getImageBitmap().getWidth() + " x " + view.getImageBitmap().getHeight()); 78 // 1. 平移 79 matrix.postTranslate(view.getImageBitmap().getWidth(), view.getImageBitmap().getHeight()); 80 // 在x方向平移view.getImageBitmap().getWidth(),在y軸方向view.getImageBitmap().getHeight() 81 view.setImageMatrix(matrix); 82 83 // 下面的代碼是為了查看matrix中的元素 84 float[] matrixValues = new float[9]; 85 matrix.getValues(matrixValues); 86 for(int i = 0; i < 3; ++i) 87 { 88 String temp = new String(); 89 for(int j = 0; j < 3; ++j) 90 { 91 temp += matrixValues[3 * i + j ] + "\t"; 92 } 93 Log.e("TestTransformMatrixActivity", temp); 94 } 95 96 97 // // 2. 旋轉(圍繞圖像的中心點) 98 // matrix.setRotate(45f, view.getImageBitmap().getWidth() / 2f, view.getImageBitmap().getHeight() / 2f); 99 // 100 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 101 // matrix.postTranslate(view.getImageBitmap().getWidth() * 1.5f, 0f); 102 // view.setImageMatrix(matrix); 103 // 104 // // 下面的代碼是為了查看matrix中的元素 105 // float[] matrixValues = new float[9]; 106 // matrix.getValues(matrixValues); 107 // for(int i = 0; i < 3; ++i) 108 // { 109 // String temp = new String(); 110 // for(int j = 0; j < 3; ++j) 111 // { 112 // temp += matrixValues[3 * i + j ] + "\t"; 113 // } 114 // Log.e("TestTransformMatrixActivity", temp); 115 // } 116 117 118 // // 3. 旋轉(圍繞坐標原點) + 平移(效果同2) 119 // matrix.setRotate(45f); 120 // matrix.preTranslate(-1f * view.getImageBitmap().getWidth() / 2f, -1f * view.getImageBitmap().getHeight() / 2f); 121 // matrix.postTranslate((float)view.getImageBitmap().getWidth() / 2f, (float)view.getImageBitmap().getHeight() / 2f); 122 // 123 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 124 // matrix.postTranslate((float)view.getImageBitmap().getWidth() * 1.5f, 0f); 125 // view.setImageMatrix(matrix); 126 // 127 // // 下面的代碼是為了查看matrix中的元素 128 // float[] matrixValues = new float[9]; 129 // matrix.getValues(matrixValues); 130 // for(int i = 0; i < 3; ++i) 131 // { 132 // String temp = new String(); 133 // for(int j = 0; j < 3; ++j) 134 // { 135 // temp += matrixValues[3 * i + j ] + "\t"; 136 // } 137 // Log.e("TestTransformMatrixActivity", temp); 138 // } 139 140 // // 4. 縮放 141 // matrix.setScale(2f, 2f); 142 // // 下面的代碼是為了查看matrix中的元素 143 // float[] matrixValues = new float[9]; 144 // matrix.getValues(matrixValues); 145 // for(int i = 0; i < 3; ++i) 146 // { 147 // String temp = new String(); 148 // for(int j = 0; j < 3; ++j) 149 // { 150 // temp += matrixValues[3 * i + j ] + "\t"; 151 // } 152 // Log.e("TestTransformMatrixActivity", temp); 153 // } 154 // 155 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 156 // matrix.postTranslate(view.getImageBitmap().getWidth(), view.getImageBitmap().getHeight()); 157 // view.setImageMatrix(matrix); 158 // 159 // // 下面的代碼是為了查看matrix中的元素 160 // matrixValues = new float[9]; 161 // matrix.getValues(matrixValues); 162 // for(int i = 0; i < 3; ++i) 163 // { 164 // String temp = new String(); 165 // for(int j = 0; j < 3; ++j) 166 // { 167 // temp += matrixValues[3 * i + j ] + "\t"; 168 // } 169 // Log.e("TestTransformMatrixActivity", temp); 170 // } 171 172 173 // // 5. 錯切 - 水平 174 // matrix.setSkew(0.5f, 0f); 175 // // 下面的代碼是為了查看matrix中的元素 176 // float[] matrixValues = new float[9]; 177 // matrix.getValues(matrixValues); 178 // for(int i = 0; i < 3; ++i) 179 // { 180 // String temp = new String(); 181 // for(int j = 0; j < 3; ++j) 182 // { 183 // temp += matrixValues[3 * i + j ] + "\t"; 184 // } 185 // Log.e("TestTransformMatrixActivity", temp); 186 // } 187 // 188 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 189 // matrix.postTranslate(view.getImageBitmap().getWidth(), 0f); 190 // view.setImageMatrix(matrix); 191 // 192 // // 下面的代碼是為了查看matrix中的元素 193 // matrixValues = new float[9]; 194 // matrix.getValues(matrixValues); 195 // for(int i = 0; i < 3; ++i) 196 // { 197 // String temp = new String(); 198 // for(int j = 0; j < 3; ++j) 199 // { 200 // temp += matrixValues[3 * i + j ] + "\t"; 201 // } 202 // Log.e("TestTransformMatrixActivity", temp); 203 // } 204 205 // // 6. 錯切 - 垂直 206 // matrix.setSkew(0f, 0.5f); 207 // // 下面的代碼是為了查看matrix中的元素 208 // float[] matrixValues = new float[9]; 209 // matrix.getValues(matrixValues); 210 // for(int i = 0; i < 3; ++i) 211 // { 212 // String temp = new String(); 213 // for(int j = 0; j < 3; ++j) 214 // { 215 // temp += matrixValues[3 * i + j ] + "\t"; 216 // } 217 // Log.e("TestTransformMatrixActivity", temp); 218 // } 219 // 220 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 221 // matrix.postTranslate(0f, view.getImageBitmap().getHeight()); 222 // view.setImageMatrix(matrix); 223 // 224 // // 下面的代碼是為了查看matrix中的元素 225 // matrixValues = new float[9]; 226 // matrix.getValues(matrixValues); 227 // for(int i = 0; i < 3; ++i) 228 // { 229 // String temp = new String(); 230 // for(int j = 0; j < 3; ++j) 231 // { 232 // temp += matrixValues[3 * i + j ] + "\t"; 233 // } 234 // Log.e("TestTransformMatrixActivity", temp); 235 // } 236 237 // 7. 錯切 - 水平 + 垂直 238 // matrix.setSkew(0.5f, 0.5f); 239 // // 下面的代碼是為了查看matrix中的元素 240 // float[] matrixValues = new float[9]; 241 // matrix.getValues(matrixValues); 242 // for(int i = 0; i < 3; ++i) 243 // { 244 // String temp = new String(); 245 // for(int j = 0; j < 3; ++j) 246 // { 247 // temp += matrixValues[3 * i + j ] + "\t"; 248 // } 249 // Log.e("TestTransformMatrixActivity", temp); 250 // } 251 // 252 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 253 // matrix.postTranslate(0f, view.getImageBitmap().getHeight()); 254 // view.setImageMatrix(matrix); 255 // 256 // // 下面的代碼是為了查看matrix中的元素 257 // matrixValues = new float[9]; 258 // matrix.getValues(matrixValues); 259 // for(int i = 0; i < 3; ++i) 260 // { 261 // String temp = new String(); 262 // for(int j = 0; j < 3; ++j) 263 // { 264 // temp += matrixValues[3 * i + j ] + "\t"; 265 // } 266 // Log.e("TestTransformMatrixActivity", temp); 267 // } 268 269 // // 8. 對稱 (水平對稱) 270 // float matrix_values[] = {1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f}; 271 // matrix.setValues(matrix_values); 272 // // 下面的代碼是為了查看matrix中的元素 273 // float[] matrixValues = new float[9]; 274 // matrix.getValues(matrixValues); 275 // for(int i = 0; i < 3; ++i) 276 // { 277 // String temp = new String(); 278 // for(int j = 0; j < 3; ++j) 279 // { 280 // temp += matrixValues[3 * i + j ] + "\t"; 281 // } 282 // Log.e("TestTransformMatrixActivity", temp); 283 // } 284 // 285 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 286 // matrix.postTranslate(0f, view.getImageBitmap().getHeight() * 2f); 287 // view.setImageMatrix(matrix); 288 // 289 // // 下面的代碼是為了查看matrix中的元素 290 // matrixValues = new float[9]; 291 // matrix.getValues(matrixValues); 292 // for(int i = 0; i < 3; ++i) 293 // { 294 // String temp = new String(); 295 // for(int j = 0; j < 3; ++j) 296 // { 297 // temp += matrixValues[3 * i + j ] + "\t"; 298 // } 299 // Log.e("TestTransformMatrixActivity", temp); 300 // } 301 302 // // 9. 對稱 - 垂直 303 // float matrix_values[] = {-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f}; 304 // matrix.setValues(matrix_values); 305 // // 下面的代碼是為了查看matrix中的元素 306 // float[] matrixValues = new float[9]; 307 // matrix.getValues(matrixValues); 308 // for(int i = 0; i < 3; ++i) 309 // { 310 // String temp = new String(); 311 // for(int j = 0; j < 3; ++j) 312 // { 313 // temp += matrixValues[3 * i + j ] + "\t"; 314 // } 315 // Log.e("TestTransformMatrixActivity", temp); 316 // } 317 // 318 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 319 // matrix.postTranslate(view.getImageBitmap().getWidth() * 2f, 0f); 320 // view.setImageMatrix(matrix); 321 // 322 // // 下面的代碼是為了查看matrix中的元素 323 // matrixValues = new float[9]; 324 // matrix.getValues(matrixValues); 325 // for(int i = 0; i < 3; ++i) 326 // { 327 // String temp = new String(); 328 // for(int j = 0; j < 3; ++j) 329 // { 330 // temp += matrixValues[3 * i + j ] + "\t"; 331 // } 332 // Log.e("TestTransformMatrixActivity", temp); 333 // } 334 335 336 // // 10. 對稱(對稱軸為直線y = x) 337 // float matrix_values[] = {0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f}; 338 // matrix.setValues(matrix_values); 339 // // 下面的代碼是為了查看matrix中的元素 340 // float[] matrixValues = new float[9]; 341 // matrix.getValues(matrixValues); 342 // for(int i = 0; i < 3; ++i) 343 // { 344 // String temp = new String(); 345 // for(int j = 0; j < 3; ++j) 346 // { 347 // temp += matrixValues[3 * i + j ] + "\t"; 348 // } 349 // Log.e("TestTransformMatrixActivity", temp); 350 // } 351 // 352 // // 做下面的平移變換,純粹是為了讓變換后的圖像和原圖像不重疊 353 // matrix.postTranslate(view.getImageBitmap().getHeight() + view.getImageBitmap().getWidth(), 354 // view.getImageBitmap().getHeight() + view.getImageBitmap().getWidth()); 355 // view.setImageMatrix(matrix); 356 // 357 // // 下面的代碼是為了查看matrix中的元素 358 // matrixValues = new float[9]; 359 // matrix.getValues(matrixValues); 360 // for(int i = 0; i < 3; ++i) 361 // { 362 // String temp = new String(); 363 // for(int j = 0; j < 3; ++j) 364 // { 365 // temp += matrixValues[3 * i + j ] + "\t"; 366 // } 367 // Log.e("TestTransformMatrixActivity", temp); 368 // } 369 370 view.invalidate(); 371 } 372 return true; 373 } 374 }下面給出上述代碼中,各種變換的具體結果及其對應的相關變換矩陣
1.???? 平移
輸出的結果:
請對照第一部分中的“一、平移變換”所講的情形,考察上述矩陣的正確性。
?
2.???? 旋轉(圍繞圖像的中心點)
輸出的結果:
它實際上是
matrix.setRotate(45f,view.getImageBitmap().getWidth() / 2f, view.getImageBitmap().getHeight() / 2f);
matrix.postTranslate(view.getImageBitmap().getWidth()* 1.5f, 0f);
這兩條語句綜合作用的結果。根據第一部分中“二、旋轉變換”里面關于圍繞某點旋轉的公式,
matrix.setRotate(45f,view.getImageBitmap().getWidth() / 2f, view.getImageBitmap().getHeight() / 2f);
所產生的轉換矩陣就是:
而matrix.postTranslate(view.getImageBitmap().getWidth()* 1.5f, 0f);的意思就是在上述矩陣的左邊再乘以下面的矩陣:
關于post是左乘這一點,我們在前面的理論部分曾經提及過,后面我們還會專門討論這個問題。
?
所以它實際上就是:
出去計算上的精度誤差,我們可以看到我們計算出來的結果,和程序直接輸出的結果是一致的。
?
3.???? 旋轉(圍繞坐標原點旋轉,在加上兩次平移,效果同2)
根據第一部分中“二、旋轉變換”里面關于圍繞某點旋轉的解釋,不難知道:
matrix.setRotate(45f,view.getImageBitmap().getWidth() / 2f, view.getImageBitmap().getHeight() / 2f);
等價于
matrix.setRotate(45f);
matrix.preTranslate(-1f* view.getImageBitmap().getWidth() / 2f, -1f *view.getImageBitmap().getHeight() / 2f);
matrix.postTranslate((float)view.getImageBitmap().getWidth()/ 2f, (float)view.getImageBitmap().getHeight() / 2f);
?
其中matrix.setRotate(45f)對應的矩陣是:
matrix.preTranslate(-1f* view.getImageBitmap().getWidth() / 2f, -1f * view.getImageBitmap().getHeight()/ 2f)對應的矩陣是:
由于是preTranslate,是先乘,也就是右乘,即它應該出現在matrix.setRotate(45f)所對應矩陣的右側。
?
matrix.postTranslate((float)view.getImageBitmap().getWidth()/ 2f, (float)view.getImageBitmap().getHeight() / 2f)對應的矩陣是:
這次由于是postTranslate,是后乘,也就是左乘,即它應該出現在matrix.setRotate(45f)所對應矩陣的左側。
?
所以綜合起來,
matrix.setRotate(45f);
matrix.preTranslate(-1f* view.getImageBitmap().getWidth() / 2f, -1f *view.getImageBitmap().getHeight() / 2f);
matrix.postTranslate((float)view.getImageBitmap().getWidth()/ 2f, (float)view.getImageBitmap().getHeight() / 2f);
對應的矩陣就是:
這和下面這個矩陣(圍繞圖像中心順時針旋轉45度)其實是一樣的:
因此,此處變換后的圖像和2中變換后的圖像時一樣的。
?
4.???? 縮放變換
程序所輸出的兩個矩陣分別是:
其中第二個矩陣,其實是下面兩個矩陣相乘的結果:
?
大家可以對照第一部分中的“三、縮放變換”和“一、平移變換”說法,自行驗證結果。
?
5.???? 錯切變換(水平錯切)
代碼所輸出的兩個矩陣分別是:
其中,第二個矩陣其實是下面兩個矩陣相乘的結果:
?
大家可以對照第一部分中的“四、錯切變換”和“一、平移變換”的相關說法,自行驗證結果。
?
6.???? 錯切變換(垂直錯切)
代碼所輸出的兩個矩陣分別是:
其中,第二個矩陣其實是下面兩個矩陣相乘的結果:
大家可以對照第一部分中的“四、錯切變換”和“一、平移變換”的相關說法,自行驗證結果。
?
7.???? 錯切變換(水平+垂直錯切)
代碼所輸出的兩個矩陣分別是:
其中,后者是下面兩個矩陣相乘的結果:
大家可以對照第一部分中的“四、錯切變換”和“一、平移變換”的相關說法,自行驗證結果。
?
8.???? 對稱變換(水平對稱)
代碼所輸出的兩個各矩陣分別是:
其中,后者是下面兩個矩陣相乘的結果:
?
大家可以對照第一部分中的“五、對稱變換”和“一、平移變換”的相關說法,自行驗證結果。
?
9.???? 對稱變換(垂直對稱)
代碼所輸出的兩個矩陣分別是:
其中,后者是下面兩個矩陣相乘的結果:
?
大家可以對照第一部分中的“五、對稱變換”和“一、平移變換”的相關說法,自行驗證結果。
?
10.?? 對稱變換(對稱軸為直線y = x)
代碼所輸出的兩個矩陣分別是:
其中,后者是下面兩個矩陣相乘的結果:
?
大家可以對照第一部分中的“五、對稱變換”和“一、平移變換”的相關說法,自行驗證結果。
?
11.?? 關于先乘和后乘的問題
由于矩陣的乘法運算不滿足交換律,我們在前面曾經多次提及先乘、后乘的問題,即先乘就是矩陣運算中右乘,后乘就是矩陣運算中的左乘。其實先乘、后乘的概念是針對變換操作的時間先后而言的,左乘、右乘是針對矩陣運算的左右位置而言的。以第一部分“二、旋轉變換”中圍繞某點旋轉的情況為例:
?
越靠近原圖像中像素的矩陣,越先乘,越遠離原圖像中像素的矩陣,越后乘。事實上,圖像處理時,矩陣的運算是從右邊往左邊方向進行運算的。這就形成了越在右邊的矩陣(右乘),越先運算(先乘),反之亦然。
?
當然,在實際中,如果首先指定了一個matrix,比如我們先setRotate(),即指定了上面變換矩陣中,中間的那個矩陣,那么后續的矩陣到底是pre還是post運算,都是相對這個中間矩陣而言的。
?
轉載于:https://www.cnblogs.com/wugu-ren/p/6179076.html
總結
以上是生活随笔為你收集整理的Android笔记——Matrix的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 亮灯问题
- 下一篇: 算法训练 出现次数最多的整数