Android Camera图像处理学习

学习资料

  • GcsSloop 安卓自定义View进阶-Matrix Camera
  • 麻花儿wt的android camera 3d特效 详解与进阶

十分感谢GcsSloop,直接去看他的博客学习,图文并茂


Android中有2个Cameraandroid.hardware.Cameraandroid.graphics.Camera,看包名就可以区分出两个Camera的作用。hardware硬件,是摄像头;graphics,图像,用于图形处理。android.hardware.Camera5.0后被废弃,由android.hardware.Camera2代替,具体使用可以看看Android Camera2 拍照入门学习 : )


1. 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.

Camera对象可以用来计算3D变换,并将计算结果封装进一个Matrix矩阵,之后便进行应用(ps:我这都啥破翻译)

Camera可以用在画布上 。计算过程进行了封装,内部有一个Matrix

只有一个空的构造方法Camera()

Camera既然可以用来做3D三维变换,坐标系就和之前学习遇到的二维坐标系不同,是左手坐标系统,Y轴在三维坐标系中是向上的,Z轴是朝向屏幕里面的

Android Camera图像处理学习_第1张图片
3维左手坐标系

Z轴是朝里面的,屏幕像一个窗口,我们看到的是窗口外面的物体投射到窗口上的二维镜像。Camera实际上就像我们的眼睛,眼睛看到的是物体投射到窗口上的图形,其实这里就有3个要素,一是物体,二是窗子,三是眼睛,也就是物体,屏幕和Camera。最终呈现在用户面前的是屏幕上的图形。影响物体投射到屏幕上的效果,可以移动物体(Matrix),也可以移动眼睛(setLocation()方法)

以上从麻花儿wt的android camera 3d特效 详解与进阶摘抄


在一个虚拟的3D的立体空间中,由于我们无法直接用眼睛去观察这一个空间,所以要借助摄像机采集信息,制成2D影像供我们观察。简单来说,摄像机就是我们观察虚拟3D空间的眼睛。


Android 上面观察View的摄像机默认位置在屏幕左上角,而且是距屏幕有一段距离的,假设灰色部分是手机屏幕,白色是上面的一个View,摄像机位置看起来大致就是下面这样子的(为了更好的展示摄像机的位置,做了一个空间转换效果的动图)。

Android Camera图像处理学习_第2张图片
Camera位置

Camera默认距离为-8172像素,在坐标系中(0,0,-576)

以上从GcsSloop 安卓自定义View进阶-Matrix Camera摘抄


对于一个像素点的矩阵来说

Android Camera图像处理学习_第3张图片
一个像素点矩阵

1CameraZ轴的默认值,比1大,代表相对于默认位置,将屏幕进行拉远。远小近大,值越大就越远,投射到Camera上的图像也就也小


2. 方法

Camera中方法并不算多

Android Camera图像处理学习_第4张图片
原始图像

原始图像只是将Bitmap宽高缩小为1/2后,绘制在了画布上


2.1 translate(float x, float y, float z)

方法的名字和参数都比较容易理解,这个方法可以理解为移动了物体,但z这个值,会影响x,y的值。

例如mCamera.translate(100,0,100)x的值为100,但最终显示效果,图像右移的距离并没有100。z值导致图像缩放,移动距离也进行了缩放

Y轴是向上的,mCamera.translate(0,30,0)mMatrix.translate(0,-30)效果是一样的


2.2 rotate(float x, float y, float z)

这个方法是rotateX(float x),rotateY(float y),rotateZ(float z)的综合

以默认点左上角为中心绕值不为0的轴顺时针进行旋转

例如rotate(30,0,0),就是以左上角为中心,绕X轴顺时针旋转30°
x的值为角度,0°到360°


简单使用:

    /**
     * 初始化
     */
    private void init() {
        mCamera = new Camera();
        mMatrix = new Matrix();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test, options);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCamera.save();
        mCamera.rotate(180,0,0);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.postTranslate(0,500);
        canvas.drawBitmap(mBitmap,mMatrix, null);
    }
Android Camera图像处理学习_第5张图片
以控件左上角为旋转中心,绕x轴旋转180°

mMatrix.postTranslate(0,500),矩阵后乘,由于图片默认以左上角为旋转中心,绕着x轴旋转180°,图片已经超出了屏幕,使用后乘平移,将图片再移动到屏幕范围内。不可以setTanslate(),因为set方法会将原先的矩阵的值清空,成为初始矩阵

其他同理


2.3 setLocation(float x, float y, float z)

设置相机的位置,默认为-8

Android Camera图像处理学习_第6张图片
相机在默认位置,绕Y轴旋转30°

简单修改代码,修改相机的位置

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCamera.save();
        mCamera.setLocation(0,0,-30);//设置相机位置
        mCamera.rotate(0,30,0);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.postTranslate(0,500);
        canvas.drawBitmap(mBitmap,mMatrix, null);
    }
Android Camera图像处理学习_第7张图片
修改相机位置后

Y轴方向是向屏幕里的,所以-30-8要离物体远,这样旋转的最终效果就会减轻,根据生活经验,手机拍照时,手机距离拍摄物的远近,物体进行同样角度的改变,照片的效果并不完全一样。但Z轴的值并不会影响平移操作


3.结合动画,形成简单的3D效果

代码是从GcsSloop 安卓自定义View进阶-Matrix Camera学到,里面涉及到的优化原理讲的很好

矩阵值的影响

动画代码:

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     <------- 添加上下文,为获取像素密度准备
     * @param fromDegrees 起始时角度
     * @param toDegrees   结束时角度
     * @param centerX     旋转中心x坐标
     * @param centerY     旋转中心y坐标
     * @param depthZ      最远到达的z轴坐标
     * @param reverse     true 表示由从0到depthZ,false相反
     */
    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;
        // 像素密度
        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);
    }
}

Activity代码:

public class CameraGActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_g);
        initView();
    }

    private void initView() {
        ImageView iv = (ImageView) findViewById(R.id.iv_camera_g_activity);
        iv.setImageResource(R.drawable.test);
        iv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 计算中心点(这里是使用view的中心作为旋转的中心点)
                final float centerX = v.getWidth() / 2.0f;
                final float centerY = v.getHeight() / 2.0f;

                //括号内参数分别为(上下文,开始角度,结束角度,x轴中心点,y轴中心点,深度,是否扭曲)
                final Rotate3DAnimation rotation = new Rotate3DAnimation(CameraGActivity.this, 0, 360, centerX, centerY, 0f, true);
                rotation.setDuration(3000);
                rotation.setFillAfter(true);
                rotation.setInterpolator(new LinearInterpolator());
                v.startAnimation(rotation);
            }
        });
    }
}

围绕图片中心旋转

优化就是修正失真,主要修改 MPERSP_0MPERSP_1


4. 最后

本篇内容的学习,是最近学习过程中,效率最低的,Camera与物体,屏幕三者的关系没有搞清楚,一开始搜到的学习博客,感觉有错误,质量不是很高。

强烈推荐学习GcsSloop的系列博客,感觉质量都很高,真正的图文并茂

本人很菜,写的很水,有错误请指出

共勉 : )

你可能感兴趣的:(Android Camera图像处理学习)