转自 :http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#code

Matrix的数学原理

平移变换

旋转变换

缩放变换

错切变换

对称变换

代码验证

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轴方向分别放大k1k2倍的话,那么图像中的所有点的x坐标和y坐标均会分别放大k1k2倍,即

用矩阵表示就是:

缩放变换比较好理解,就不多说了。

四、 错切变换

错切变换(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。

每种变换的结果,请见代码之后的说明。

  1. <span style="font-size:13px;"></span><pre name="code" class="java">package com.pat.testtransformmatrix;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.graphics.Canvas;
  7. import android.graphics.Matrix;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android.view.MotionEvent;
  11. import android.view.View;
  12. import android.view.Window;
  13. import android.view.WindowManager;
  14. import android.view.View.OnTouchListener;
  15. import android.widget.ImageView;
  16. public class TestTransformMatrixActivity extends Activity
  17. implements
  18. OnTouchListener
  19. {
  20. private TransformMatrixView view;
  21. @Override
  22. public void onCreate(Bundle savedInstanceState)
  23. {
  24. super.onCreate(savedInstanceState);
  25. requestWindowFeature(Window.FEATURE_NO_TITLE);
  26. this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
  27. view = new TransformMatrixView(this);
  28. view.setScaleType(ImageView.ScaleType.MATRIX);
  29. view.setOnTouchListener(this);
  30. setContentView(view);
  31. }
  32. class TransformMatrixView extends ImageView
  33. {
  34. private Bitmap bitmap;
  35. private Matrix matrix;
  36. public TransformMatrixView(Context context)
  37. {
  38. super(context);
  39. bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sophie);
  40. matrix = new Matrix();
  41. }
  42. @Override
  43. protected void onDraw(Canvas canvas)
  44. {
  45. // 画出原图像
  46. canvas.drawBitmap(bitmap, 0, 0, null);
  47. // 画出变换后的图像
  48. canvas.drawBitmap(bitmap, matrix, null);
  49. super.onDraw(canvas);
  50. }
  51. @Override
  52. public void setImageMatrix(Matrix matrix)
  53. {
  54. this.matrix.set(matrix);
  55. super.setImageMatrix(matrix);
  56. }
  57. public Bitmap getImageBitmap()
  58. {
  59. return bitmap;
  60. }
  61. }
  62. public boolean onTouch(View v, MotionEvent e)
  63. {
  64. if(e.getAction() == MotionEvent.ACTION_UP)
  65. {
  66. Matrix matrix = new Matrix();
  67. // 输出图像的宽度和高度(162 x 251)
  68. Log.e("TestTransformMatrixActivity", "image size: width x height = " +  view.getImageBitmap().getWidth() + " x " + view.getImageBitmap().getHeight());
  69. // 1. 平移
  70. matrix.postTranslate(view.getImageBitmap().getWidth(), view.getImageBitmap().getHeight());
  71. // 在x方向平移view.getImageBitmap().getWidth(),在y轴方向view.getImageBitmap().getHeight()
  72. view.setImageMatrix(matrix);
  73. // 下面的代码是为了查看matrix中的元素
  74. float[] matrixValues = new float[9];
  75. matrix.getValues(matrixValues);
  76. for(int i = 0; i < 3; ++i)
  77. {
  78. String temp = new String();
  79. for(int j = 0; j < 3; ++j)
  80. {
  81. temp += matrixValues[3 * i + j ] + "\t";
  82. }
  83. Log.e("TestTransformMatrixActivity", temp);
  84. }
  85. //          // 2. 旋转(围绕图像的中心点)
  86. //          matrix.setRotate(45f, view.getImageBitmap().getWidth() / 2f, view.getImageBitmap().getHeight() / 2f);
  87. //
  88. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  89. //          matrix.postTranslate(view.getImageBitmap().getWidth() * 1.5f, 0f);
  90. //          view.setImageMatrix(matrix);
  91. //
  92. //          // 下面的代码是为了查看matrix中的元素
  93. //          float[] matrixValues = new float[9];
  94. //          matrix.getValues(matrixValues);
  95. //          for(int i = 0; i < 3; ++i)
  96. //          {
  97. //              String temp = new String();
  98. //              for(int j = 0; j < 3; ++j)
  99. //              {
  100. //                  temp += matrixValues[3 * i + j ] + "\t";
  101. //              }
  102. //              Log.e("TestTransformMatrixActivity", temp);
  103. //          }
  104. //          // 3. 旋转(围绕坐标原点) + 平移(效果同2)
  105. //          matrix.setRotate(45f);
  106. //          matrix.preTranslate(-1f * view.getImageBitmap().getWidth() / 2f, -1f * view.getImageBitmap().getHeight() / 2f);
  107. //          matrix.postTranslate((float)view.getImageBitmap().getWidth() / 2f, (float)view.getImageBitmap().getHeight() / 2f);
  108. //
  109. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  110. //          matrix.postTranslate((float)view.getImageBitmap().getWidth() * 1.5f, 0f);
  111. //          view.setImageMatrix(matrix);
  112. //
  113. //          // 下面的代码是为了查看matrix中的元素
  114. //          float[] matrixValues = new float[9];
  115. //          matrix.getValues(matrixValues);
  116. //          for(int i = 0; i < 3; ++i)
  117. //          {
  118. //              String temp = new String();
  119. //              for(int j = 0; j < 3; ++j)
  120. //              {
  121. //                  temp += matrixValues[3 * i + j ] + "\t";
  122. //              }
  123. //              Log.e("TestTransformMatrixActivity", temp);
  124. //          }
  125. //          // 4. 缩放
  126. //          matrix.setScale(2f, 2f);
  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. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  141. //          matrix.postTranslate(view.getImageBitmap().getWidth(), view.getImageBitmap().getHeight());
  142. //          view.setImageMatrix(matrix);
  143. //
  144. //          // 下面的代码是为了查看matrix中的元素
  145. //          matrixValues = new float[9];
  146. //          matrix.getValues(matrixValues);
  147. //          for(int i = 0; i < 3; ++i)
  148. //          {
  149. //              String temp = new String();
  150. //              for(int j = 0; j < 3; ++j)
  151. //              {
  152. //                  temp += matrixValues[3 * i + j ] + "\t";
  153. //              }
  154. //              Log.e("TestTransformMatrixActivity", temp);
  155. //          }
  156. //          // 5. 错切 - 水平
  157. //          matrix.setSkew(0.5f, 0f);
  158. //          // 下面的代码是为了查看matrix中的元素
  159. //          float[] matrixValues = new float[9];
  160. //          matrix.getValues(matrixValues);
  161. //          for(int i = 0; i < 3; ++i)
  162. //          {
  163. //              String temp = new String();
  164. //              for(int j = 0; j < 3; ++j)
  165. //              {
  166. //                  temp += matrixValues[3 * i + j ] + "\t";
  167. //              }
  168. //              Log.e("TestTransformMatrixActivity", temp);
  169. //          }
  170. //
  171. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  172. //          matrix.postTranslate(view.getImageBitmap().getWidth(), 0f);
  173. //          view.setImageMatrix(matrix);
  174. //
  175. //          // 下面的代码是为了查看matrix中的元素
  176. //          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. //          // 6. 错切 - 垂直
  188. //          matrix.setSkew(0f, 0.5f);
  189. //          // 下面的代码是为了查看matrix中的元素
  190. //          float[] matrixValues = new float[9];
  191. //          matrix.getValues(matrixValues);
  192. //          for(int i = 0; i < 3; ++i)
  193. //          {
  194. //              String temp = new String();
  195. //              for(int j = 0; j < 3; ++j)
  196. //              {
  197. //                  temp += matrixValues[3 * i + j ] + "\t";
  198. //              }
  199. //              Log.e("TestTransformMatrixActivity", temp);
  200. //          }
  201. //
  202. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  203. //          matrix.postTranslate(0f, view.getImageBitmap().getHeight());
  204. //          view.setImageMatrix(matrix);
  205. //
  206. //          // 下面的代码是为了查看matrix中的元素
  207. //          matrixValues = new float[9];
  208. //          matrix.getValues(matrixValues);
  209. //          for(int i = 0; i < 3; ++i)
  210. //          {
  211. //              String temp = new String();
  212. //              for(int j = 0; j < 3; ++j)
  213. //              {
  214. //                  temp += matrixValues[3 * i + j ] + "\t";
  215. //              }
  216. //              Log.e("TestTransformMatrixActivity", temp);
  217. //          }
  218. //          7. 错切 - 水平 + 垂直
  219. //          matrix.setSkew(0.5f, 0.5f);
  220. //          // 下面的代码是为了查看matrix中的元素
  221. //          float[] matrixValues = new float[9];
  222. //          matrix.getValues(matrixValues);
  223. //          for(int i = 0; i < 3; ++i)
  224. //          {
  225. //              String temp = new String();
  226. //              for(int j = 0; j < 3; ++j)
  227. //              {
  228. //                  temp += matrixValues[3 * i + j ] + "\t";
  229. //              }
  230. //              Log.e("TestTransformMatrixActivity", temp);
  231. //          }
  232. //
  233. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  234. //          matrix.postTranslate(0f, view.getImageBitmap().getHeight());
  235. //          view.setImageMatrix(matrix);
  236. //
  237. //          // 下面的代码是为了查看matrix中的元素
  238. //          matrixValues = new float[9];
  239. //          matrix.getValues(matrixValues);
  240. //          for(int i = 0; i < 3; ++i)
  241. //          {
  242. //              String temp = new String();
  243. //              for(int j = 0; j < 3; ++j)
  244. //              {
  245. //                  temp += matrixValues[3 * i + j ] + "\t";
  246. //              }
  247. //              Log.e("TestTransformMatrixActivity", temp);
  248. //          }
  249. //          // 8. 对称 (水平对称)
  250. //          float matrix_values[] = {1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f};
  251. //          matrix.setValues(matrix_values);
  252. //          // 下面的代码是为了查看matrix中的元素
  253. //          float[] matrixValues = new float[9];
  254. //          matrix.getValues(matrixValues);
  255. //          for(int i = 0; i < 3; ++i)
  256. //          {
  257. //              String temp = new String();
  258. //              for(int j = 0; j < 3; ++j)
  259. //              {
  260. //                  temp += matrixValues[3 * i + j ] + "\t";
  261. //              }
  262. //              Log.e("TestTransformMatrixActivity", temp);
  263. //          }
  264. //
  265. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  266. //          matrix.postTranslate(0f, view.getImageBitmap().getHeight() * 2f);
  267. //          view.setImageMatrix(matrix);
  268. //
  269. //          // 下面的代码是为了查看matrix中的元素
  270. //          matrixValues = new float[9];
  271. //          matrix.getValues(matrixValues);
  272. //          for(int i = 0; i < 3; ++i)
  273. //          {
  274. //              String temp = new String();
  275. //              for(int j = 0; j < 3; ++j)
  276. //              {
  277. //                  temp += matrixValues[3 * i + j ] + "\t";
  278. //              }
  279. //              Log.e("TestTransformMatrixActivity", temp);
  280. //          }
  281. //          // 9. 对称 - 垂直
  282. //          float matrix_values[] = {-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f};
  283. //          matrix.setValues(matrix_values);
  284. //          // 下面的代码是为了查看matrix中的元素
  285. //          float[] matrixValues = new float[9];
  286. //          matrix.getValues(matrixValues);
  287. //          for(int i = 0; i < 3; ++i)
  288. //          {
  289. //              String temp = new String();
  290. //              for(int j = 0; j < 3; ++j)
  291. //              {
  292. //                  temp += matrixValues[3 * i + j ] + "\t";
  293. //              }
  294. //              Log.e("TestTransformMatrixActivity", temp);
  295. //          }
  296. //
  297. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  298. //          matrix.postTranslate(view.getImageBitmap().getWidth() * 2f, 0f);
  299. //          view.setImageMatrix(matrix);
  300. //
  301. //          // 下面的代码是为了查看matrix中的元素
  302. //          matrixValues = new float[9];
  303. //          matrix.getValues(matrixValues);
  304. //          for(int i = 0; i < 3; ++i)
  305. //          {
  306. //              String temp = new String();
  307. //              for(int j = 0; j < 3; ++j)
  308. //              {
  309. //                  temp += matrixValues[3 * i + j ] + "\t";
  310. //              }
  311. //              Log.e("TestTransformMatrixActivity", temp);
  312. //          }
  313. //          // 10. 对称(对称轴为直线y = x)
  314. //          float matrix_values[] = {0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f};
  315. //          matrix.setValues(matrix_values);
  316. //          // 下面的代码是为了查看matrix中的元素
  317. //          float[] matrixValues = new float[9];
  318. //          matrix.getValues(matrixValues);
  319. //          for(int i = 0; i < 3; ++i)
  320. //          {
  321. //              String temp = new String();
  322. //              for(int j = 0; j < 3; ++j)
  323. //              {
  324. //                  temp += matrixValues[3 * i + j ] + "\t";
  325. //              }
  326. //              Log.e("TestTransformMatrixActivity", temp);
  327. //          }
  328. //
  329. //          // 做下面的平移变换,纯粹是为了让变换后的图像和原图像不重叠
  330. //          matrix.postTranslate(view.getImageBitmap().getHeight() + view.getImageBitmap().getWidth(),
  331. //                  view.getImageBitmap().getHeight() + view.getImageBitmap().getWidth());
  332. //          view.setImageMatrix(matrix);
  333. //
  334. //          // 下面的代码是为了查看matrix中的元素
  335. //          matrixValues = new float[9];
  336. //          matrix.getValues(matrixValues);
  337. //          for(int i = 0; i < 3; ++i)
  338. //          {
  339. //              String temp = new String();
  340. //              for(int j = 0; j < 3; ++j)
  341. //              {
  342. //                  temp += matrixValues[3 * i + j ] + "\t";
  343. //              }
  344. //              Log.e("TestTransformMatrixActivity", temp);
  345. //          }
  346. view.invalidate();
  347. }
  348. return true;
  349. }
  350. }

下面给出上述代码中,各种变换的具体结果及其对应的相关变换矩阵

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运算,都是相对这个中间矩阵而言的。

Android Matrix的更多相关文章

  1. Android Matrix(坐标矩阵)

    Android Matrix 2016-02-26 14:38:10 介绍 中文名:坐标矩阵 高等数学里有介绍,在图像处理方面,主要是用于平面的缩放.平移.旋转等操作. 在Android里面,Matr ...

  2. Android Matrix类以及ColorMatri

    引自:http://www.chinabaike.com/t/37396/2014/0624/2556217.html Android Matrix类以及ColorMatrix类详解 最近在系统学习了 ...

  3. Android Matrix用法

    Matrix,中文里叫矩阵,高等数学里有介绍,在图像处理方面,主要是用于平面的缩放.平移.旋转等操作. 首先介绍一下矩阵运算.加法和减法就不用说了,太简单了,对应位相加就好.图像处理,主要用到的是乘法 ...

  4. Android Matrix详解

    Matrix的数学原理 平移变换 旋转变换 缩放变换 错切变换 对称变换 代码验证 Matrix的数学原理 在Android中,如果你用Matrix进行过图像处理,那么一定知道Matrix这个类.An ...

  5. Android Matrix理论与应用详解

    转:http://zensheno.blog.51cto.com/2712776/513652 Matrix学习——基础知识 以前在线性代数中学习了矩阵,对矩阵的基本运算有一些了解,前段时间在使用GD ...

  6. Android 之 Matrix(转)

    原文:http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#code Android Matrix   Matrix的数学原理 平 ...

  7. Android中的Matrix(矩阵)

    写在前面 看这篇笔记之前先看一下参考文章,这篇笔记没有系统的讲述矩阵和代码的东西,参考文章写的也有错误的地方,要辨证的看. 如何计算矩阵乘法 android matrix 最全方法详解与进阶(完整篇) ...

  8. android图片处理方法

    Java代码 //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ...

  9. Android -- View setScale, setTranslation 对View矩阵的处理

    参考: 1.Android Matrix理论与应用详解 2.2D平面中关于矩阵(Matrix)跟图形变换的讲解 3.Android中关于矩阵(Matrix)前乘后乘的一些认识 4.Android Ma ...

随机推荐

  1. Laravel 5.1 文档攻略 —— Eloquent: 读取器和修饰器

    date_range 8月前 tag_faces Woody remove_red_eye 1483 chat0 简介 这一章其实很简单,Model的属性不是和数据表的字段一一对应吗? 那么在存储和呈 ...

  2. 跟着百度学PHP[4]OOP面对对象编程-6-封装性private

    所谓封装顾名思义,如同箱子般给封装起来.结合前面的来说就是对属性或者方法,封装后的方法或属性只能有类内部进行调用.外部调用不了. 封装性的好处: 1.信息隐藏 2.http://www.cnblogs ...

  3. Apache 无法启动

    本人是做前端开发的,对后台程序不太熟悉,也就以前学过一点.net.但现在都忘记的差不多了.最近在公司,经理给了我一个管理工具dedecms,我刚开始看的时候完全不懂这是什么东西,之前都没听说过(本人见 ...

  4. linux操作系统flash player问题--ubuntu

    adobe公司停止了对linux系统的flash player的更新,这导致很多网页视频不能够通过浏览器观看,很是不爽! 还好,给用户留下了一点点希望,那便是chrome浏览器. 谷歌浏览器,有一款插 ...

  5. gedit配置记

    gedit配置记 起因 突然感觉sublime用用这里那里不方便(虽然很好看> >),然后稍微手调了一下gedit发现gedit还是非常可用的(雾)... 阶段一 我感觉sublime各种 ...

  6. linux 终端报错 Out of memory: Kill process[PID] [process name] score问题分析

    从Out of memory来看是内存超出了,后面的 Kill process[PID] [process name] score好像和进程有关了,下面我们就一起来看看linux 终端报错 Out o ...

  7. Oauth 2.0第三方账号登录原理图

    百度.QQ等服务商

  8. 【leetcode】Populating Next Right Pointers in Each Node II

    Populating Next Right Pointers in Each Node II Follow up for problem "Populating Next Right Poi ...

  9. linux资源使用配置文件 /etc/security/limits.conf和ulimit

    limits.conf文件实际上是linux PAM中pam_limits.so的配置文件,而且只针对于单个会话. limits.conf的格式如下: <domain> <type& ...

  10. Oracle备份之RMAN

    1.备份:物理备份时文件层次的备份,逻辑备份时数据层次的备份,物理备份为主,逻辑备份作为补充.物理备份分为用户管理备份和RMAN备份,前者使用SQL命令和OS的cp命令进行文件备份,后者使用RMAN工 ...