精华内容
下载资源
问答
  • Android相机开发

    热门讨论 2013-11-22 11:27:27
    Android相机开发,包括调用系统相机APP拍照、拍摄视频,和自定义相机拍照、拍摄视频。
  • android开发APP实现照相机功能

    千次阅读 2018-05-28 14:19:20
    Android SDK 中提供的面向硬件的特性特性描述android.hardware.Camera相机交互的类,可以截取照片、获取预览屏幕的图像,修改照相机操作的参数。android.hardware.SensorManager允许访问 Android 平台传感器的类。...


    Android SDK 中提供的面向硬件的特性

    特性

    描述

    android.hardware.Camera

    相机交互的类,可以截取照片、获取预览屏幕的图像,修改照相机操作的参数。

    android.hardware.SensorManager

    允许访问 Android 平台传感器的类。并非所有配备 Android 的设备都支持 SensorManager 中的所有传感器。

    android.hardware.SensorListener

    在传感器值实时更改时,希望接收更新的类要实现的接口。用以监视硬件中一个或多个可用传感器。

    android.media.MediaRecorder

    用于录制媒体的类。

    android.FaceDetector

    人脸进行基本识别类。

    android.os.*

    可以与操作环境交互的包,包括电源管理、文件查看器、处理器和消息类。

      android.hardware.SensorManager 包含几个常量,这表示 Android 传感器系统的不同方面,包括:

    传感器类型:方向、加速表、光线、磁场、临近性、温度等。采样率最快、游戏、普通、用户界面。

    当应用程序请求特定的采样率时,其实只是对传感器子系统的一个提示,或者一个建议。不保证特定的采样率可用。准确性高、低、中、不可靠。

      SensorListener 接口是传感器应用程序的中心。它包括两个必需方法:

    onSensorChanged(int sensor,float values[]) 方法在传感器值更改时调用。该方法只对受此应用程序监视的传感器调用。该方法

     

    相机拍摄:

    package com.android.cameraAndroid;

     

    import android.app.Activity;

    import android.os.Bundle;

     

    import java.io.File;

    import java.io.FileOutputStream;

    import java.io.IOException;

     

    import android.content.Context;

    import android.content.Intent;

    import android.graphics.PixelFormat;

    import android.hardware.Camera;

    import android.hardware.Camera.Parameters;

    import android.hardware.Camera.PictureCallback;

    import android.hardware.Camera.ShutterCallback;

    import android.media.AudioManager;

    import android.media.ToneGenerator;

    import android.net.Uri;

    import android.os.Environment;

    import android.os.StatFs;

    import android.view.Menu;

    import android.view.MenuItem;

    import android.view.SurfaceHolder;

    import android.view.SurfaceView;

     

    public class CameraAndroid extends Activity {

     

    private CameraPreview preview;

    private Camera camera;

    private ToneGenerator tone;

    private static final int OPTION_SNAPSHOT = 0;

     

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    preview = new CameraPreview(this);

    setContentView(preview);

    }

     

    @Override

    public boolean onOptionsItemSelected(MenuItem item) {

    int itemId = item.getItemId();

    switch(itemId){

    case OPTION_SNAPSHOT:

    //拍摄照片

    camera.takePicture(shutterCallback, null, jpegCallback);

    break;

    }

    return true;

    }

    //返回照片的JPEG格式的数据

    private PictureCallback jpegCallback = new PictureCallback(){

     

    public void onPictureTaken(byte[] data, Camera camera) {

    Parameters ps = camera.getParameters();

    if(ps.getPictureFormat() == PixelFormat.JPEG){

        //存储拍照获得的图片

        String path = save(data);

        //将图片交给Image程序处理

        Uri uri = Uri.fromFile(new File(path));

            Intent intent = new Intent();

            intent.setAction("android.intent.action.VIEW");

            intent.setDataAndType(uri, "image/jpeg");

            startActivity(intent);

    }

    }

    };

    //快门按下的时候onShutter()被回调

    private ShutterCallback shutterCallback = new ShutterCallback(){

    public void onShutter() {

    if(tone == null)

    //发出提示用户的声音

    tone = new ToneGenerator(AudioManager.STREAM_MUSIC,

    ToneGenerator.MAX_VOLUME);

    tone.startTone(ToneGenerator.TONE_PROP_BEEP2);

    }

    };

    private String save(byte[] data){

    String path = "/sdcard/"+System.currentTimeMillis()+".jpg";

    try {

    //判断SD卡上是否有足够的空间

    String storage = Environment.getExternalStorageDirectory().toString();

    StatFs fs = new StatFs(storage);

    long available = fs.getAvailableBlocks()*fs.getBlockSize();

    if(available<data.length){

    //空间不足直接返回空

    return null;

    }

    File file = new File(path);

    if(!file.exists())

    //创建文件

    file.createNewFile();

    FileOutputStream fos = new FileOutputStream(file);

    fos.write(data);

    fos.close();

    } catch (Exception e) {

    e.printStackTrace();

    return null;

    }

    return path;

    }

     

    @Override

    public boolean onCreateOptionsMenu(Menu menu) {

    menu.add(0, OPTION_SNAPSHOT, 0, R.string.snapshot);

    return super.onCreateOptionsMenu(menu);

    }

     

    class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    SurfaceHolder mHolder;

     

    public CameraPreview(Context context) {

    super(context);

    mHolder = getHolder();

    mHolder.addCallback(this);

    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    //Sureface创建的时候,此方法被调用

    public void surfaceCreated(SurfaceHolder holder) {

    //打开摄像头,获得Camera对象

    camera = Camera.open();

    try {

    //设置显示

    camera.setPreviewDisplay(holder);

    } catch (IOException exception) {

    camera.release();

    camera = null;

    }

    }

     

    //Surface销毁的时候,此方法被调用

    public void surfaceDestroyed(SurfaceHolder holder) {

    camera.stopPreview();

    //释放Camera

    camera.release();

    camera = null;

    }

     

    public void surfaceChanged(SurfaceHolder holder, int format, int w,

    int h) {

    //已经获得Surfacewidthheight,设置Camera的参数

    Camera.Parameters parameters = camera.getParameters();

    parameters.setPreviewSize(w, h);

    camera.setParameters(parameters);

    //开始预览

    camera.startPreview();

    }

    }

    }

    展开全文
  • 上一篇博客,我简单的介绍了一下使用Camera录制视频的方法,回过细细琢磨,我好像跳过了使用相机拍照。因此,本文主要针对没有做过Camera开发的初学者,会讲的非常的细,因此大神们可以直接无视~哈哈哈 一、前言 ...

    上一篇博客,我简单的介绍了一下使用Camera录制视频的方法,回过细细琢磨,我好像跳过了使用相机拍照。因此,本文主要针对没有做过Camera开发的初学者,会讲的非常的细,因此大神们可以直接无视~哈哈哈


    一、前言

    首先,和录制视频一样,我们需要向系统申请使用权限,有需要的可能需要往系统中保存所拍到的图片。因此,我们常需要申请一下三种权限:

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    当然,很多朋友会在很多大神的博客中看到添加了
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    事实上,uses-permission 同 user-feature在某种程度上,都可以像系统申请使用的权限,但是他们侧重的方向并不相同:

    uses-permission 仅仅是向你的手机申请权限,也就是申请使用该功能的权限;

    user-feature 是用于确保你的手机有该功能的支持。

    当然,针对于现在手机的Camera的开发来讲,这两个基本是没有什么区别的。


    二、使用Camera

    使用Camera可以分为两种方式来做,一种就是直接使用Intent调用系统的Camera,使用系统的相机进行拍照,另外一种就是调用系统的Camera,嵌入到自己的App中使用。本文仅针对第二种方式进行详细的讲解。


    三、布局

    与视频拍摄类似,我们在布局中需要使用SurfaceView作为相机的预览显示器,并且我们需要有一个控件来控制拍照操作,因此我仅仅是简单的写了两个主要控件来实现相应的方法:

    <?xml version="1.0" encoding="utf-8"?>
    <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"
        tools:context="seeunsee.cameratext.MainActivity">
    
        <SurfaceView
            android:id="@+id/camera"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <ImageView
            android:id="@+id/iv_takepic"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="8dp"
            android:src="@drawable/takepicture" />
    
    </RelativeLayout>
    

    四、初步使用

    有了以上的准备工作,我们就可以开始着手Camera的开发了。那么我们就先实现一个相机预览的功能:

    private void init() {
            sfv = (SurfaceView) findViewById(R.id.camera);
            ivTakePic = (ImageView) findViewById(R.id.iv_takepic);
            sfh = sfv.getHolder();
            // 实测不带这个参数也可以有效果,不过网上的资料显示,增加这个变量,可以使得预览的图像更流畅
            sfh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            sfh.addCallback(this);
        }
    
    private void cameraCreate() {
            if (camera != null) {
                return;
            }
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); // 使用后置摄像头
            try {
                camera.setPreviewDisplay(sfh);
                camera.startPreview();
            } catch (IOException e) {
                camera.release();
            }
        }

    其中,cameraCreate函数需要放在SurfaceHolder.Callback中,你可以选择放在surfaceCreated或者surfaceChanged中。区别在于surfaceCreated仅会在SurfaceView创建的时候被调用,而surfaceChanged无论如何都会在至少在surfaceCreated之后调用一次,且每次surfaceView发生改变的时候,都会再次调用。对于我而言,我更喜欢写在changed中,不过,如果你喜欢两个地方都写上,其实也不会有什么问题。

    当然,为了保证其他进程使用Camera,我们最好是在surfaceview销毁的时候,将Camera重置:

    @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }

    OK,就让我们运行一下程序看看会有怎么样的结果


    五、优化

    阿嘞,我手机明明是竖着的,为啥预览的图像却是逆时针旋转了90度呢?不要急,你先把手机调整到水平模式来看看会有什么结果吧~

    很明显,当我们把手机界面变成水平模式的时候,预览图像显示的角度就和我们所看的角度是一致的了。因此,我们可以得到系统相机的预览规律,当手机处于竖屏状态时,相机预览图像与实际图像呈90度角;当手机处于横屏状态时,相机预览图像与实际图像一致,因此,我们需要对这两种情况分别处理。

    因此我们需要采用预览图像的旋转方法,将相机预览图像进行旋转。

    当然,我们前文说过,我们只有在竖屏模式下才需要旋转预览图像,因此这里我们有两个可选的解决方式:

    1:采用大部分相机App的方式,强行让应用处于垂直状态,在onCreate中添加

    // 强行限制屏幕为纵向
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    然后cameraCreate()中对camera进行角度的设置

    camera.setDisplayOrientation(90);

    2:对屏幕的方向进行判断,根据不同的方向,对Camera预览的旋转角度进行设置:

    if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
                    // 如果手机屏幕处于垂直模式
    		camera.setDisplayOrientation(90);
    	} else { 
    		// 如果手机屏幕处于水平模式 
    		camera.setDisplayOrientation(0); 
    	}	

    OK,在运行一次,我们就会发现这回显示就完全正常了,但是细心的童鞋肯定会发现,为什么预览效果这么模糊呢?了解相机功能的童鞋肯定知道,这是因为相机对焦不正确导致的结果,那问题又来了,我们怎么才能设置相机对焦呢?
    在解决这个问题,我们需要引入一个新的类Camera.Parameters。


    六、Camera.Parameters类简介
    Camera.Parameters类,主要是概述相机的服务设置,包括对相机预览图像的设置,以及获得拍照结果的设置。
    与大部分创建对象方式不同,Parameters对象的创建方式为:

    Camera.Parameters parameters = camera.getParameters();
    其中camera 为我们创建的Camera对象。
    在编译器中,我们使用Parameters,我们可以发现编译器给我们提供了很多不同的方法,所以下面我们先来了解一下常用的几个Parameters方法:

    parameters.setPreviewSize(int width, int height); // 设置摄像预览的分辨率
    parameters.setPictureSize(int width, int height); // 设置拍摄照片的分辨率
    parameters.setRotation(int rotation); // 设置获得照片的旋转角度
    parameters.setPictureFormat(int pixel_format); // 设置图片格式
    parameters.setPreviewFpsRange(int min, int max); // 设置最小和最大的预览帧数
    
    parameters.setFocusMode(String value); // 设置聚焦模式
    // 常量有如下几种:
    // FOCUS_MODE_AUTO 自动对焦模式
    // FOCUS_MODE_CONTINUOUS_PICTURE 用于拍照的连续自动对焦模式
    // FOCUS_MODE_CONTINUOUS_VIDEO 用于视频录制的连续自动对焦模式 
    // FOCUS_MODE_EDOF 扩展景深(EDOF)
    // FOCUS_MODE_FIXED 固定焦点
    // FOCUS_MODE_INFINITY 焦点在无限远处
    // FOCUS_MODE_MACRO 微距(特写)对焦模式
    
    parameters.setWhiteBalance(String value); // 设置白平衡模式
    // 常量有如下几种:
    // WHITE_BALANCE_AUTO 自动模式
    // WHITE_BALANCE_CLOUDY_DAYLIGHT 多云
    // WHITE_BALANCE_DAYLIGHT 白天
    // WHITE_BALANCE_FLUORESCENT 荧光灯下
    // WHITE_BALANCE_INCANDESCENT 白炽灯下
    // WHITE_BALANCE_SHADE 阴暗
    // WHITE_BALANCE_TWILIGHT 黄昏
    // WHITE_BALANCE_WARM_FLUORESCENT 温柔的日光下
    
    parameters.setSceneMode(String value); // 设置场景模式(这个有点多-.-,有兴趣的童鞋可以去开发者网站看一下)
    // 网址:https://developer.android.google.cn/reference/android/hardware/Camera.Parameters.html#SCENE_MODE_AUTO


    七、优化(二)
    大致的对Parameters有所了解,那么我们就可以继续优化我们的相机。
    我们在camereCreate中调用parameters.getFocusMode(),发现返回值为auto,因此我们知道,在我们没有对相机进行设置的时候,相机的聚焦模式为自动对焦模式,然而从这里我们可以看出,这个自动对焦,实际上并没有说那么自动智能,完全无法达到我们对相片清晰度的要求,因此我们需要对相机的对焦模式进行修改。我在这里使用的是
    FOCUS_MODE_CONTINUOUS_PICTURE
    有兴趣的童鞋们也可以试试其他的对焦方式哦!


    八、Android 6.0系统
    写到这里,很多童鞋肯定会深感疑惑,为毛作者写的津津乐道,我一运行就会闪退呢!
    这里我建议大家先看一下自己的手机系统,如果你是Android 6.0的系统,那么恭喜你,这段代码一定是会导致程序闪退的。为什么?因为Android 6.0 Google大大加入了运行时权限功能,并将几百种权限区分为普通权限、危险权限两种。如果你的开发涉及到危险权限,对于这部分权限的申请,必须要由用户手动点击授权才可以(至于具体的讲解,可以参考一下郭霖大神的第二行代码哦)。
    因此,如果你的手机是Android6.0及其以上,你可以在oncreate()方法中,添加

    // 6.0及其以上系统的手机,需要动态的申请权限,否则App会发生闪退现象
    // 并且针对于6.0以下的手机来说,并没有什么改变
    // 在这里,一旦点击拒绝,就直接会导致程序的闪退
    // 因此,处理权限问题,应该放置在其他页面中进行,根据用户的选择进行跳转
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    动态的申请权限就可以了哦


    如果,还有遇到什么以上没有涉及到的问题,也可以留言给我哦~


    写到这里,我们就已经完成了对相机预览的简单编写,我们可以通过相机预览到方向正确、清晰的预览图像,那么下一篇,我将带大家走进拍照的深坑 偷笑



    展开全文
  • 从零开始开发Android相机app(三)简单介绍图像滤镜功能 文章目录 1. 前期基础知识详解 2.滤镜效果如何实现分析 3.我们来实现静态的滤镜实现吧 4.GPUImage API调用: 5.最后叨一叨: 6.下面附上一些常用的滤镜 ...

    目前章节

    1.从零开始安卓端相机功能开发(一)了解用什么去开发以及流程
    2.从零开始安卓端相机功能开发(二)让我们来开发一个相机
    3.从零开始开发Android相机app(三)简单介绍图像滤镜功能

    源码地址:https://github.com/307572384/GPItest/commit/a89a605cec14bd573cd90994c973cfdd00f97991?diff=unified

    1. 前期基础知识详解

    滤镜;主要是用来实现图像的各种特殊效果。它在Photoshop中具有非常神奇的作用。所有的滤镜在Photoshop中都按分类放置在菜单中,使用时只需要从该菜单中执行这命令即可。滤镜的操作是非常简单的,但是真正用起来却很难恰到好处。滤镜通常需要同通道、图层等联合使用,才能取得最佳艺术效果。如果想在最适当的时候应用滤镜到最适当的位置,除了平常的美术功底之外,还需要用户对滤镜的熟悉和操控能力,甚至需要具有很丰富的想象力。这样,才能有的放矢的应用滤镜,发挥出艺术才华。

    以上来源于百度百科,当然我们的Android相机开发的图像滤镜也不是那么简单的需要自己有一些动手能力和一定的英语阅读水平和数学能力才能够熟悉的一些东西,这里我个人建议要想变得更强英语和数学这两个要变得非常强才可以,毕竟有些外国文章写得非常不错可以用来参考,但是翻译却很少所以得提高自己的能力才行。这个是我这几天的学习感受。

    2.滤镜效果如何实现分析

    首先我们写滤镜效果可以使用现成的如GPUImage或者是其他的现成付费SDK也可以自己写当然这种的话就比较麻烦涉及到算法之类的,我个人比较推荐GPUImage这一款开源项目。

    GPUImage 是iOS下一个开源的基于GPU的图像处理库,提供各种各样的图像处理滤镜,并且支持照相机和摄像机的实时滤镜。GPUImage for Android是它在Android下的实现,同样也是开源的。其中提供了几十多种常见的图片滤镜API,且其机制是基于GPU渲染,处理速度相应也比较快,是一个不错的图片实时处理框架。
    而且现在还在更新状态中。
    需要的可以去看看GPUImageGithub开源项目

    滤镜处理对象:通常分为两类:1.静态图片;2.实时相机预览;3.视频添加滤镜;

    实现方式有多种,比如通过调用Android系统提供的图像处理API,可以设置图片的色调、饱和度、亮度,也可以调用ColorMatrix进行更加精确的图片色彩调控,还可以使用更加精细化的像素处理方式—提取图片像素点,然后对每个像素点进行处理,使图片变换不同的色彩效果,以上的方式都是调用Android系统提供的API进行处理,难点在于图像处理算法的研究,这也是专业图像处理人员的工作之一,尝试不同色彩矩阵的配合,可以创建出不同的色彩效果。

    GPUImage是iOS的一个开源库,后来也有了Android的版本,可以实现五十多种的滤镜效果,不用开发者自己进行滤镜算法的实现,处理起来更加的方便,而且GPUImage可以做到的不仅仅是像ColorMatrix一样的色彩特效,还可以进一步实现美颜相机需要的其他特效,比如磨皮,美白等,功能会更加强大。

    3.我们来实现静态的滤镜实现吧

    环境搭建

    首先,要使用这个库自然是要先导入依赖,在app的gradle文件中添加:

    repositories {
          google()
        jcenter()
        
    }
    
    dependencies {
        compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1'
    }
    

    至于怎么创建Assets文件我们就使用这个
    Android图像滤镜框架GPUImage从配置到应用
    在这里插入图片描述
    在这里插入图片描述
    然后里面的素材图片大家可以随便写一个然后导入进去。

    4.GPUImage API调用:

    GPUImage主要通过一个GPUImageFilter类来提供各种滤镜效果实现类,比如我们来实现一个将图片变成的鱼眼的滤镜:

    “GPUImageBulgeDistortionFilter” 【凸起失真,鱼眼效果】这个是我们需要实现的效果。

    我们来看一下鱼眼效果

    鱼眼效果

    这里是静态滤镜的MainActivity里面有滤镜的主要功能:包括滤镜显示到屏幕上和拖拉调整图片饱和度的功能
    务必在AndroidManifest中先添加联网权限

       <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    
    import android.content.Intent;
    import android.content.res.AssetManager;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.media.Image;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.SeekBar;
    
    import junit.framework.Assert;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    import jp.co.cyberagent.android.gpuimage.GPUImage;
    import jp.co.cyberagent.android.gpuimage.GPUImageBulgeDistortionFilter;
    import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter;
    import jp.co.cyberagent.android.gpuimage.GPUImageSaturationFilter;
    
    public class MainActivity extends AppCompatActivity {
    	private GPUImage gpuImage;
    	//显示处理结果
    	private ImageView resultIv;
    	//进度条
    	private SeekBar seekBar;
    	private Button bt_net;//点击跳转到图片网络滤镜转换
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    
    		resultIv = (ImageView)findViewById(R.id.resultIv);
    		bt_net=(Button)findViewById(R.id.button) ;
    		seekBar = (SeekBar)this.findViewById(R.id.seekbar);
    		seekBar.setMax(10);
    		seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    			@Override
    			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    				//通过进度条的值更改饱和度
    				resultIv.setImageBitmap(getGPUImageFromAssets(progress));
    			}
    
    			@Override
    			public void onStartTrackingTouch(SeekBar seekBar) {
    
    			}
    
    			@Override
    			public void onStopTrackingTouch(SeekBar seekBar) {
    
    			}
    		});
    		//初始化图片
    		resultIv.setImageBitmap(getGPUImageFromAssets(0));
    		bt_net.setOnClickListener(new View.OnClickListener() {
    			@Override
    			public void onClick(View v) {
    				Intent intent = new Intent(MainActivity.this,NetActivity.class);
    				startActivity(intent);
    
    			}
    		});
    	}
    
    	//根据传进来的数值设置素材饱和度
    	public Bitmap getGPUImageFromAssets(int progress)
    	{
    		//获得Assets资源文件
    		AssetManager as = getAssets();
    		InputStream is = null;
    		Bitmap bitmap = null;
    		try{
    			is = as.open("link.jpg");
    			bitmap = BitmapFactory.decodeStream(is);
    			is.close();
    		}catch (IOException e)
    		{
    			Log.e("GPUImage","Error");
    		}
    		gpuImage = new GPUImage(this);
    		gpuImage.setImage(bitmap);
    		gpuImage.setFilter(new GPUImageBulgeDistortionFilter());
    		bitmap = gpuImage.getBitmapWithFilterApplied();
    		//显示处理图片后的照片
    		return bitmap;
    	}
    
    }
    
    

    PS:这里注意一下有些滤镜功能是没有饱和度如鱼眼功能
    这里是MainActivity的activity_layout布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.beta.gpitest.MainActivity">
    
        <ImageView
            android:id="@+id/resultIv"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_gravity="center_vertical"
            android:layout_marginBottom="23dp"
            android:layout_marginTop="10dp"
            app:layout_constraintBottom_toTopOf="@+id/button"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <SeekBar
            android:id="@+id/seekbar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="93dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="30dp"
            android:text="跳转到网络图片滤镜效果"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/resultIv" />
    
        <Button
            android:id="@+id/setting"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="2dp"
            android:text="setting"
            app:layout_constraintBaseline_toBaselineOf="@+id/button"
            app:layout_constraintEnd_toEndOf="parent" />
    
    </android.support.constraint.ConstraintLayout>
    
    

    如果我们需要联网进行滤镜效果的话,由于访问网络图片,所以需要放在子线程中进行,所以这里通过AsynTask(Android异步线程,不清楚的可以看下这篇文章AsynTask使用简介),现在子线程请求完网络图片并转换为Bitmap传递给主线程中对图片进行滤镜处理并显示出来。

    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.ImageView;
    
    import java.io.BufferedInputStream;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.URLConnection;
    
    import jp.co.cyberagent.android.gpuimage.GPUImage;
    import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter;
    
    
    public class NetActivity  extends AppCompatActivity {
    
    
    	private GPUImage gpuImage;
    	//显示处理结果
    	private ImageView resultIv;
    
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.net_main);
    		resultIv = (ImageView) findViewById(R.id.imagex);
    
    		//开启异步线程加载图片并处理
    		MyAsynTask asynTask = new MyAsynTask();
    		asynTask.execute();
    
    	}
    
    	class MyAsynTask extends AsyncTask<Integer,Integer,Bitmap>{
    
    		@Override
    		protected Bitmap doInBackground(Integer... params) {
    			//写入图片的url
    			Bitmap bitmap = getGPUImageFromURL("https://img-blog.csdn.net/20180422104130848?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTEwMTE3Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70");
    			return bitmap;
    		}
    
    		@Override
    		protected void onPostExecute(Bitmap bitmap) {
    			// 使用GPUImage处理图像
    			gpuImage = new GPUImage(getApplicationContext());
    			gpuImage.setImage(bitmap);
    			gpuImage.setFilter(new GPUImageGrayscaleFilter());
    			bitmap = gpuImage.getBitmapWithFilterApplied();
    			//显示处理后的图片存储到bitmap
    			resultIv.setImageBitmap(bitmap);
    		}
    	}
    
    	public static Bitmap getGPUImageFromURL(String url) {
    		Bitmap bitmap = null;
    		try {
    			URL iconUrl = new URL(url);
    			URLConnection conn = iconUrl.openConnection();
    			HttpURLConnection http = (HttpURLConnection) conn;
    			int length = http.getContentLength();
    			conn.connect();
    			// 获得图像的字符流
    			InputStream is = conn.getInputStream();
    			BufferedInputStream bis = new BufferedInputStream(is, length);
    			bitmap = BitmapFactory.decodeStream(bis);
    			bis.close();
    			is.close();// 关闭流
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return bitmap;
    	}
    
    
    }
    
    

    网络图片的layout这个很简单就只是一个imageview:

    <?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/imagex"
            android:layout_width="match_parent"
            android:layout_height="229dp"
            android:layout_gravity="center_horizontal" />
    </LinearLayout>
    

    5.最后叨一叨:

    这个静态滤镜和联网滤镜功能已经实现了,接下来我需要做的是实现人脸识别美颜+组合滤镜功能,不知道大家有没有学习过或者使用过lightroom这款滤镜调整的WIN平台下的软件因为我本身副职业是走的是摄影这条路所以有所学习到,但是我认为GpuImage的滤镜功能就我暂时学到的可能有点少所以想要实现像LightRoom的那些大片滤镜功能就稍微有些复杂不过还是慢慢的一步一步走下去比较好一点。
    下面我们来看看我们走到哪一步了。

    基础拍照功能
    简单的相机设置功能实现
    GPUimage的简单滤镜功能实现
    接下来我们需要做的
    通过网络实现照片滤镜
    使用opencv实现人脸识别美颜和组合滤镜的实现

    6.下面附上一些常用的滤镜

    Coloradjustments: 31 filters, 颜色处理相关
    
    #import "GPUImageBrightnessFilter.h"                //亮度
    #import "GPUImageExposureFilter.h"                  //曝光
    #import "GPUImageContrastFilter.h"                  //对比度
    #import "GPUImageSaturationFilter.h"                //饱和度
    #import "GPUImageGammaFilter.h"                     //伽马线
    #import "GPUImageColorInvertFilter.h"               //反色
    #import "GPUImageSepiaFilter.h"                     //褐色(怀旧)
    #import "GPUImageLevelsFilter.h"                    //色阶
    #import "GPUImageGrayscaleFilter.h"                 //灰度
    #import "GPUImageHistogramFilter.h"                 //色彩直方图,显示在图片上
    #import "GPUImageHistogramGenerator.h"              //色彩直方图
    #import "GPUImageRGBFilter.h"                       //RGB
    #import "GPUImageToneCurveFilter.h"                 //色调曲线
    #import "GPUImageMonochromeFilter.h"                //单色
    #import "GPUImageOpacityFilter.h"                   //不透明度
    #import "GPUImageHighlightShadowFilter.h"           //提亮阴影
    #import "GPUImageFalseColorFilter.h"                //色彩替换(替换亮部和暗部色彩)
    #import "GPUImageHueFilter.h"                       //色度
    #import "GPUImageChromaKeyFilter.h"                 //色度键
    #import "GPUImageWhiteBalanceFilter.h"              //白平横
    #import "GPUImageAverageColor.h"                    //像素平均色值
    #import "GPUImageSolidColorGenerator.h"             //纯色
    #import "GPUImageLuminosity.h"                      //亮度平均
    #import "GPUImageAverageLuminanceThresholdFilter.h" //像素色值亮度平均,图像黑白(有类似漫画效果)
    #import "GPUImageLookupFilter.h"                    //lookup 色彩调整
    #import "GPUImageAmatorkaFilter.h"                  //Amatorka lookup
    #import "GPUImageMissEtikateFilter.h"               //MissEtikate lookup
    #import "GPUImageSoftEleganceFilter.h"              //SoftElegance lookup
    
    
    **#pragma mark - 图像处理 Handle Image**
    Image processing: 40 filters, 图像处理相关.
    
    
    #import "GPUImageCrosshairGenerator.h"              //十字
    #import "GPUImageLineGenerator.h"                   //线条
    #import "GPUImageTransformFilter.h"                 //形状变化
    #import "GPUImageCropFilter.h"                      //剪裁
    #import "GPUImageSharpenFilter.h"                   //锐化
    #import "GPUImageUnsharpMaskFilter.h"               //反遮罩锐化
    //#import "GPUImageFastBlurFilter.h"                  //模糊
    #import "GPUImageGaussianBlurFilter.h"              //高斯模糊
    #import "GPUImageGaussianSelectiveBlurFilter.h"     //高斯模糊,选择部分清晰
    #import "GPUImageBoxBlurFilter.h"                   //盒状模糊
    #import "GPUImageTiltShiftFilter.h"                 //条纹模糊,中间清晰,上下两端模糊
    #import "GPUImageMedianFilter.h"                    //中间值,有种稍微模糊边缘的效果
    #import "GPUImageBilateralFilter.h"                 //双边模糊
    #import "GPUImageErosionFilter.h"                   //侵蚀边缘模糊,变黑白
    #import "GPUImageRGBErosionFilter.h"                //RGB侵蚀边缘模糊,有色彩
    #import "GPUImageDilationFilter.h"                  //扩展边缘模糊,变黑白
    #import "GPUImageRGBDilationFilter.h"               //RGB扩展边缘模糊,有色彩
    #import "GPUImageOpeningFilter.h"                   //黑白色调模糊
    #import "GPUImageRGBOpeningFilter.h"                //彩色模糊
    #import "GPUImageClosingFilter.h"                   //黑白色调模糊,暗色会被提亮
    #import "GPUImageRGBClosingFilter.h"                //彩色模糊,暗色会被提亮
    #import "GPUImageLanczosResamplingFilter.h"         //Lanczos重取样,模糊效果
    #import "GPUImageNonMaximumSuppressionFilter.h"     //非最大抑制,只显示亮度最高的像素,其他为黑
    #import "GPUImageThresholdedNonMaximumSuppressionFilter.h" //与上相比,像素丢失更多
    #import "GPUImageSobelEdgeDetectionFilter.h"        //Sobel边缘检测算法(白边,黑内容,有点漫画的反色效果)
    #import "GPUImageCannyEdgeDetectionFilter.h"        //Canny边缘检测算法(比上更强烈的黑白对比度)
    #import "GPUImageThresholdEdgeDetectionFilter.h"    //阈值边缘检测(效果与上差别不大)
    #import "GPUImagePrewittEdgeDetectionFilter.h"      //普瑞维特(Prewitt)边缘检测(效果与Sobel差不多,貌似更平滑)
    #import "GPUImageXYDerivativeFilter.h"              //XYDerivative边缘检测,画面以蓝色为主,绿色为边缘,带彩色
    #import "GPUImageHarrisCornerDetectionFilter.h"     //Harris角点检测,会有绿色小十字显示在图片角点处
    #import "GPUImageNobleCornerDetectionFilter.h"      //Noble角点检测,检测点更多
    #import "GPUImageShiTomasiFeatureDetectionFilter.h" //ShiTomasi角点检测,与上差别不大
    #import "GPUImageMotionDetector.h"                  //动作检测
    #import "GPUImageHoughTransformLineDetector.h"      //线条检测
    #import "GPUImageParallelCoordinateLineTransformFilter.h" //平行线检测
    #import "GPUImageLocalBinaryPatternFilter.h"        //图像黑白化,并有大量噪点
    #import "GPUImageLowPassFilter.h"                   //用于图像加亮
    #import "GPUImageHighPassFilter.h"                  //图像低于某值时显示为黑
     
     
     
    #pragma mark - 视觉效果 Visual Effect
    Visual effects: 25 filters, 视觉效果相关
    
    
    
    #import "GPUImageSketchFilter.h"                    //素描
    #import "GPUImageThresholdSketchFilter.h"           //阀值素描,形成有噪点的素描
    #import "GPUImageToonFilter.h"                      //卡通效果(黑色粗线描边)
    #import "GPUImageSmoothToonFilter.h"                //相比上面的效果更细腻,上面是粗旷的画风
    #import "GPUImageKuwaharaFilter.h"                  //桑原(Kuwahara)滤波,水粉画的模糊效果;处理时间比较长,慎用
    #import "GPUImageMosaicFilter.h"                    //黑白马赛克
    #import "GPUImagePixellateFilter.h"                 //像素化
    #import "GPUImagePolarPixellateFilter.h"            //同心圆像素化
    #import "GPUImageCrosshatchFilter.h"                //交叉线阴影,形成黑白网状画面
    #import "GPUImageColorPackingFilter.h"              //色彩丢失,模糊(类似监控摄像效果)
     
    #import "GPUImageVignetteFilter.h"                  //晕影,形成黑色圆形边缘,突出中间图像的效果
    #import "GPUImageSwirlFilter.h"                     //漩涡,中间形成卷曲的画面
    #import "GPUImageBulgeDistortionFilter.h"           //凸起失真,鱼眼效果
    #import "GPUImagePinchDistortionFilter.h"           //收缩失真,凹面镜
    #import "GPUImageStretchDistortionFilter.h"         //伸展失真,哈哈镜
    #import "GPUImageGlassSphereFilter.h"               //水晶球效果
    #import "GPUImageSphereRefractionFilter.h"          //球形折射,图形倒立
     
    #import "GPUImagePosterizeFilter.h"                 //色调分离,形成噪点效果
    #import "GPUImageCGAColorspaceFilter.h"             //CGA色彩滤镜,形成黑、浅蓝、紫色块的画面
    #import "GPUImagePerlinNoiseFilter.h"               //柏林噪点,花边噪点
    #import "GPUImage3x3ConvolutionFilter.h"            //3x3卷积,高亮大色块变黑,加亮边缘、线条等
    #import "GPUImageEmbossFilter.h"                    //浮雕效果,带有点3d的感觉
    #import "GPUImagePolkaDotFilter.h"                  //像素圆点花样
    #import "GPUImageHalftoneFilter.h"                  //点染,图像黑白化,由黑点构成原图的大致图形
     
    #pragma mark - 混合模式 Blend
    Blending modes: 29 filters, 混合模式相关.
    
     
    #import "GPUImageMultiplyBlendFilter.h"             //通常用于创建阴影和深度效果
    #import "GPUImageNormalBlendFilter.h"               //正常
    #import "GPUImageAlphaBlendFilter.h"                //透明混合,通常用于在背景上应用前景的透明度
    #import "GPUImageDissolveBlendFilter.h"             //溶解
    #import "GPUImageOverlayBlendFilter.h"              //叠加,通常用于创建阴影效果
    #import "GPUImageDarkenBlendFilter.h"               //加深混合,通常用于重叠类型
    #import "GPUImageLightenBlendFilter.h"              //减淡混合,通常用于重叠类型
    #import "GPUImageSourceOverBlendFilter.h"           //源混合
    #import "GPUImageColorBurnBlendFilter.h"            //色彩加深混合
    #import "GPUImageColorDodgeBlendFilter.h"           //色彩减淡混合
    #import "GPUImageScreenBlendFilter.h"               //屏幕包裹,通常用于创建亮点和镜头眩光
    #import "GPUImageExclusionBlendFilter.h"            //排除混合
    #import "GPUImageDifferenceBlendFilter.h"           //差异混合,通常用于创建更多变动的颜色
    #import "GPUImageSubtractBlendFilter.h"             //差值混合,通常用于创建两个图像之间的动画变暗模糊效果
    #import "GPUImageHardLightBlendFilter.h"            //强光混合,通常用于创建阴影效果
    #import "GPUImageSoftLightBlendFilter.h"            //柔光混合
    #import "GPUImageChromaKeyBlendFilter.h"            //色度键混合
    #import "GPUImageMaskFilter.h"                      //遮罩混合
    #import "GPUImageHazeFilter.h"                      //朦胧加暗
    #import "GPUImageLuminanceThresholdFilter.h"        //亮度阈
    #import "GPUImageAdaptiveThresholdFilter.h"         //自适应阈值
    #import "GPUImageAddBlendFilter.h"                  //通常用于创建两个图像之间的动画变亮模糊效果
    #import "GPUImageDivideBlendFilter.h"               //通常用于创建两个图像之间的动画变暗模糊效果
    
    

    本文参考自:
    Android图像滤镜框架GPUImage从配置到应用
    Android使用GPUImage实现滤镜效果精炼详解(一)

    展开全文
  • Android APP开发 请教下:使用SurfaceView能实现相机的预览实时滤镜效果吗?如果能 怎么实现呀?跪谢
  • Android 相机 II-实现自己的相机APP

    千次阅读 2016-01-02 16:54:59
    Android 相机 II-实现自己的相机APP; 信息来自官网. 有些开发者可能会需要一个自定义的相机用户接口, 以实现自己独特样式的相机和特殊的功能. 创建一个自定义相机activity比调用系统相机需要更多的代码, 但是它可以...

    概述:

    有些开发者可能会需要一个自定义的相机用户接口, 以实现自己独特样式的相机和特殊的功能. 创建一个自定义相机activity比调用系统相机需要更多的代码, 但是它可以为用户提供更加丰富的体验.

    注意: 这里介绍的是使用老版本的Camera类, 该类已经不推荐使用. 推荐使用的类是android.hardware.camera2.该类在API21中引入. 

    为一个APP创造一个自定义相机接口的普通步骤是这样的:

    1.      检测和访问相机– 创建代码来检查是否存在相机并申请访问.

    2.      创建一个Preview类– 创建一个相机预览类, 该类继承SurfaceView并实现SurfaceHolder接口. 这个类负责预览相机拍摄到的图像.

    3.      创建一个Preview用的Layout – 一旦有了相机预览类, 就得创建一个layout来合并预览和给用户提供的操作界面.

    4.      为拍照功能设置监听– 为我们的启动拍照或者视频的接口控制连接监听器来响应用户的操作, 比如点击按钮拍照.

    5.      抓取和保存文件– 写代码实现抓取图片或者视频, 并保存输出.

    6.      释放camera – 用完之后, APP必须适时释放以供其它APP使用.

    相机硬件是一种共享资源, 它必须被小心的使用这样就不会让我们的APP与其它需要使用它的APP发生冲突. 下面的小节将会讨论如何检测相机硬件, 如何请求访问相机, 如何抓取图片或者视频和用完之后如何释放相机资源.

    注意, 请一定记得在使用完毕后及时释放相机资源. 否则所有后续尝试访问相机的APP包括我们自己的APP都无法再访问相机资源, 并很可能引起APP闪退.

    检测相机硬件:

    如果我们的APP没有在manifest中声明需要使用相机资源, 我们应该在运行时检测相机资源是否可用. 想要实现这个操作, 需要使用PackageManager.hasSystemFeature()方法, 栗子:

    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context){
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }

    Android设备可以拥有多个相机, 比如一个用于拍照的主摄像头和一个用于视频通话或者自拍的前置摄像头. Android 2.3及更高版本允许我们使用Camera.getNumberOfCameras()方法检测可用相机的数量.

    访问相机:

    如果在APP运行的设备上确定有一个相机, 那么可以使用Camera的实例来请求访问它(或者使用intent访问). 想要在底层访问相机, 需要使用Camera.open()方法并确认捕获任何异常, 栗子:

    /** A safe way to get an instance of the Camera object. */
    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }

    要注意在使用Camera.open()方法访问相机的时候必须检查异常. 如果相机不存在或者检查失败的话会导致APP挂掉.

    在Android 2.3及更高版本中, 我们可以使用Camera.open(int)访问指定的相机. 上面的栗子将会访问第一个, 就是后置摄像机.

    检查相机功能:

    一旦取得了对相机的访问, 我们就可以通过Camera.getParameters()方法获得更多的相机功能的信息, 该方法会返回一个Camera.Parameters对象, 可以通过它查看相机功能. 当使用API 9 及更高版本时, 使用Camera.getCameraInfo(0方法来决定相机是在设备的前面还是后面, 以及画面的方向.

    创建一个预览类:

    对于用户来说, 如果他们想拍出靠谱的图片或者视频, 他们必须能看到设备相机所看到的内容. 这时候就需要一个预览的窗口让用户可以看到相机拍到的东西, 相机预览类是SurfaceView, 它可以显示从相机直播的图像数据.

    下面的栗子展示了如何创建一个基本的相机预览类, 并可以放在View layout中. 这个类实现了SurfaceHolder.Callback接口, 它可以用来捕捉view创建和回收的事件.

    /** A basic Camera preview class */
    public classCameraPreview extendsSurfaceView implementsSurfaceHolder.Callback{
        private SurfaceHolder mHolder;
        private Camera mCamera;

        public CameraPreview(Context context,Camera camera){
            super(context);
            mCamera = camera;

            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        public void surfaceCreated(SurfaceHolder holder){
            // The Surface has been created, now tell the camera where to draw thepreview.
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch(IOException e){
                Log.d(TAG,"Errorsetting camera preview: " + e.getMessage());
            }
        }

        public void surfaceDestroyed(SurfaceHolder holder){
            // empty. Take care of releasing the Camera preview in your activity.
        }

        public void surfaceChanged(SurfaceHolder holder,int format,int w, int h) {
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.

            if (mHolder.getSurface()== null){
              // preview surface does not exist
              return;
            }

            // stop preview before making changes
            try {
                mCamera.stopPreview();
            } catch(Exception e){
              // ignore: tried to stop a non-existent preview
            }

            // set preview size and make any resize, rotate or
            // reformatting changes here

            // start preview with new settings
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();

            } catch(Exception e){
                Log.d(TAG,"Errorstarting camera preview: " + e.getMessage());
            }
        }
    }

    如果想要为相机预览设置一个指定的大小, 则需要在surfaceChanged()中设置. 当设置预览窗口的大小的时候, 必须使用从getSupportedPreviewSizes()提供的值. 不要在setPreviewSize()方法中设置随意的值.

    在layout中放置preview:

    相机预览类(比如前一节的栗子)必须被放置在layout中并跟它的用户控制接口(比如拍照或者摄像键)放在一起. 本的小节将会展示如何创建一个基础的layout和activity用来预览. 下面的layout代码提供了一个非常基础的view, 它可以用来显示一个相机的预览. 在这个栗子中, FrameLayout标签用于作为相机预览类的容器. 使用这种layout是为了让更多的图片信息或者控件可以覆盖在相机的预览图像上.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
      <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        />

      <Button
        android:id="@+id/button_capture"
        android:text="Capture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        />
    </LinearLayout>

    在大多数设备上, 默认的相机方向是横向的. 这个栗子中的layout指定了一个横向的layout, 并且使用下面的代码修正APP的屏幕方向为横向. 为简单起见, 可以在manifest中通过这段代码修改APP预览activity的方向到横屏:

    <activity android:name=".CameraActivity"
              android:label="@string/app_name"

              android:screenOrientation="landscape">
              <!-- configure this activity to use landscapeorientation -->

              <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    一个相机预览窗口并不一定必须是横屏模式, 从Android2.2开始, 我们可以使用setDisplayOrientation()方法来设置预览图像的方向. 为了在用户旋转屏幕的时候改变预览方向, 在surfaceChanged()方法中, 首先通过Camera.stopPreview()停止预览, 然后改变方向, 之后再用Camera.startPreview()方法重新启动预览.

    在相机预览的activity中, 向FrameLayout中添加预览类. 相机activity必须确保相机暂停或者关闭的时候释放相机资源. 下面的代码展示了如何修改相机activity来关联预览类:

    public class CameraActivity extends Activity {

        private Camera mCamera;
        private CameraPreview mPreview;

        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            // Create an instance of Camera
            mCamera = getCameraInstance();

            // Create our Preview view and set it as the content of our activity.
            mPreview = new CameraPreview(this, mCamera);
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
            preview.addView(mPreview);
        }
    }

    getCameraInstance()方法是在”访问相机”小节实现的.

    捕捉图片(拍照..):

    一旦预览类创建完毕, 并且已经可以在一个layout中显示, 就表示已经为捕捉图片做好了准备. 在APP代码中我们必须为用户接口设置监听器以相应用户的操作. 想要获取一个图片, 要使用Camera.takePicture()方法. 该方法接收三个参数用来获取相机传回的数据. 为了接收接收JPEG格式的数据, 我们必须实现一个Camera.PictureCallback接口来接收图片数据, 并将它写入一个文件中. 下面的代码展示了一个基础的Camera.PictureCallback接口的实现, 用于保存一个从相机接收的图像:

    private PictureCallback mPicture = new PictureCallback(){

        @Override
        public void onPictureTaken(byte[] data,Camera camera){

            File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
            if (pictureFile== null){
                Log.d(TAG,"Errorcreating media file, check storage permissions: "+
                    e.getMessage());
                return;
            }

            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch(FileNotFoundException e){
                Log.d(TAG,"File notfound: " + e.getMessage());
            } catch(IOException e){
                Log.d(TAG,"Erroraccessing file: " + e.getMessage());
            }
        }
    };

    通过Camera.takePicture()方法来触发拍照操作. 下面的栗子展示了如何从一个button的View.OnClickListener中调用该方法:

    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(id.button_capture);
    captureButton.setOnClickListener(
        new View.OnClickListener(){
            @Override
            public void onClick(View v){
                // get an image from the camera
                mCamera.takePicture(null,null, mPicture);
            }
        }
    );

    mPicture变量在之前的栗子中定义.

    注意: 一定要记得在APP用完相机之后释放它. 释放方法是Camera.release().

    捕捉视频(摄像…):

    使用Android framework捕捉视频需要对Camera对象很仔细的使用和管理, 并且需要跟MediaRecorder类协作使用. 当使用Camera类录制视频的时候, 我们必须管理Camera.lock()和Camera.unlock()方法来允许MediaRecorder访问相机硬件, 除此之外还有Cemra.open()和Camera.release()方法.

    从Android4.0开始, Camera.lock()和Camera.unlock()方法已经可以自动管理了.

    不同于使用设备拍照, 录像需要一个非常特殊的顺序. 详情如下:

    1.      打开相机– 使用Camera.open()方法来获取一个相机对象的实例.

    2.      连接预览窗口– 通过Camera.setPreviewDisplay()方法连接一个SurfaceView到相机, 这样就可以预览相机的图像了.

    3.      开始预览– 调用Camera.startPreview()方法来启动显示直播的相机图像.

    4.      开始录制视频– 想要成功录制视频, 必须完成下面的步骤:

    a)        解锁相机– 通过Camera.unlock()方法为MediaRecorder解锁相机.

    b)        配置 MediaRecorder – 按照下面指定的顺序调用MediaRecorder中的下列方法.

                            i.             setCamera – 设置相机用于录像, 使用APP当前的Camera实例.

                          ii.             setAudioSource() – 设置音频源, 使用MediaRecorder.AudioSource.CAMCORDER.

                         iii.             setVideoSource() – 设置视频源, 使用MediaRecorder.VideoSource.CAMCORDER.

                         iv.             设置视频输出的编码格式. 对于Android2.2及更高版本, 使用MediaRecorder.setProfile方法, 并使用CamcorderProfile.get()获取一个profile实例. 对于Android2.2以前的版本, 必须设置视频输出格式和编码参数: setOutputFormat()方法用于设置输出格式, 默认设置是MediaRecorder.OutputFormat.MPEG_4. setAudioEncoder()方法用于设置声音编码类型,默认值是MediaRecorder.AudioEncoder.AMR_NB. setVideoEncoder()方法用于设置视频编码类型,默认值是MediaRecorder.VideoEncoder.MPEG_4_SP.

                          v.             setOutputFile() – 设置输出文件, 使用”保存媒体文件”小节中的getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()方法.

                         vi.             setPreviewDisplay() – 为APP指定SurfaceView预览layout. 使用”连接预览窗口”中相同的对象.

    注意, 我们必须按照上面的顺序调用这些MediaRecorder配置方法, 否则APP将会出错, 录制也将会失败.

    c)        准备MediaRecorder – 通过MediaRecorder.prepare()方法及提供的配置设置项准备MediaRecorder.

    d)        启动MediaRecorder – 使用MediaRecorder.start()方法启动录制视频.

    5.      停止录制视频– 按顺序调用下面的方法来完成视频录制:

    a)        停止MediaRecorder – 使用MediaRecorder.stop()方法停止视频录制.

    b)        重置MediaRecorder – 可选, 从recorder中移除配置设置项. 方法是MediaRecorder.reset().

    c)        释放MediaRecorder – 使用MediaRecorder.release()方法释放MediaRecorder.

    d)        锁定相机– 使用Camera.lock()锁定相机, 这样未来的MediaRecorder会话就可以使用它了. 从Android4.0开始, 该方法不用调用了, 除非MediaRecorder.prepare()方法调用失败.

    6.      停止预览– 当activity已经完成使用相机, 使用Camera.stopPreview()来停止预览.

    7.      释放相机– 使用Camera.release()方法释放相机, 这样其它的APP才可以再次使用它.

    注意: 不创建相机预览而使用MediaRecorder是可行的. 但是用户通常更希望在拍摄之前可以看到预览.

    提示: 如果我们的APP是用来录像的, 设置setRecordingHint(Boolean)为true来提前启动预览. 这个设置可以帮助减少开始录制话费的时间.

    配置MediaRecorder:

    当使用MediaRecorder类来录像的时候, 我们必须按顺序执行配置步骤, 然后调用MediaRecorder.prepare()方法来检查和实现配置. 下面的代码展示了如何合适的配置和准备MediaRecorder类:

    private boolean prepareVideoRecorder(){

        mCamera = getCameraInstance();
        mMediaRecorder = new MediaRecorder();

        // Step 1:Unlock and set camera to MediaRecorder
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);

        // Step 2: Setsources
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        // Step 3: Set aCamcorderProfile (requires API Level 8 or higher)
        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

        // Step 4: Setoutput file
        mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

        // Step 5: Setthe preview output
        mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

        // Step 6:Prepare configured MediaRecorder
        try {
            mMediaRecorder.prepare();
        } catch(IllegalStateException e){
            Log.d(TAG,"IllegalStateException preparing MediaRecorder:"+ e.getMessage());
            releaseMediaRecorder();
            return false;
        } catch(IOException e){
            Log.d(TAG,"IOException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }
        return true;
    }

    Android2.2版本之前, 我们必须直接设置输出格式和编码格式参数, 而不是使用CamcorderProfile. 这种方法是这样的:

        // Step3: Set output format and encoding (for versions prior to API Level 8)
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

    上面的MediaRecorder的录像参数提供了默认的设置项, 但是如果想要自定义的话, 我们可以使用这些方法:

    l  setVideoEncodingBitRate()

    l  setVideoSize()

    l  setVideoFrameRate()

    l  setAudioEncodingBitRate()

    l  setAudioChannels()

    l  setAudioSamplingRate()

    启动和停止MediaRecorder:

    当使用MediaRecorder类启动和停止视频录制的时候, 我们必须按顺序执行下面的步骤: 

    1.      使用Camera.unlock()解锁相机.

    2.      像上面栗子中那样配置MediaRecorder.

    3.      使用MediaRecorder.start()开始录制.

    4.      录制视频.

    5.      调用MediaRecorder.stop()方法停止录制.

    6.      使用MediaRecorder.release()方法释放媒体recorder.

    7.      使用Camera.lock()锁定相机.

    下面的栗子展示了如何使用一个button来合适的启动和停止视频录制:

    注意, 当完成录制之后不要直接释放相机, 否则预览就会被停止.

    private boolean isRecording = false;
    
    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(id.button_capture);
    captureButton.setOnClickListener(
        new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRecording) {
                    // stop recording and release camera
                    mMediaRecorder.stop();  // stop the recording
                    releaseMediaRecorder(); // release the MediaRecorder object
                    mCamera.lock();         // take camera access back from MediaRecorder
    
                    // inform the user that recording has stopped
                    setCaptureButtonText("Capture");
                    isRecording = false;
                } else {
                    // initialize video camera
                    if (prepareVideoRecorder()) {
                        // Camera is available and unlocked, MediaRecorder is prepared,
                        // now you can start recording
                        mMediaRecorder.start();
    
                        // inform the user that recording has started
                        setCaptureButtonText("Stop");
                        isRecording = true;
                    } else {
                        // prepare didn't work, release the camera
                        releaseMediaRecorder();
                        // inform user
                    }
                }
            }
        }
    );

    上面的代码中, prepareVideoRecorder()方法在”配置MediaRecorder”小节中实现. 该方法负责锁定相机, 配置和准备MediaRecorder实例.

    释放相机:

    相机是一个可以被设备上的APP共享的资源. 我们的APP可以在获取到一个Camera实例之后开始使用相机, 当使用结束之后, 必须记得释放相机对象, 还有在APP暂停的时候(Activity.onPause)也要记得释放. 如果APP没有合适的释放相机, 所有的接下来的访问相机的请求包括我们自己的APP都将会失败, 可能会导致我们的APP闪退.

    想要释放一个Camera对象的实例, 需要使用Camera.release()方法. 栗子:

    public class CameraActivity extends Activity {
        private Camera mCamera;
        private SurfaceView mPreview;
        private MediaRecorder mMediaRecorder;
    
        ...
    
        @Override
        protected void onPause() {
            super.onPause();
            releaseMediaRecorder();       // if you are using MediaRecorder, release it first
            releaseCamera();              // release the camera immediately on pause event
        }
    
        private void releaseMediaRecorder(){
            if (mMediaRecorder != null) {
                mMediaRecorder.reset();   // clear recorder configuration
                mMediaRecorder.release(); // release the recorder object
                mMediaRecorder = null;
                mCamera.lock();           // lock camera for later use
            }
        }
    
        private void releaseCamera(){
            if (mCamera != null){
                mCamera.release();        // release the camera for other applications
                mCamera = null;
            }
        }
    }

    保存媒体文件:

    用户通过拍照或者录像创建的媒体文件应该被保存在设备的外部存储目录中(SD卡), 这样可以节省系统空间让用户可以在设备之外访问这些文件. 有很多种可以存放媒体文件的目录, 然而作为一个开发者, 我们应该只考虑两个标准的路径:

    1.      Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)– 该方法返回标准的共享的和官方推荐的路径用来保存图片和视频. 该目录是共享的(public), 所以其他的APP也可以很容易的发现读取修改和删除保存在这里的文件. 如果我们的APP被用户卸载了, 保存在这里的媒体文件不会被移除. 想要避免干涉用户已经存在的图片和视频, 我们应该为APP创建一个子目录来存放自己的媒体文件. 该方法只能在Android2.2及之后的版本中使用. 更早的API版本可以参考这里.

    2.      Context.getExternalFilesDir(Envireonment.DIRECTORY_PICTURES)– 该方法返回一个标准的路径用于保存图片和视频, 该路径是与APP关联的. 如果APP被卸载了, 那么任何保存在该路径下的文件都将被卸载. 该路径中的文件并不是加密的, 其它的APP可以读取修改和删除它们.

    下面的栗子展示了如何为一个媒体文件创建一个File或者Uri路径:

    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;
    
    /** Create a file Uri for saving an image or video */
    private static Uri getOutputMediaFileUri(int type){
          return Uri.fromFile(getOutputMediaFile(type));
    }
    
    /** Create a File for saving an image or video */
    private static File getOutputMediaFile(int type){
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.
    
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                  Environment.DIRECTORY_PICTURES), "MyCameraApp");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.
    
        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");
                return null;
            }
        }
    
        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "IMG_"+ timeStamp + ".jpg");
        } else if(type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "VID_"+ timeStamp + ".mp4");
        } else {
            return null;
        }
    
        return mediaFile;
    }

    注意: Environment.getExternalStoragePublicDirectory()在Android2.2及更高版本中可用, 如果目标设备使用更早的Android版本, 则要使用Environment.getExternalStorageDirectory()方法代替.

     

    总结:

    获取相机对象(PackageManager, Camera); 创建预览窗口(SurfaceView,SurfaceHolder); 关联预览窗口和相机对象; 设置拍摄操作的事件监听器; 拍摄保存; 释放;

     

    参考: https://developer.android.com/guide/topics/media/camera.html


    展开全文
  • 在实际的工作时,我们有的时候会遇到这种情况:骁龙相机的一些设置方法,谷歌api中没有。比如设置Contrast(对比度),Sharpness(清晰度),Saturation(饱和度)等等的一下方法,这些方法在谷歌原生的api中是没有的...
  • Android进阶(十八)AndroidAPP开发问题汇总(二) 端口被占用解决措施: Android使用SimpleAdapter更新ListView里面的Drawable元素: http://www.cnblogs.com/thu539/archive/2012/02/01/2334455.html Android中...
  • 非商业性使用-禁止演绎 4.0 国际》协议 https://blog.csdn.net/bluewindtalker/article/details/54563910相机开发现在有2个类,分别为android.hardware.camera2和android.hard...
  • 详述Google的Android平板App开发准则

    千次阅读 2012-12-17 16:06:37
    为了给自己的平板业务创造一个优质的App市场,Google近日向开发者发布了10条在Android平板上开发App的准则,下面是这10条准则的详细描述。 1、保证符合App的通用开发准则 在谈Android平板App开发准则之前,...
  • 4.写的Socket Service类,报出android.os.NetworkOnMainThreadException错误,在Service中,已经使用了线程去启动socket网络服务,不知道为什么还会报错,正在排查中。调试后发现,其实socket的建立也应该放到线程中...
  • 最近 做了 Sony 、松下等多款相机Android APP的二次开发。有需要或者交流的联系2637405696。 Sony有开源的sdk可以使用,松下的就有点坑了 毫无借鉴的 资料都是全英文的,还有 佳能的 各种坑。
  • 安卓web app开发

    2017-03-27 23:55:37
    安卓移动应用的混合开发,现在很多APP都开始着手实现了,比如淘宝的页面就是,但是吐槽下,确实又卡又慢,当然你可以反击我手机性能差... 说说优点吧: 1 快速上手支持快速迭代更新(快速上手:你可以不懂Android,IOS就...
  • Android 调用相机APP获取拍照图片和从相册选择图片
  • 相机360安卓版介绍:Camera360【相机360】,可以让你替代单反相机,省去学习复杂的PS教程,"傻瓜"式的拍摄和美图滤镜效果,瞬间让你的照片华丽起来。Camera360让你玩转旅行拍照、个性自拍、图片美化编辑、同时还一键...
  • OkCamera,Android 相机应用开发通用库 转载请声明出处:http://blog.csdn.net/andrexpert/article/details/79302576    明天就可以回家过年了,有点小激动,于是乎赶紧写篇文章压压惊!本文主要介绍最近写的一...
  • Android 水印相机开发

    千次阅读 2019-03-08 16:57:46
    水印相机是自定义相机的一种,实现方法有很多,我看了很多别人的做的很漂亮,我做的就很普通了,不过总算是实现了拍照加水印的功能。 我这边用到了SurfaceView,有人没用这个也做出来水印...相机功能由android.hardw...
  • 首先,动态获取权限,非常重要 //在进入主页面时动态获取(记得在清单文件中添加) ... requestPermissions(new String[]{"android.permission.CAMERA", "android.permission.READ_EXTERNAL_STORAGE", "a
  • 【copy from:Android Camera相机以及相机程序开发实例 】 拍照程序,是通过 Intent 调用 Android 系统提供的照相机程序实现的。 Android SDK 提供了直接操作移动设备摄像头的 android.hardware.Camera 类,通过该类...
  • Android平台Camera开发实践指南 特点 功能相互独立,各个功能的实现依赖于约定的接口,彼此互不依赖,开发者不必为了引入某一个功能而带入一堆依赖。 高度的UI定制性,内置四种配色方案,开发者也可以通过简单的...
  • 随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑、智能电视、车载大屏、智能家居、智能手表等诸多设备,...在5G时代,Android App开发需要发挥5G优势给用户带来新体验、增添新功能、用得更省
  • 基于Eclipse ADT开发的一个美颜瘦脸手机APP,能实现一般瘦脸APP的基本功能。 项目具体内容包括: 1、主要包括瘦脸功能模块。瘦脸功能模块实现了美颜瘦脸APP的基本缩小脸颊瘦脸功能。 2、后台主要实现美颜相机瘦脸...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,441
精华内容 6,976
关键字:

安卓相机app开发