文档章节

Android Camera&Matrix图像变换

IamOkay
 IamOkay
发布于 04/04 15:11
字数 2037
阅读 88
收藏 3

Camera与Matrix

Android UI系统中,Camera充当着相机的角色,无论是系统成像还是UI绘制。都离不开Camera。但是在Android系统中,存在两种Camera,一种是视觉成像的(拍照、摄像),另一种是图形绘制(游戏、地图、3D),实际上两种也都离不开Matrix,所以本质上可以理解为,一个负责对相机以外的物体成像,一个负责Android View的成像。这里我们重点来介绍系统UI成像的Camera。

        UI成像需要使用到画布和坐标系。在Android系统中,View最终以二维方式显示,但是Camera是三维成像,遇到这种问题,我们这里需要用到Matrix了,它用来将三维转为二维。原理是Matrix矩阵将Camera的投影转到Canvas上,因此我们就能看见3D图形显示在二维坐标系中了。

关于Matrix请参阅:

android matrix 最全方法详解与进阶(完整篇)

Android中利用Camera与Matrix实现3D效果详解

 

 

Camera坐标系与Android坐标系

  camera的坐标系是左手坐标系。伸出左手,让拇指和食指成L形,大拇指向右,食指向上,中指指向前方,这样我们就建立了一个左手坐标系,拇指,食指,中指的指向分别代表了x,y,z轴的正方向。如下图所示:

下面是一些细节点:

1,camera位于坐标点(0,0),也就是视图的左上角;

2,camera.translate(10, 20, 30)的意思是把观察物体右移10,上移20,向前移30(即让物体远离camera,这样物体将会变小);
3,camera.rotateX(45)的意思是绕x轴顺时针旋转45度。举例来说,如果物体中间线和x轴重合的话,绕x轴顺时针旋转45度就是指物体上半部分向里翻转,下半部分向外翻转;
4,camera.rotateY(45)的意思是绕y轴顺时针旋转45度。举例来说,如果物体中间线和y轴重合的话,绕y轴顺时针旋转45度就是指物体右半部分向里翻转,左半部分向外翻转;
5,camera.rotateZ(45)的意思是绕z轴顺时针旋转45度。举例来说,如果物体中间线和z轴重合的话,绕z轴顺时针旋转45度就是指物体上半部分向左翻转,下半部分向右翻转;

 

Android坐标系是二维的

1,camera位于坐标点(0,0),也就是视图的左上角;

2,垂直向下为y轴正方向

3、垂直向右为x轴正方向

 

两类坐标系比较

 

Camera与Matrix API

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

  • applyToCanvas(Canvas canvas) 根据当前的变换计算出相应的矩阵,然后应用到制定的画布上
  • getLocationX() 获取Camera的x坐标
  • getLocationY() 获取Camera的y坐标
  • getLocationZ() 获取Camera的z坐标
  • getMatrix(Matrixmatrix) 获取转换效果后的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相关方法如下

  • setTranslate(floatdx,floatdy):控制Matrix进行平移
  • setSkew(floatkx,floatky,floatpx,floatpy):控制Matrix以px,py为轴心进行倾斜,kx,ky为X,Y方向上的倾斜距离
  • setRotate(floatdegress):控制Matrix进行旋转,degress控制旋转的角度
  • setRorate(floatdegress,floatpx,floatpy):设置以px,py为轴心进行旋转,degress控制旋转角度
  • setScale(floatsx,floatsy):设置Matrix进行缩放,sx,sy控制X,Y方向上的缩放比例
  • setScale(floatsx,floatsy,floatpx,floatpy):设置Matrix以px,py为轴心进行缩放,sx,sy控制X,Y方向上的缩放比例

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

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


pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。

 

导演与摄像机

在3D摄影中,导演控制镜头位置来呈现不同的效果,摄像机在空间的不同位置展现出来的效果是不同的。由于我们无法直接用眼睛去观察这一个空间,所以要借助摄像机采集信息,制成2D影像供我们观察。简单来说,摄像机就是我们观察虚拟3D空间的眼睛,而我们既是导演又是观众。我们在电视上看到的都是三维投影。

注意:摄像机的位置默认是 (0, 0, -576)

三维投影

三维投影是将三维空间中的点映射到二维平面上的方法。由于目前绝大多数图形数据的显示方式仍是二维的,因此三维投影的应用相当广泛,尤其是在计算机图形学,工程学和工程制图中。

三维投影一般有两种,正交投影 和 透视投影

正交投影就是我们数学上学过的 “正视图、正视图、侧视图、俯视图” 这些东西。

透视投影则更像拍照片,符合近大远小的关系,有立体感,我们此处使用的就是透视投影。

 

实战

简单示例

原始图 转换图

第二张图实际上是摄像机分别向x,y,z移动了(这种效果的转变,我们可以假定在View原图已经绘制完成的情况下,拿一个相机去拍摄,然后再次将投影通过Materix转到Canvas上)

代码如下:

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) {
        matrix.reset();
        camera.save();
        camera.translate(10, 50, -180);
        camera.getMatrix(matrix);
        camera.restore();
        canvas.concat(matrix);
        
        canvas.drawCircle(60, 60, 60, paint);
    }

}

 

3D旋转动画示例

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;
    float scale = 1;    // 

    /**
     * 创建一个绕y轴旋转的3D动画效果,旋转过程中具有深度调节,可以指定旋转中心。
     * @param context     
    public Rotate3dAnimation(Context context, float fromDegrees, float toDegrees,
                             float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;

        // 获取手机像素密度 (即dp与px的比例)
        scale = context.getResources().getDisplayMetrics().density;
    }

    @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));
        }

        // 绕y轴旋转
        camera.rotateY(degrees);

        camera.getMatrix(matrix);
        camera.restore();

        // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
        float[] mValues = new float[9];
        matrix.getValues(mValues);			    //获取数值
        mValues[6] = mValues[6]/scale;			//数值修正
      	mValues[7] = mValues[7]/scale;			//数值修正
        matrix.setValues(mValues);			    //重新赋值

        // 调节中心点
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

 

当然,以上的实现方式较复杂,我们可以使用Animation或者Animator来实现,通过rotationY动画。

 final float targetVal = 180f;
            final int width = v.getMeasuredWidth();
            v.setPivotX(width/2);
            v.clearAnimation();
            final Drawable  before= getResources().getDrawable(R.mipmap.img_cake);
            final Drawable  after = getResources().getDrawable(R.mipmap.img_heart);
            Animator animator = ObjectAnimator.ofFloat(v,"rotationY",targetVal,360);
            animator.setDuration(1000);
            v.setRotationY(180f);
            v.setBackground(before);
            final float distance = v.getCameraDistance();  //获取相机距离

            ((ValueAnimator)animator).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    float fraction = animation.getAnimatedFraction();

                    if(Math.abs(360+180)/2<=Math.abs(value)){
                        v.setBackground(after);
                    }
                    float f = (float) Math.abs(Math.sin(Math.toRadians(fraction * targetVal)));
                    Log.i("Animator","value="+value +" ,fraction="+fraction+", f="+f);
                    v.setCameraDistance(distance + f*(distance*width)/2);
                }
            });

            animator.start();
        }

 

摄像机要求 由近到远,然后由远到近,这里我们通过三角函数sin来实现

float f = (float) Math.abs(Math.sin(Math.toRadians(fraction * targetVal)));

 

© 著作权归作者所有

共有 人打赏支持
IamOkay
粉丝 187
博文 459
码字总数 372015
作品 0
海淀
程序员
Matrix, ColorMatrix

作为Android源码中的一个常用类,它的作用是持有一个3*3的矩阵数组,用于坐标的转换。 Matrix用来制作动画效果、改变图片大小、给图片加各类滤镜等。 Matrix 的应用 - 压缩图像;Matrix 的应...

shareus
04/13
0
0
Android 平滑和立体翻页效果1

Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述 Android 的动画框架是如何实现的。任何一个框架都有其优势和局限性,只有明白了其实现原理...

紫地瓜
2012/10/25
0
4
Android中图像变换Matrix的原理、代码验证和应用

第一部分 Matrix的数学原理 在Android中,如果你用Matrix进行过图像处理,那么一定知道Matrix这个类。Android中的Matrix是一个3 x 3的矩阵,其内容如下: Matrix的对图像的处理可分为四类基本...

蜗牛TT
2012/08/23
0
3
Android 开源框架Glide的使用

是一个快速高效的多媒体管理和图像加载的框架,封装了平台的多媒体的解码,内存和硬盘缓存等,支持解码、显示视频、图像和GIFs,Glide是基于定制的下面是关于Glide的配置和使用。 Glide的配置...

记录自己的点点滴滴
08/06
0
0
Android--Matrix图片变换处理

前言   本篇博客主要讲解一下如何处理对一个Bitmap对象进行处理,包括:缩放、旋转、位移、倾斜等。在最后将以一个简单的Demo来演示图片特效的变换。   本篇博客的主要内容: Matrix Mat...

天天慕白
07/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS7防火墙firewalld操作

firewalld Linux上新用的防火墙软件,跟iptables差不多的工具。 firewall-cmd 是 firewalld 的字符界面管理工具,firewalld是CentOS7的一大特性,最大的好处有两个:支持动态更新,不用重启服...

dingdayu
今天
1
0
关于组件化的最初步

一个工程可能会有多个版本,有国际版、国内版、还有针对各种不同的渠道化的打包版本、这个属于我们日常经常见到的打包差异化版本需求。 而对于工程的开发,比如以前的公司,分成了有三大块业...

DannyCoder
今天
2
0
Spring的Resttemplate发送带header的post请求

private HttpHeaders getJsonHeader() { HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8"); ......

qiang123
昨天
3
0
Spring Cloud Gateway 之 Only one connection receive subscriber allowed

都说Spring Cloud Gateway好,我也来试试,可是配置了总是报下面这个错误: java.lang.IllegalStateException: Only one connection receive subscriber allowed. 困扰了我几天的问题,原来...

ThinkGem
昨天
27
0
学习设计模式——观察者模式

1. 认识观察者模式 1. 定义:定义对象之间一种一对多的依赖关系,当一个对象状态发生变化时,依赖该对象的其他对象都会得到通知并进行相应的变化。 2. 组织结构: Subject:目标对象类,会被...

江左煤郎
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部