这几天看到亚瑟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;@Overridepublic 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 {@Overridepublic 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());}}}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubif(camera!=null){camera.setPreviewCallback(null) ;camera.stopPreview();camera.release();camera = null;}super.onDestroy();}private final class SurfaceCallback implements SurfaceHolder.Callback {@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}@Overridepublic 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;}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if (camera != null) {if (preview)camera.stopPreview();camera.release();}} }@Overridepublic 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} // ybitmap.setPixels(dst, 0, width, 0, 0, width, height);return bitmap;}

获取照片回调

private final class TakePictureCallback implements PictureCallback {@Overridepublic 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>

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

转载于:https://www.cnblogs.com/vus520/archive/2012/04/12/2561976.html

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

  1. 优化tableView性能(针对滑动时出现卡的现象)

    优化tableView性能(针对滑动时出现卡的现象) 在iOS应用中,UITableView应该是使用率最高的视图之一了.iPod.时钟.日历.备忘录.Mail.天气.照片.电话.短信. Safari ...

  2. html上传动态图片不显示图片,解决 viewer.js 动态更新图片导致无法预览的问题

    前台页面要求图片的查看,是在表格中点击查看才弹出图片,网上发现用Viewer插件的挺多,就选用的这款插件,但是Viewer插件会产生缩略图,这里取巧了,将缩略图统一替换成了一个带有查看两字的小图片,这 ...

  3. html动态添加图片不显示不出来,解决 viewer.js 动态更新图片导致无法预览的问题...

    前台页面要求图片的查看,是在表格中点击查看才弹出图片,网上发现用Viewer插件的挺多,就选用的这款插件,但是Viewer插件会产生缩略图,这里取巧了,将缩略图统一替换成了一个带有查看两字的小图片,这 ...

  4. android 相机纹理,Android平台Camera实时滤镜实现方法探讨(五)--GLSurfaceView实现Camera预览...

    前面有一篇探讨了如何在片段着色器中将YUV数据转换为RGB数据并显示,但采用samplerExternalOES将SurfaceTexture作为OpenGL外部纹理,需要使用GL_TEXTURE_E ...

  5. Android视频滤镜添加硬解码方案

    由于工作的需求,研究过了一段时间的Android 的音视频播放渲染以及编辑方面的知识,这里就自己一些浅薄的了解对所了解做一个简单的介绍和记录,如有不对的地方请指正!同时也会记录下硬件解码的情况下完成滤 ...

  6. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——1.1 工程思路与难点

    回到目录 本文主要探讨搭建一款Android平台下美颜相机可能需要填的坑,内容会不断更新.. 相机框架 相机框架相对比较简单,现有的开源代码很多,可以很容易的实现拍照和录像的功能. 预览尺寸选择 预览 ...

  7. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——2.3 仿制Snow相机和FaceU的边框/小脸模式

    Github项目地址 回到目录 在体验各种美颜相机时,我发现FaceU和Snow相机都带一个小脸模式(或者边框模式),像这样的效果: 这是Snow相机的: 这是FaceU的: 两个看上去并不一样,因为 ...

  8. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——2.2 来一份LOMO滤镜

    Github项目地址 回到目录 了解了滤镜的基本知识以后,我们就可以试着来做我们的第一个滤镜了 虽然之前做过一个灰度滤镜,但是是采用直接修改片元着色器代码的方式,非常"不优雅",所 ...

  9. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——2.4 滤镜以及配套代码的制作方法

    Github项目地址 好久没有更新了,不行不行,怎么可以太监呢(`⌒´メ) 滤镜结构 滤镜主要是对于图像的处理,关于一款滤镜的制作方法可以看这里 既然是图像处理,那么滤镜的操作就主要是:卷积.像素映射 ...

最新文章

  1. 小度智能音响拆解 芯片_打磨小度智能音箱:深度拆解,发掘升级潜能
  2. 【引用】如何结束线程运行(转)
  3. tips:Java基本数据类型大小比较
  4. Java编程:动态规划
  5. Java中VO/DTO/DO/PO/POJO/BO/DAO概念及其区别
  6. 如何制作计算机启动盘,电脑怎么制作U盘启动盘
  7. 解析TCP/UDP协议的通讯软件
  8. 将Go语言编写的HttpServer部署到Docker并推送到DockerHub
  9. 抖音小程序开发 唤起收银台支付(可以选择支付宝APP支付或微信H5支付)
  10. 一个好中医就是一座全科医院
  11. win10 安装硕正
  12. 【MySQL作业】avg 和 count 函数——美和易思聚合函数应用习题
  13. 引用防删——JAVA设计模式总结之六大设计原则
  14. Calcite 原理解析
  15. MindMapper 与MindManager之间的区别
  16. 洛谷 P2357 守墓人(树状数组)
  17. 佳能mg3150pixma_升级到佳能Pixma MP500多功能喷墨打印机
  18. 正排索引和倒排索引的区别
  19. 软件开发周期(各个阶段)
  20. 将十六进制转化为十进制

热门文章

  1. javascript学习系列(12):数组中的join方法
  2. 前端学习(3053):vue+element今日头条管理-展示列表分页
  3. [css] 如何禁用移动的选择高亮?
  4. [js] 使用ajax轮询接口有什么优缺点?
  5. 前端学习(2656):vue2中用v-model实现
  6. 前端学习(2509):脚手架开发
  7. 前端学习(2505):小游戏设计
  8. 前端学习(2384):element介绍
  9. 前端学习(1266):axios的常见api
  10. 前端学习(1171):includes方法