0
回答
照相机滤镜使用,优化解码和滤镜导致的预览卡屏现象
终于搞明白,存储TCO原来是这样算的>>>   

这几天看到亚瑟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 view; 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(); // 开始预览 view = true ; } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (camera != null ) { if (view) 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.comss(ComssFormat.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>

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

 

 


原文链接:http://www.cnblogs.com/vus520/archive/2012/04/12/2561976.html
<无标签>
举报
长平狐
发帖于5年前 0回/442阅
顶部