一、問題描述
1.部分手機在弱光環境下不管什麼分辨率,預覽和拍出來的照片都非常的暗
2.部分手機在弱光環境下,預覽分辨率1920x1080,輸出圖片分辨率1920x1080時,預覽和拍出來的照片亮度比較亮,但是在預覽分辨率1920x1080,輸出圖片分辨率4000x2250時,預覽和拍出來的照片都非常暗
3.不是調整曝光度(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION)能解決的問題,增加曝光值只是使畫面變得更加蒼白,沒有讓場景本身變得亮起來。
二、解決方案
1.通過設置曝光時間範圍(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE),增加感光元件的曝光時間,接收到更多的光線,使得弱光場景下拍的更亮。
這是調整FPS範圍爲[15,15]時拍攝的效果和之前較暗時效果的對比。
這裏參考了鏈接https://stackoverflow.com/questions/28429071/camera-preview-is-too-dark-in-low-light-android/49643140#49643140 其中的這個回答:
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, getRange());//This line of code is used for adjusting the fps range and fixing the dark preview
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
最終我的預覽previewBuilder相關設置如下:
//設置預覽請求的方式
previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
...
//自動對焦
previewBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
//設置自動曝光幀率範圍
previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,getRange());
//對焦觸發器設置爲空閒狀態
previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
captureSession.setRepeatingRequest(previewBuilder.build(),captureCallback, mainHandler);
private Range<Integer> getRange() {
CameraManager mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics chars = null;
try {
chars = mCameraManager.getCameraCharacteristics(cameraID);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Range<Integer>[] ranges = chars.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
Range<Integer> result = null;
for (Range<Integer> range : ranges) {
//幀率不能太低,大於10
if (range.getLower()<10)
continue;
if (result==null)
result = range;
//FPS下限小於15,弱光時能保證足夠曝光時間,提高亮度。range範圍跨度越大越好,光源足夠時FPS較高,預覽更流暢,光源不夠時FPS較低,亮度更好。
else if (range.getLower()<=15 && (range.getUpper()-range.getLower())>(result.getUpper()-result.getLower()))
result = range;
}
return result;
}
實際代碼中我設置的自動曝光FPS範圍是[10,30],理由是,FPS下限越小,曝光時間越長,那麼接收到的光線越多,拍出來的場景就越亮。FPS的範圍需要有一定的跨度是因爲,FPS太小的時候,比如10,預覽會比較卡,體驗沒那麼好,如果範圍設置成[15,15]這種,全程都很卡。跨度大一點,在光線足夠的時候,FPS會升上去,就不卡了。因爲拍照其實對預覽的幀率要求沒有錄像高,因此犧牲一些幀率大大的提高感光度是可以接受的。關於錄像使用這種方式會比較卡頓的問題,後面會講另一個辦法。
這裏我的代碼中沒有用到CONTROL_AE_LOCK,有些人可能設置了預覽拍照的時候鎖定曝光,或者手動調曝光模式,需要注意了。這個方法是不會起作用,因爲他是設置在自動曝光模式下的FPS範圍,你可能需要設置曝光模式在非鎖定狀態下或自動曝光模式下,才能起作用。
最後,如果預覽的時候亮度正常了,拍照時還是比較暗,需要在拍照的CaptureRequest.Builder也進行這樣的設置。
2.設置預覽請求方式爲CameraDevice.TEMPLATE_RECORD,優先保證穩定的幀率,犧牲畫面的質量。
previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
設置這種預覽請求方式後,即使不設置曝光的FPS範圍,也能在弱光環境下看到比較亮的場景,但是,明顯的感覺到,噪點變多了,畫面沒那麼清晰了,可以做個切換,對比一下畫質。這時也可以去設置曝光FPS的範圍,但是作用不大,甚至讓本來流暢的預覽變得更卡。
最終我的處理是,拍照的時候,預覽方式是CameraDevice.TEMPLATE_PREVIEW,畫質更清晰,弱光時幀率稍低一點,光線足夠時幀率比較流暢。預覽和拍出來的照片亮度都很好。錄製視頻時,預覽方式是CameraDevice.TEMPLATE_RECORD,畫質稍差,無需設置曝光FPS範圍。幀率能夠全程保持流暢,弱光環境下視頻效果也比較亮。
比較了一下輕顏相機,它採取的應該是統一使用CameraDevice.TEMPLATE_RECORD的預覽方式。