• 照相机滤镜使用,优化解码和滤镜导致的预览卡屏现象


    这几天看到亚瑟boy的技术连载,也试着做了下带滤镜特效的照相机,效果也出来了,但是发现添加滤镜特效后的预览窗口卡屏现象很严重,于是自己索性试着尝试修改,在亚瑟和其他网友的代码中基本上都是对于照相机data视频流先进行解码,然后对解码出的帧Bitmap进行滤镜算法处理,这个是必走的流程,而每一帧在处理解码和滤镜时都需要用掉大量时间,我测了下,解码需要300毫秒左右,滤镜处理需要600毫秒左右(冰冻滤镜),如此一来,处理完这两个流程需要的时间要在900毫秒甚至更长,我们知道如果看上去比较流畅的话我们需要每秒更新三帧的图片,而这么处理只能更新一张,明显的卡屏。
    于是试着去缩小处理的Bitmap大小,在照相机预览返回照片大小中设置:

    Camera.Parameters parameters = camera.getParameters();
    parameters.setPreviewSize(display.getWidth()/2, display.getHeight()/2);// 设置预览照片的大小


    原来默认是返回屏幕大小的预览图片,此时我改成了屏幕大小一半的图片,发现处理过程明显加快了(当然也有稍微的卡屏),最后在预览回调接口PreviewCallBack中再将图片放大到屏幕大小,有雨我预览图片返回时只是缩小了一半,此时放大回屏幕大小时仍然是非常清晰的,如果你想速度更快的话可以继续缩小预览图片的返回大小。

    代码如下:

    public class CameraActivity extends NoSearchActivity {
             private static final String TAG = "CameraActivity";
             private SurfaceView surfaceView;
             private Camera camera;
             private boolean preview;
             private ImageButton take_picture;
             private int width,height;
     
            @Override
             public void onCreate(Bundle savedInstanceState) {
                     super.onCreate(savedInstanceState);
                     Window window = getWindow();
                     requestWindowFeature(Window.FEATURE_NO_TITLE);// 没有标题
                     window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                                     WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
                     window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 高亮
     
                    setContentView(R.layout.camera_view);
     
                    ButtonClickingListener buttonlistener = new ButtonClickingListener();
                     surfaceView = (SurfaceView) this.findViewById(R.id.camera_surface);
                     WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
                     Display display = wm.getDefaultDisplay();
                     width = display.getWidth();
                     height = display.getHeight();
     
                    take_picture = (ImageButton) findViewById(R.id.take_picture);//拍照
                     take_picture.setOnClickListener(buttonlistener);
                     surfaceView.getHolder().setFixedSize(width, height); // 设置分辨率
                     /* 下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前 */
                     surfaceView.getHolder().addCallback(new SurfaceCallback());
             }
             //按钮监听
             private final class ButtonClickingListener implements View.OnClickListener {
                     @Override
                     public void onClick(View v) {
                             if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                                     Toast.makeText(CameraActivity.this, R.string.sdcarderror, 1).show();
                                     return;
                             }
                             try {
                                     switch (v.getId()) {
                                     case R.id.take_picture:
                                             camera.takePicture(null, null, new TakePictureCallback());
                                             break;
                                     }
                             } catch (Exception e) {
                                     Toast.makeText(CameraActivity.this, R.string.error, 1).show();
                                     Log.e(TAG, e.toString());
                             }
                     }
             }
             @Override
             protected void onDestroy() {
                     // TODO Auto-generated method stub
                     if(camera!=null){
                             camera.setPreviewCallback(null) ;
                 camera.stopPreview();
                 camera.release();
                 camera = null;
                     }
                     super.onDestroy();
             }
             private final class SurfaceCallback implements SurfaceHolder.Callback {
     
                    @Override
                     public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}
                     @Override
                     public void surfaceCreated(SurfaceHolder holder) {
                             if(camera==null){
                                     camera = Camera.open();//打开相机
                             }else{
                                     Toast.makeText(CameraActivity.this, "相机正在使用中", 1).show();
                             }
                             WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
                             Display display = wm.getDefaultDisplay();
                             Camera.Parameters parameters = camera.getParameters();
                             parameters.setPreviewSize(display.getWidth()/2, display.getHeight()/2);// 设置预览照片的大小
                             parameters.setPreviewFrameRate(3);// 每秒3帧
                             parameters.setPictureFormat(PixelFormat.JPEG);// 设置照片的输出格式
                             parameters.set("jpeg-quality", 100);// 照片质量
                             parameters.setPictureSize(display.getWidth(), display.getHeight());// 设置照片的大小
                             
                            camera.setParameters(parameters);
                             camera.setPreviewCallback(new PreviewCallBack());// 通过SurfaceView显示取景画面
                             camera.startPreview();//开始预览
                             preview = true;
                     }
     
                    @Override
                     public void surfaceDestroyed(SurfaceHolder holder) {
                             if (camera != null) {
                                     if (preview)
                                             camera.stopPreview();
                                     camera.release();
                             }
                     } 
            }
     
            @Override
             public boolean onKeyDown(int keyCode, KeyEvent event) {
                     if (camera != null && event.getRepeatCount() == 0) {
                             switch (keyCode) {
                                     case KeyEvent.KEYCODE_MENU:
                                             camera.autoFocus(null);// 自动对焦
                                             break;
                                     case KeyEvent.KEYCODE_CAMERA:
                                     case KeyEvent.KEYCODE_DPAD_CENTER:
                                             camera.takePicture(null, null, new TakePictureCallback());
                                             break;
                                     case KeyEvent.KEYCODE_BACK:
                                             new AlertDialog.Builder(CameraActivity.this).setTitle("提示")
                                             .setMessage("确定退出照相机?").setPositiveButton("确定",
                                                             new DialogInterface.OnClickListener() {
                                                     public void onClick(DialogInterface dialog,int whichButton) {
                                                             Intent exit = new Intent(Intent.ACTION_MAIN);
                                                             exit.addCategory(Intent.CATEGORY_HOME);
                                                             exit.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                                             startActivity(exit);
                                                             System.exit(0);
                                                     }
                                             }).setNegativeButton("取消",new DialogInterface.OnClickListener() {
                                                     public void onClick(DialogInterface dialog,int whichButton) {
                                                             // 取消按钮事件
                                                             dialog.cancel();
                                                     }
                                             }).show();
                                             break;
                             }
                     }
                     return super.onKeyDown(keyCode, event); // 不会回到 home 页面
             }
             //预览回调接口
             private final class PreviewCallBack implements Camera.PreviewCallback {
                     public void onPreviewFrame(byte[] data, Camera camera) {
                             if (data != null) {
                                     int imageWidth = camera.getParameters().getPreviewSize().width;
                                     int imageHeight = camera.getParameters().getPreviewSize().height;
                                     int RGBData[] = new int[imageWidth * imageHeight];
                                     decodeYUV420SP(RGBData, data, imageWidth, imageHeight); //解码
                                     Bitmap bm = Bitmap.createBitmap(RGBData, imageWidth, imageHeight, Config.ARGB_8888);
     //                                bm = toGrayscale(bm);//实时滤镜效果,现在是变成黑白效果
                                     bm = ice(bm);//冰冻效果
                                     Canvas canvas = surfaceView.getHolder().lockCanvas();
                         // 判断非null,才能drawBitmap.
                         if (bm != null) {
                                 bm = Bitmap.createScaledBitmap(bm, width, height,false);
                             canvas.drawBitmap(bm, 0, 0, null);
                         }
                         surfaceView.getHolder().unlockCanvasAndPost(canvas);
                             }
             }
             }

    灰度效果(黑白照片)

    public static Bitmap toGrayscale(Bitmap bmp) {
                     int height = bmp.getHeight();
                     int width = bmp.getWidth();
     
                    Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
                     Canvas c = new Canvas(bmpGrayscale);
                     Paint paint = new Paint();
                     ColorMatrix cm = new ColorMatrix();
                     cm.setSaturation(0);
                     ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
                     paint.setColorFilter(f);
                     c.drawBitmap(bmp, 0, 0, paint);
                     return bmpGrayscale;
             }

    冰冻特效

    public static Bitmap ice(Bitmap bmp) {
                     int width = bmp.getWidth();
                     int height = bmp.getHeight();
                     Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
                     int dst[] = new int[width * height];
                     bmp.getPixels(dst, 0, width, 0, 0, width, height);
                     int R, G, B, pixel;
                     int pos, pixColor;
                     for (int y = 0; y < height; y++) {
                             for (int x = 0; x < width; x++) {
                                     pos = y * width + x;
                                     pixColor = dst[pos]; // 获取图片当前点的像素值
                                     R = Color.red(pixColor); // 获取RGB三原色
                                     G = Color.green(pixColor);
                                     B = Color.blue(pixColor);
                                     pixel = R - G - B;
                                     pixel = pixel * 3 / 2;
    
    if (pixel < 0) pixel = -pixel; if (pixel > 255) pixel = 255;
    R
    = pixel; // 计算后重置R值,以下类同 pixel = G - B - R; pixel = pixel * 3 / 2;
    if (pixel < 0) pixel = -pixel; if (pixel > 255) pixel = 255;
    G
    = pixel; pixel = B - R - G; pixel = pixel * 3 / 2;
    if (pixel < 0) pixel = -pixel; if (pixel > 255) pixel = 255; B = pixel; dst[pos] = Color.rgb(R, G, B); // 重置当前点的像素值 } // x } // y bitmap.setPixels(dst, 0, width, 0, 0, width, height); return bitmap; }

    获取照片回调

    private final class TakePictureCallback implements PictureCallback {
                     @Override
                     public void onPictureTaken(byte[] data, Camera camera) {
                             try {
                                     Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,data.length);
                                     bitmap = ice(bitmap);
                                     File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis() + ".jpg");//保存在SD卡根目录下,以当前时间毫秒命名
                                     FileOutputStream outStream = new FileOutputStream(file);
                                     bitmap.compress(CompressFormat.JPEG, 100, outStream);
                                     outStream.close();
                                     camera.stopPreview();
                                     camera.startPreview();//重新开始照相预览
                             } catch (Exception e) {
                                     Log.e(TAG, e.toString());
                             }
                     }
             }

     解码

    static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
                     final int frameSize = width * height;
                     for (int j = 0, yp = 0; j < height; j++) {
                             int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
                             for (int i = 0; i < width; i++, yp++) {
                                     int y = (0xff & ((int) yuv420sp[yp])) - 16;
                                     if (y < 0)y = 0;
                                     if ((i & 1) == 0) {
                                             v = (0xff & yuv420sp[uvp++]) - 128;
                                             u = (0xff & yuv420sp[uvp++]) - 128;
                                     }
    
    int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0)r = 0; else if (r > 262143)r = 262143; if (g < 0)g = 0; else if (g > 262143)g = 262143; if (b < 0)b = 0; else if (b > 262143) b = 262143; rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); } } } }

    camera_view 代码:

    <?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" android:background="#000000">
             <SurfaceView android:id="@+id/camera_surface"
                     android:layout_height="fill_parent"
                     android:layout_width="fill_parent"
                     android:layout_weight="2.0" />
             <LinearLayout android:orientation="vertical"
                     android:layout_width="50dip"
                     android:layout_height="fill_parent"
                     android:gravity="center_vertical">
                     <ImageButton android:layout_width="48dip"
                             android:layout_height="48dip"
                             android:src="@android:drawable/ic_menu_camera"
                             android:id="@+id/take_picture" />
                     <View android:layout_width="40dip"
                         android:layout_height="fill_parent"
                         android:layout_weight="2.0"/>
             </LinearLayout>
     </LinearLayout>

    效果如下图:照相机冰冻效果

  • 相关阅读:
    线段树套线段树
    hdu6800
    半平面交 poj1279
    Unity:创建了一个自定义的找子物体的脚本
    Unity:一个简单的开门动画
    hdu 4940
    hdu 4939
    hdu 4932
    hdu 4912
    AC自动机
  • 原文地址:https://www.cnblogs.com/vus520/p/2561976.html
Copyright © 2020-2023  润新知