Android Camera 的学习记录

本文详细介绍如何在Android中利用Camera与Matrix实现3D效果,包括Camera的基本使用、坐标系介绍及常见API说明,并通过具体示例展示了如何实现旋转和平移等效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android中利用Camera与Matrix实现3D效果详解 - 优快云博客
http://blog.youkuaiyun.com/zhangke3016/article/details/52093776






android 中存在两Camera,这里说的是 android.graphics.Camera;

官方介绍

A camera instance can be used to compute 3D transformations and generate a matrix that can be applied, for instance, on a Canvas. 
一个照相机实例可以被用于计算3D变换,生成一个可以被使用的Matrix矩阵,一个实例,用在画布上。

Camera内部机制实际上还是opengl,不过大大简化了使用。有了感性的认识之后,我们再来看下它的常用API定义:

Camera() 创建一个没有任何转换效果的新的Camera实例 

applyToCanvas(Canvas canvas) 根据当前的变换计算出相应的矩阵,然后应用到制定的画布上 
getLocationX() 获取Camera的x坐标 
getLocationY() 获取Camera的y坐标 
getLocationZ() 获取Camera的z坐标 
getMatrix(Matrix matrix) 获取转换效果后的Matrix对象 
restore() 恢复保存的状态 
rotate(float x, float y, float z) 沿X、Y、Z坐标进行旋转 
rotateX(float deg) 
rotateY(float deg) 
rotateZ(float deg) 
save() 保存状态 
setLocation(float x, float y, float z) 
translate(float x, float y, float z)沿X、Y、Z轴进行平移

不得不说下Matrix,它是Android提供的一个矩阵工具类,是一个3x3的矩阵,一般要实现2D的旋转(绕z轴旋转)、缩放、平移、倾斜用这个作用于画布,这四种操作的内部实现过程都是通过matrix.setValues(…)来设置矩阵的值来达到变换的效果。

setTranslate(float dx,float dy):控制Matrix进行平移 
setSkew(float kx,float ky,float px,float py):控制Matrix以px,py为轴心进行倾斜,kx,ky为X,Y方向上的倾斜距离 
setRotate(float degress):控制Matrix进行旋转,degress控制旋转的角度 
setRorate(float degress,float px,float py):设置以px,py为轴心进行旋转,degress控制旋转角度 
setScale(float sx,float sy):设置Matrix进行缩放,sx,sy控制X,Y方向上的缩放比例 
setScale(float sx,float sy,float px,float py):设置Matrix以px,py为轴心进行缩放,sx,sy控制X,Y方向上的缩放比例


API提供了set、post和pre三种操作,下面这个重点看下,之后效果会用到

post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。 
pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。

好了,上面基本方法先简单了解下,现在让我们看看能做出什么效果,之后回头再重新看看会有更深的理解。

二、Camera与Matrix旋转效果拆分介绍

Camera坐标系研究 
Camera的坐标系是左手坐标系。当手机平整的放在桌面上,X轴是手机的水平方向,Y轴是手机的竖直方向,Z轴是垂直于手机向里的那个方向。

左手坐标系

camera位于坐标点(0,0),也就是视图的左上角; 
camera.translate(10,50,-180)的意思是把观察物体右移(+x)10,上移(+z)50,向-z轴移180(即让物体接近camera,这样物体将会变大); 
原图:

public class CameraTestView extends View{

    private Camera camera;
    private Matrix matrix;
    private Paint paint;
    public CameraTestView(Context context, AttributeSet attrs) {
        super(context, attrs);
        camera = new Camera();
        matrix = new Matrix();
        setBackgroundColor(Color.parseColor("#3f51b5"));
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Style.FILL);
        paint.setColor(Color.parseColor("#ff4081"));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawCircle(60, 60, 60, paint);
    }
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    tools:context=".MainActivity" >

    <com.example.matrixcamera.CameraTestView
        android:layout_width="200dp"
        android:layout_height="200dp"
        />

</RelativeLayout>
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

原图

    @Override
    protected void onDraw(Canvas canvas) {
        matrix.reset();
        camera.save();
        camera.translate(10, 50, -180);
        camera.getMatrix(matrix);
        camera.restore();
        canvas.concat(matrix);

        canvas.drawCircle(60, 60, 60, paint);
    }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

translate(10, 50, -180)

camera.rotateX(60)的意思是绕X轴顺时针旋转60度。举例来说,如果物体中间线和X轴重合的话,绕X轴顺时针旋转60度就是指物体上半部分向里翻转,下半部分向外翻转;

@Override
    protected void onDraw(Canvas canvas) {
        Options option = new Options();
        option.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), R.drawable.aa,option);
        option.inSampleSize = calculateInSampleSize(option, getWidth()/2, getHeight()/2);
        option.inJustDecodeBounds = false;
        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.aa,option), matrix, paint);
    }
    private int calculateInSampleSize(BitmapFactory.Options options,  
            int reqWidth, int reqHeight) {  
        final int height = options.outHeight;  
        final int width = options.outWidth;  
        int inSampleSize = 1;  
        if (height > reqHeight || width > reqWidth) {  
            final int halfHeight = height / 2;  
            final int halfWidth = width / 2;  
            while ((halfHeight / inSampleSize) > reqHeight  
                    && (halfWidth / inSampleSize) > reqWidth) {  
                inSampleSize *= 2;  
            }  
        }  
        return inSampleSize;  
    } 
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

未旋转图片

@Override
    protected void onDraw(Canvas canvas) {
        matrix.reset();
        camera.save();
        camera.rotateX(60);
        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-getWidth()/2, -getHeight()/2);
        matrix.postTranslate(getWidth()/2, getHeight()/2);

        Options option = new Options();
        option.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), R.drawable.aa,option);
        option.inSampleSize = calculateInSampleSize(option, getWidth()/2, getHeight()/2);
        option.inJustDecodeBounds = false;
        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.aa,option), matrix, paint);
    }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

绕X轴顺时针旋转60度 
camera.rotateY(60)的意思是绕Y轴顺时针旋转60度。举例来说,如果物体中间线和Y轴重合的话,绕Y轴顺时针旋转60度就是指物体左半部分向外翻转,右半部分向里翻转;

@Override
    protected void onDraw(Canvas canvas) {
         ...
                  camera.rotateY(60);
                ...
    }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

绕Y轴顺时针旋转60度

camera.rotateZ(60)的意思是绕Z轴逆时针旋转60度。举例来说,如果物体中间线和Z轴重合的话,绕Z轴顺时针旋转60度就是物体上半部分向左翻转,下半部分向右翻转。

@Override
    protected void onDraw(Canvas canvas) {
                ...
                camera.rotateZ(60);
                ...
        }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

绕Z轴逆时针旋转60度 
注意:下面两行代码的意思是先将旋转中心移动到(0,0)点,因为Matrix总是用0,0点作为旋转点,旋转之后将视图放回原来的位置。

matrix.preTranslate(-getWidth()/2, -getHeight()/2); 
matrix.postTranslate(getWidth()/2, getHeight()/2);

API DEMOS中的例子,大家可以看下效果加深理解:

/**
 * An animation that rotates the view on the Y axis between two specified angles.

 * This animation also adds a translation on the Z axis (depth) to improve the effect.

 */

public class Rotate3dAnimation extends Animation {

 private final float mFromDegrees;

 private final float mToDegrees;

 private final float mCenterX;

 private final float mCenterY;

 private final float mDepthZ;

 private final boolean mReverse;

 private Camera mCamera;

 /**

 * Creates a new 3D rotation on the Y axis. The rotation is defined by its

 * start angle and its end angle. Both angles are in degrees. The rotation

 * is performed around a center point on the 2D space, definied by a pair

 * of X and Y coordinates, called centerX and centerY. When the animation

 * starts, a translation on the Z axis (depth) is performed. The length

 * of the translation can be specified, as well as whether the translation

 * should be reversed in time.

 *

 * @param fromDegrees the start angle of the 3D rotation

 * @param toDegrees the end angle of the 3D rotation

 * @param centerX the X center of the 3D rotation

 * @param centerY the Y center of the 3D rotation

 * @param reverse true if the translation should be reversed, false otherwise

 */

 public Rotate3dAnimation(float fromDegrees, float toDegrees,

 float centerX, float centerY, float depthZ, boolean reverse) {

 mFromDegrees = fromDegrees;

 mToDegrees = toDegrees;

 mCenterX = centerX;

 mCenterY = centerY;

 mDepthZ = depthZ;

 mReverse = reverse;

 }

 @Override

 public void initialize(int width, int height, int parentWidth, int parentHeight) {

     super.initialize(width, height, parentWidth, parentHeight);
     mCamera = new Camera();
 }

 @Override

 protected void applyTransformation(float interpolatedTime, Transformation t) {

 final float fromDegrees = mFromDegrees;

 float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

 final float centerX = mCenterX;

 final float centerY = mCenterY;

 final Camera camera = mCamera;

 final Matrix matrix = t.getMatrix();

 camera.save();

 if (mReverse) {
    camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
 } else {
    camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));

 }

 camera.rotateY(degrees);

 camera.getMatrix(matrix);

 camera.restore();

 matrix.preTranslate(-centerX, -centerY);

 matrix.postTranslate(centerX, centerY);

 }
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
iv.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                int width = getWindowManager().getDefaultDisplay().getWidth();
                int height = getWindowManager().getDefaultDisplay().getHeight();
                Rotate3dAnimation animation = new Rotate3dAnimation(0, 360, width/2, height/2,0, true);
                animation.setInterpolator(new AccelerateDecelerateInterpolator());
                animation.setDuration(2000);
                animation.setFillAfter(true);
                iv.startAnimation(animation);
            }
        });
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值