android camera2 相機切換模糊效果實現

前言

最近有客戶反饋,camera2相機切換時,會黑屏一段時間很不美觀,影響體驗,客戶要求能夠像小米,華爲等品牌機一樣,中間有一個模糊的效果。
這個問題由於關聯問題比較多,包括,錄像,照相,半屏預覽,全屏預覽,第三方應用調用,以及google GMS 測試的問題。最後還是和客戶溝通掉了,不做修改。
但是,這裏我們需要知道,相機模糊的原理。

實現步驟

1.點擊切換時,獲取相機預覽的一幀。
2.獲取的幀,轉爲爲bitmap
3.在camera surfaceview 之上添加view ,並setBackground 爲步驟2中處理的bitmap

具體實現

1.獲取預覽幀

mCameraDevice.setOneShotPreviewCallback(mHandler, new CameraManager.CameraPreviewDataCallback() {
    @TargetApi(Build.VERSION_CODES.FROYO)
    @Override
    public void onPreviewFrame(byte[] data, CameraProxy camera) {
        Log.d(TAG,"wangjicong  onPreviewFrame");
        Camera.Size size = camera.getParameters().getPreviewSize();
        Log.d(TAG, "wangjicong size, width = " + size.width + " height = " + size.height);
        mYuvImage = null;
        mYuvImage = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);

通過setOneShotPreviewCallback 獲取data 幀數據,由於預覽數據時Yuv的,需要需要轉化爲得到YuvImage
2.通過 YuvImage 得到bitmap

ByteArrayOutputStream stream = new ByteArrayOutputStream();
//Log.d(TAG,"wangjicong blur bitmap  size.width = "+size.width+" size.height = "+size.height);
mYuvImage.compressToJpeg(new Rect(0, 0, mYuvImage.getWidth(), mYuvImage.getHeight()), 40, stream);
Bitmap bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

由於我們得到的bitmap,旋轉方向和我們手機屏時不同的,以及前攝情況下,bitmap存在鏡像,需要bitmap鏡像處理。

private Bitmap rotateBitmap(Bitmap origin, int rotate) {
    if (origin == null) {
        return null;
    }
    int width = origin.getWidth();
    int height = origin.getHeight();
    Matrix matrix = new Matrix();
    matrix.setRotate(rotate);
    if (rotate==-90){
        matrix.postScale(-1, 1);
    }
    Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
    if (newBM.equals(origin)) {
        return newBM;
    }
    origin.recycle();
    return newBM;
}

3.模糊處理
將我們步驟2中的旋轉,鏡像處理之後的bitmap 做模糊處理。

private static final float SCALE_DEGREE = 0.4f;
private static final float BLUR_RADIUS = 25f;
private HandlerThread mBlurHandlerThread;
private Handler mBlurHandler;
private YuvImage mYuvImage;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static Bitmap blur(Bitmap bitmap,Context context) {
    //計算圖片縮小的長寬
    int width = Math.round(bitmap.getWidth()*SCALE_DEGREE);
    int height = Math.round(bitmap.getHeight() * SCALE_DEGREE);
    //將縮小後的圖片作爲預渲染的圖片
    Bitmap inputBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
    //創建一張渲染後的輸入圖片
    Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
    //創建RenderScript內核對象
    RenderScript renderScript = RenderScript.create(context);
    //創建一個模糊效果的RenderScript的工具對象
    ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));

    /**
     * 由於RenderScript並沒有使用VM來分配內存,所以需要使用Allocation類來創建和分配內存空間。
     * 創建Allocation對象的時候其實內存是空的,需要使用copyTo()將數據填充進去。
     */
    Allocation inputAllocation = Allocation.createFromBitmap(renderScript, inputBitmap);
    Allocation outputAllocation = Allocation.createFromBitmap(renderScript, outputBitmap);

    //設置渲染的模糊程度,25f是最大模糊度
    scriptIntrinsicBlur.setRadius(BLUR_RADIUS);
    //設置ScriptIntrinsicBlur對象的輸入內存
    scriptIntrinsicBlur.setInput(inputAllocation);
    //將ScriptIntrinsicBlur輸出數據保存到輸出內存中
    scriptIntrinsicBlur.forEach(outputAllocation);

    //將數據填充到Allocation中
    outputAllocation.copyTo(outputBitmap);
    return  outputBitmap;
}

備註

由於bitmap處理比較耗時,這裏定義了一個private HandlerThread mBlurHandlerThread; 來處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章