您的位置:首页 > 移动开发 > Android开发

Android Matrix图形变换

2015-06-26 01:15 531 查看
平移变换



从坐标(x0,y0)变换到(x, y)

x = x0 + △x

y =y0 + △y

坐标x,y写作矩阵C

[ x

y

1 ]

原坐标x0,y0写作矩阵B

[x0

y0

1 ]

想通过矩阵B得到矩阵C,根据矩阵乘法公式,

x = a*x0 + b*y0 + c*1, 由于x = x0 + △x, 所以推导出, a = 1, b = 0, c = △x

y = d*x0 + e*y0 + f * 1, 由于x = x0 + △x, 所以推导出, d = 0, e = 1, f = △y

1 = g *x0 + h*y0+ i*1 , 所以推导出,g = 0, h = 0 ,i= 1

由上述推导可得左乘矩阵B的矩阵A为:

[ 1 0 △x

0 1 △y

0 0 1 ]

旋转变换



如图所示,点(x0, y0)以o为圆心,旋转θ角度,到一个新的点(x,y),四个点分别用公式表示:

x0 = rcosα
y0 = rsinα
x = rcos(α+θ) = rcosαcosθ - rsinαsinθ = x0cosθ - y0sinθ

y = rsin(α+θ) = rsinαcosθ + rcosαsinθ = y0cosθ + x0sinθ

坐标x,y写作矩阵C

[ x

y

1 ]

原坐标x0,y0写作矩阵B

[x0

y0

1 ]

想通过矩阵B得到矩阵C,根据矩阵乘法公式,

x = a*x0 + b*y0 + c*1, 由于x = x0cosθ - y0sinθ, 所以推导出, a = cosθ, b = -sinθ, c = 0

y = d*x0 + e*y0 + f * 1, 由于x = y0cosθ + x0sinθ, 所以推导出, d = sinθ, e = cosθ, f = 0

1 = g *x0 + h*y0+ i*1 , 所以推导出,g = 0, h = 0 ,i= 1

由上述推导可得左乘矩阵B的矩阵A为:

[ cosθ -sinθ 0

sinθ cosθ 0

0 0 1 ]

缩放变换



如图,坐标公式

x = k*x0

y = k*y0

坐标x,y写作矩阵C

[ x

y

1 ]

原坐标x0,y0写作矩阵B

[x0

y0

1 ]

想通过矩阵B得到矩阵C,根据矩阵乘法公式,

x = a*x0 + b*y0 + c*1, 由于x = kx0, 所以推导出, a = k1, b =0, c = 0

y = d*x0 + e*y0 + f * 1, 由于x =ky0, 所以推导出, d = 0, e = k2, f = 0

1 = g *x0 + h*y0+ i*1 , 所以推导出,g = 0, h = 0 ,i= 1

由上述推导可得左乘矩阵B的矩阵A为:

[ k1 0 0

0 k2 0

0 0 1 ]

错切变换

水平错切:



垂直错切:



如图,坐标公式:

x = x0 + k1 * y0

y = k2*x0 + y0

坐标x,y写作矩阵C

[ x

y

1 ]

原坐标x0,y0写作矩阵B

[x0

y0

1 ]

想通过矩阵B得到矩阵C,根据矩阵乘法公式,

x = a*x0 + b*y0 + c*1, 由于x = x0 + k1*y0 , 所以推导出, a = 1, b =k1, c = 0

y = d*x0 + e*y0 + f * 1, 由于y =k2*x0 + y0, 所以推导出, d = k2, e = 1, f = 0

1 = g *x0 + h*y0+ i*1 , 所以推导出,g = 0, h = 0 ,i= 1

由上述推导可得左乘矩阵B的矩阵A为:

[ 1 k1 0

k2 1 0

0 0 1 ]

由以上几个推导看出,对于矩阵:

[ a b c

d e
f

g h i ]

a,e 控制缩放,b,d 控制错切,c,f 控制平移

下面用一个例子说明:

创建一个Activity,布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_weight="2" />

<GridLayout
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:columnCount="3"
android:rowCount="3" >
</GridLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="btnChange"
android:text="Change" />

<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="btnReset"
android:text="Reset" />
</LinearLayout>

</LinearLayout>
最上面是显示图片的ImageView,下方GridView中会通过代码增加3*3的EditText,用于控制Matrix的值。

Activity:

public class MainActivity extends ActionBarActivity {

private ImageView mImageView;
private GridLayout mGroup;
private int mEtWidth, mEtHeight;
private EditText[] mEts = new EditText[9];
private float[] mMatrix = new float[9];
private Bitmap originBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mImageView = (ImageView) findViewById(R.id.imageview);
mGroup = (GridLayout) findViewById(R.id.group);

originBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.dragon);
mImageView.setImageBitmap(originBitmap);

// GridView的大小确定后,
// 计算其中每个EditText应有的大小(3*3),
// 并添加到GridView中。
mGroup.post(new Runnable() {

@Override
public void run() {
mEtWidth = mGroup.getWidth() / 3;
mEtHeight = mGroup.getHeight() / 3;
addEts();
}
});
}

public void btnChange(View view) {
getMatrix();
setImageMatrix();
}

public void btnReset(View view) {
initMatrix();
getMatrix();
setImageMatrix();
}

private void setImageMatrix() {

Bitmap newBitmap = Bitmap.createBitmap(originBitmap.getWidth(),
originBitmap.getHeight(), Bitmap.Config.ARGB_8888);

// 设置新的Matrix.
Matrix matrix = new Matrix();
matrix.setValues(mMatrix);
// 使用新的Matrix绘制Bitmap
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(originBitmap, matrix, paint);
mImageView.setImageBitmap(newBitmap);
}

private void addEts() {
for (int i = 0; i < 9; i++) {
EditText editText = new EditText(MainActivity.this);
editText.setBackground(getResources().getDrawable(
R.drawable.common_textfield_background));
//editText.setInputType(InputType.TYPE_CLASS_NUMBER
//		| InputType.TYPE_NUMBER_FLAG_DECIMAL);
mEts[i] = editText;
mGroup.addView(editText, mEtWidth, mEtHeight);
}
}

//将输入框内的数字组装成为Matrix内数组的值
private void getMatrix() {
for (int i = 0; i < 9; i++) {
String etNum = mEts[i].getText().toString();
if (TextUtils.isEmpty(etNum)) {
mEts[i].setText("0");
etNum = "0";
}
mMatrix[i] = Float.valueOf(etNum);
}
}

/**
* 初始化矩阵数组为: [ 1 0 0 ,0 1 0 ,0 0 1 ]
* */
private void initMatrix() {
for (int i = 0; i < 9; i++) {
if (i % 4 == 0) {
mEts[i].setText(String.valueOf(1));
} else {
mEts[i].setText(String.valueOf(0));
}
}
}
}

以上代码,setImageMatrix方法通过用户输入,改变Matrix内部数组的值,并用这个Matrix绘制新的Bitmap,来改变图片的显示效果。getMatrix方法用于把EditText里面的数字赋值到 mMatrix数组中。

下面运行这个例子,尝试几个变换:

缩放:







平移:



错切:



旋转30°:



Matrix类提供了一些方法直接实现以上的一些效果:

setRotate:旋转

setSkew:错切

setTranslate:平移

setScale:缩放

如果需要做组合变换,可以使用postXXX/preXXX方法:

postScale/postSkew/postTranslate/postRotate

preScale/preSkew/preTranslate/preRotate

post和pre的区别是,以postTranslate为例,M' = T(dx, dy) * M,新的矩阵是由这个平移变换的矩阵左乘M矩阵,意味着最后做平移这个变换。

preTranslate:M' = M * T(dx, dy),右乘M矩阵,意味着这个平移变换在M的变换之前发生。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: