這幾天看到亞瑟boy的技術連載,也試着作了下帶濾鏡特效的照相機,效果也出來了,可是發現添加濾鏡特效後的預覽窗口卡屏現象很嚴重,因而本身索性 試着嘗試修改,在亞瑟和其餘網友的代碼中基本上都是對於照相機data視頻流先進行解碼,而後對解碼出的幀Bitmap進行濾鏡算法處理,這個是必走的流 程,而每一幀在處理解碼和濾鏡時都須要用掉大量時間,我測了下,解碼須要300毫秒左右,濾鏡處理須要600毫秒左右(冰凍濾鏡),如此一來,處理完這兩 個流程須要的時間要在900毫秒甚至更長,咱們知道若是看上去比較流暢的話咱們須要每秒更新三幀的圖片,而這麼處理只能更新一張,明顯的卡屏。android
因而試着去縮小處理的Bitmap大小,在照相機預覽返回照片大小中設置:算法
Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(display.getWidth()/2, display.getHeight()/2);// 設置預覽照片的大小
原來默認是返回屏幕大小的預覽圖片,此時我改爲了屏幕大小一半的圖片,發現處理過程明顯加快了(固然也有稍微的卡屏),最後在預覽回調接口 PreviewCallBack中再將圖片放大到屏幕大小,有雨我預覽圖片返回時只是縮小了一半,此時放大回屏幕大小時仍然是很是清晰的,若是你想速度更 快的話能夠繼續縮小預覽圖片的返回大小。canvas
代碼以下:ide
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); } } }
灰度效果(黑白照片)ui
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; }
冰凍特效this
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; }
獲取照片回調spa
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()); } } }
解碼code
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 代碼:orm
<?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>