热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android变形(Transform)之Camera使用介绍

Camera主要实现3D的变形,有转动,旋转等,Camera的源码是由Native(本地代码)实现,提供的接口也比较简单,感兴趣的朋友可以参考下,或许对你学习有所帮助

引言

接Android变形(Transform)之Matrix,来总结下Camera的使用,Camera主要实现3D的变形,有转动,旋转等,Camera的源码是由Native(本地代码)实现,提供的接口也比较简单。官方的介绍:A camera instance can be used to compute 3D transformations and generate a matrix that can be applied, for instance, on a  Canvas.

效果图

原图:

 

变形以后:

 

API使用 

Camera提供的方法如下:

save:保存当前状态

restore:回复当前状态

translate:在x,y,z三位控件内进行平移 

rotateX:以(0.0)为中心,绕X轴进行选择

rotateY:以(0.0)为中心,绕Y轴进行选择

rotateZ:以(0.0)为中心,旋转(此处和Matrix旋转原理一样,只不过反向相反,为逆时针)

...

常用的就这么多

实践

直接上代码:

代码如下:

public class CameraTransformView extends View {

private Bitmap mBitmap;
private Camera mCamera;
private Matrix mMatrix;
private int deltaX, deltaY, deltaZ, extraZ;
private int centerX, centerY;

public CameraTransformView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public void setDrawable(int resId) {
mBitmap = BitmapFactory.decodeResource(getResources(), resId);
centerX = mBitmap.getWidth() / 2;
centerY = mBitmap.getHeight() / 2;
mCamera = new Camera();
mMatrix = new Matrix();
}

public void setDelta(int x, int y, int z, int extra) {
deltaX += x;
deltaY += y;
deltaZ += z;
extraZ += extra;
invalidate();
}

public void reset() {
deltaX = 0;
deltaY = 0;
deltaZ = 0;
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
mCamera.save();
mCamera.translate(10, 10, extraZ);
mCamera.rotateX(deltaX);
mCamera.rotateY(deltaY);
mCamera.rotateZ(deltaZ);
mCamera.getMatrix(mMatrix);
mCamera.restore();

mMatrix.preTranslate(-this.centerX, -this.centerY);
mMatrix.postTranslate(this.centerX, this.centerY);

canvas.drawBitmap(mBitmap, mMatrix, null);
super.onDraw(canvas);
}

}

其实Camera的变化就是封装了一个Matrix矩阵,可以通过getMatrix方法来获取这个坐标矩阵。在上面的Demo中就用到了该方法做些额外的处理,下面具体看看:
代码如下:

@Override
protected void onDraw(Canvas canvas) {
mCamera.save();
mCamera.translate(10, 10, extraZ);
mCamera.rotateX(deltaX);
mCamera.rotateY(deltaY);
mCamera.rotateZ(deltaZ);
mCamera.getMatrix(mMatrix);
mCamera.restore();

//mMatrix.preTranslate(-this.centerX, -this.centerY);
//mMatrix.postTranslate(this.centerX, this.centerY);

canvas.drawBitmap(mBitmap, mMatrix, null);
super.onDraw(canvas);
}

在onDraw方法中,可以通过Camera的方法来完成变形。注意11,12行,如果在onDraw的时候不进行俩行设置的话,可以看到效果如下:

可以看到,其按照Y轴旋转中心点是(0,0),那么平常的应用而言,大多希望其中心点在图片的中心点上。所以需要加入

代码如下:

mMatrix.preTranslate(-this.centerX, -this.centerY);
mMatrix.postTranslate(this.centerX, this.centerY);

其实这一节的重点就在于剖析这俩句话。

从Camara的API中可以看出来其不提供变形中心点的设置方法,那么怎么办呢,基本思路是:假设图片中心点为(centerX,centerY),既然Camera始终以(0,0)为中心点,那么我先将图形矩阵往左移动centerX,再往上移动centerY,让(centerX,centerY)正好掐在初始的(0,0)上,这样进行变形的话,中心点就变成了(centerX,centerY),达到了目的,当然这还没结束,你既然偏移了(-centerX,-centerY),那么变形以后得移回来,然后再往右下方分别移动centerX,centerY。

按照矩阵的变换,可以表达为:

1,0,-centerX                     1,0,centerX

0,1,-centerY  * 变形矩阵 *  0,1,centerY

0,0,1                               0,0,1

那么具体就如此,思路和代码结合起来怎么来解释呢,接着看,我们需要回顾下Matrix中的部分知识。

回顾

Matrix提供的三种变形方式为:set,post,pre。

set就是先reset,然后进行变形

pre可以解释为先乘,在矩阵原理中对应的右乘

post可以理解成后乘,在矩阵远离中对应左乘

不着急,接下俩具体看什么是先乘,后乘,什么是左乘,右乘。

举个例子:

原图

让一个图形按照中心点放大至2倍

那么期望的效果是:中心点不变(图片被边缘截断了)

那么按照之前提高的思路:假设中心点是(50,50)先左上移50,也即(-50,-50)再进行放大,再右下移50,也即(50,50)

api调用即为:setScale(2,2), preTranslate(-50,-50), postTranslate(50,50)

照例来说对应矩阵为:

1,0,-50       2,0,0       1,0,50        2,0,50

0,1,-50   *  0,0,2   *  0,1,50    =  0,2,50

0,0,1          0,0,1       0,0,1          0,0,1

可以看到结果是放大至2倍,但是却往右下移动了(50,50),奇怪要是这样的话,和预期的效果图一样预期的效果图矩阵应该为(方法至2倍,往左上移动(-50,-50))

2,0,-50

0,2,-50,

0,0,1

好,揭晓下疑点:

此处api的执行顺序为:preTranslate(-50,-50)  ->  setScale(2,2)  ->  postTranslate(50,50) 没有问题

答案揭晓:矩阵符合变化的原则,如果图形经过F1,F2...Fn此变形,对应矩阵为T1,T2...Tn,符合矩阵T = Tn*Tn-1...*T1

那么正确的矩阵算法应该为

1,0,50       2,0,0       1,0,-50        2,0,-50

0,1,50   *  0,0,2   *  0,1,-50    =  0,2,-50

0,0,1          0,0,1       0,0,1          0,0,1

此处也解释了pre为右乘,post为左乘的原理了。

那么到此为止,一切都都得到了解释。

回归

回归到Camera的Demo当中,既然Camera的变形中心点是(0,0),而且Camera的变形实际是对Matrix的变形,我们可以通过getMatrix方法来获取这个Matrix,然后通过左移pre,变形后右移post来实现中心点的设置。


推荐阅读
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 非公版RTX 3080显卡的革新与亮点
    本文深入探讨了图形显卡的进化历程,重点介绍了非公版RTX 3080显卡的技术特点和创新设计。 ... [详细]
  • 本文介绍如何在 Android 中通过代码模拟用户的点击和滑动操作,包括参数说明、事件生成及处理逻辑。详细解析了视图(View)对象、坐标偏移量以及不同类型的滑动方式。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • Søren Kierkegaard famously stated that life can only be understood in retrospect but must be lived moving forward. This perspective delves into the intricate relationship between our lived experiences and our reflections on them. ... [详细]
  • 计算机网络复习:第五章 网络层控制平面
    本文探讨了网络层的控制平面,包括转发和路由选择的基本原理。转发在数据平面上实现,通过配置路由器中的转发表完成;而路由选择则在控制平面上进行,涉及路由器中路由表的配置与更新。此外,文章还介绍了ICMP协议、两种控制平面的实现方法、路由选择算法及其分类等内容。 ... [详细]
  • 本文将介绍如何使用 Go 语言编写和运行一个简单的“Hello, World!”程序。内容涵盖开发环境配置、代码结构解析及执行步骤。 ... [详细]
  • 线性Kalman滤波器在多自由度车辆悬架主动控制中的应用研究
    本文探讨了线性Kalman滤波器(LKF)在不同自由度(2、4、7)的车辆悬架系统中进行主动控制的应用。通过详细的仿真分析,展示了LKF在提升悬架性能方面的潜力,并总结了调参过程中的关键要点。 ... [详细]
  • 本文探讨了Hive中内部表和外部表的区别及其在HDFS上的路径映射,详细解释了两者的创建、加载及删除操作,并提供了查看表详细信息的方法。通过对比这两种表类型,帮助读者理解如何更好地管理和保护数据。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 本文介绍如何利用动态规划算法解决经典的0-1背包问题。通过具体实例和代码实现,详细解释了在给定容量的背包中选择若干物品以最大化总价值的过程。 ... [详细]
  • 本文详细探讨了Java中的24种设计模式及其应用,并介绍了七大面向对象设计原则。通过创建型、结构型和行为型模式的分类,帮助开发者更好地理解和应用这些模式,提升代码质量和可维护性。 ... [详细]
author-avatar
钢铁猪991884679
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有