Matrix与图像变换

时间:2023-02-07 13:43:48

在Android中我们经常需要在屏幕上显示变换的图像,比如显示一张旋转的图像,或者一张图片做点斜切,产生类似于透视的效果。这些都需要依赖于Matrix类。其中用得最多的就是
Bitmap类的
public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
以及Canvas类的
public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
这两个方法了。

我们写个程序比较一下二者的区别。


public MyView(Context context , AttributeSet set)
{
super(context , set);
// 获得位图
bitmap = ((BitmapDrawable) context.getResources().getDrawable(
R.drawable.a)).getBitmap();
// 获得位图宽
width = bitmap.getWidth();
// 获得位图高
height = bitmap.getHeight();
// 使当前视图获得焦点
this.setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// 重置Matrix
matrix.reset();
if (!isScale)
{
// 旋转Matrix
matrix.setSkew(sx, 0);
Log.d("matrix", "matrix is : "+matrix);
}
else
{
// 缩放Matrix
matrix.setScale(scale, scale);
}
// 根据原始位图和Matrix创建新图片
Bitmap bitmap2 = Bitmap.createBitmap(bitmap, 0, 0, width/2, height/2,
matrix, true); //(0)
Log.d("matrix", "original (w,h)"+width+","+height);
Log.d("matrix", "(w,h)"+bitmap2.getWidth()+","+bitmap2.getHeight());
// 绘制新位图
//canvas.drawBitmap(bitmap, matrix, null); //(1)
canvas.drawBitmap(bitmap2,0,0,null); //(2)
}
以上代码,当我们启用(1)处的代码绘制图像时,绘制的原始图像bitmap,但是在绘制时使用matrix对图像进行了变换。此时如果matrix是

1000.110001

则生成的图像如下图
Matrix与图像变换
可以看到整个图像自上而下往左倾斜。这个很容易通过数学来解释。因为屏幕坐标系如图所示,x轴向右,y轴向下,而我们上面matrix矩阵的 m12 元素有个-0.1的值。那也就是说原来图像上(x,y)上的点会被绘制到(x-0.1y,y)位置处。所以导致随着y的增大(图像由第一行往下),图像上的点的横向位置都比原始位置更靠左(x坐标更小),于是就形成了上述效果。图像左边缘已经超出屏幕范围了。

使用同样的矩阵,如果我们启用(2)出的代码,也就是说我们在生成bitmap图像的时候就对图像做变换,而在绘制的时候按照图像本身原原本本地绘制。我们看到的效果如下图
Matrix与图像变换
可以看到效果和前次类似,但又不完全一样。
类似是指图像从上往下还是向左倾斜。这表明在drawBitmap和createBitmap时matrix启的作用是相同的,都是将像素点的坐标构成的列向量左乘矩阵matrix,以得到新的位置。
不一样的地方在于,图像的左边缘不超出屏幕了。这是因为此时上次超出屏幕的部分现在已经是图像的一部分,如果此时查看图像的大小可以看到图像已经由300*294变成了329*294大小了,而329正是300+0.1*294得到的。此时图像的原点已经不再是白色区域的左上角了,而是新补上去的黑色区域的左上角,所以图像能够完全显示。

总结,图像变换时matrix的作用在于改变像素的位置,牢记这一点以后使用matrix才能够正确地设置各个位置的参数。