Как получить уровень AutoExposureCompensation (яркость) с телефона Android , когда снимок сделан?
Я могу сделать снимок. Я могу получить доступ к параметрам камеры, включая компенсацию экспозиции (всегда ноль, когда я проверяю), но мне нужно получить уровень компенсации AE в момент, когда изображение будет снято, а не раньше и не позже.
Фон: я хочу, чтобы все снимки, сделанные в определенное время, использовали тот же уровень компенсации AE, что и фотографии. Я не хочу, чтобы эти сотни настроек уровня экспозиции или баланса белого, что обычно делают камеры для Android. Я хочу получить один раз и установить для всех последующих фотографий те же настройки.
Я попытался использовать "намерения" для изображений, OpenCV, фрагменты и т.д. Я не могу получить настройки компенсации AE ни с одним из них. Вот последний код, который я пробовал, начиная с расширенной версии JavaCameraView:
import org.opencv.android.JavaCameraView;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.Log;
@SuppressWarnings("deprecation")
public class NewJavaCameraView extends JavaCameraView implements PictureCallback {
public int getExposureCompensation(){
return mCamera.getParameters().getExposureCompensation();
}
@SuppressWarnings("deprecation")
public void takePicture(final String fileName) {
Log.i(TAG, "Taking picture");
this.mPictureFileName = fileName;
Camera.Parameters params = mCamera.getParameters();
int exposureComp = params.getExposureCompensation();
mCamera.setPreviewCallback(null);
// PictureCallback is implemented by the current class
int otherexposureComp =this.getExposureCompensation();
mCamera.takePicture(null, null, this);
}
@SuppressWarnings("deprecation")
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Camera.Parameters params = mCamera.getParameters();
int exposureComp = params.getExposureCompensation();
int otherexposureComp =this.getExposureCompensation();
mCamera.startPreview();
mCamera.setPreviewCallback(this);
// Write the image in a file (in jpeg format)
try {
FileOutputStream fos = new FileOutputStream(mPictureFileName);
fos.write(data);
fos.close();
} catch (java.io.IOException e) {
Log.e("Picture", "photoCallback", e);
}
}
Вот некоторые из кода Android View, которые используют вышеупомянутый класс:
public class DiscPhoto extends Activity implements CvCameraViewListener2, OnTouchListener {
private static final String TAG = "OCVSample::Activity";
private NewJavaCameraView mOpenCvCameraView;
private List<Size> mResolutionList;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
mOpenCvCameraView.setOnTouchListener(DiscPhoto.this);
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
public DiscPhoto() {
Log.i(TAG, "Instantiated new " + this.getClass());
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_disc_photo);
mOpenCvCameraView = (NewJavaCameraView) findViewById(R.id.discPhotoPage);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
@SuppressLint("SimpleDateFormat")
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG,"onTouch event");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateandTime = sdf.format(new Date());
String fileName = Environment.getExternalStorageDirectory().getPath() +
"/sample_picture_" + currentDateandTime + ".jpg";
mOpenCvCameraView.takePicture(fileName);
Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show();
return false;
}
Ответ 1
Я думаю, что API-интерфейсы camera2 (https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html) будет достаточным для вас.
Источник: https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html#CONTROL_AE_LOCK
Поскольку устройство камеры имеет конвейер запросов в полете, настройки, которые блокируются, не обязательно соответствуют настройкам которые присутствовали в последнем результате захвата, полученном от камеры, поскольку дополнительные записи и обновления AE могут иметь произошло еще до того, как был отправлен результат. Если приложение переключение между автоматическим и ручным управлением и желание устранить любое мерцание во время переключения, рекомендуется следующая процедура:
- Запуск в режиме авто-AE:
- Блокировка AE
- Подождите, пока будет выведен первый результат, который заблокирован AE
- Скопируйте настройки экспозиции из этого результата в запрос, установите запрос на ручной AE
- Отправьте запрос на захват, приступайте к выполнению ручного AE по желанию.
Также в соответствии с описанием режима AE (тот же источник)
При установке в любой из режимов ON значения, выбранные камерой процедура автоматического выключения устройства для переопределенных полей для заданного захват будет доступен в CaptureResult.
Итак, как только вы сделаете первый CaptureRequest, вы можете использовать TotalCaptureResult
из следующего обратного вызова:
void onCaptureCompleted (CameraCaptureSession session,
CaptureRequest request,
TotalCaptureResult result)
{
int aecompensationlevel = result.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION)
}
Ответ 2
ОК, возник вопрос, как установить конкретную экспозицию, чувствительность сенсора и другие переменные при написании кода для управления камерой Android. Это будет работать только на Lollipop или позже. Там много кода для публикации, но я постараюсь выделить основные моменты
Короче говоря, я использую TextureView (AutoFitTextureView) с CameraManager. Когда я открываю камеру, я вызываю функцию void, называемую createPreviewSessions()
void openCamera() {
try {
mManager.openCamera(mCameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
createPreviewSession();
}
}
private void createPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
final List<Surface> surfaceList = new ArrayList<>();
Surface surface = mImageReader.getSurface();
surfaceList.add(surface);
mCamera.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
mSession = session;
CaptureRequest request = createRequest(surfaceList, milliSecond, sensorSetting); //module variables
} ...
} ...
}
private CaptureRequest createRequest(List<Surface> surfaces, int milliSeconds, int sensorSetting) {
Log.v("createRequest","here");
try {
CaptureRequest.Builder builder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_OFF);
for (Surface surface : surfaces)
builder.addTarget(surface);
int exposureTime = milliSeconds * (milliSecondFactor); //billionth
CaptureRequestSettings.SetRequestBuilder(builder,CONTROL_AWB_MODE_DAYLIGHT);
builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, Long.valueOf(exposureTime)); //set hard values based on settings caught when photo taken
builder.set(CaptureRequest.SENSOR_SENSITIVITY, Integer.valueOf(sensorSetting)); //same thing
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
builder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF); //CaptureRequest.CONTROL_AWB_MODE_OFF); //off here just like video mode
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF); //off ... don't want auto exposure
return builder.build();
} catch (CameraAccessException e) {
Log.e("CaptureRequest", "CameraAccessException: " +e.getMessage());
} catch (Exception e) {
Log.e("CaptureRequest", "Regular Exception: " +e.getMessage());
}
Log.v("createRequest","shouldn't get here");
return null;
}
Ответ 3
Хорошо, я собираюсь ответить на это сам для тех, кто находит подобную проблему.
Маниш подошел близко к своему ответу, но даже когда он используется в событии onCaptureSession, возвращается только 0 (ноль) CONTROL_AE_EXPOSURE_COMPENSATION, что бесполезно; это просто начальное значение по умолчанию для камеры.
Однако CameraCaptureSession.CaptureCallback(событие onCaptureSession) позволяет вам получать значения из SENSOR_EXPOSURE_TIME и SENSOR_SENSITIVITY, чтобы создать проблему для автоматической экспозиции при работе с камерами Android.
Ниже приведен фрагмент кода, который я использовал:
private void captureStillPicture() {
try {
...
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
long sensorTime= result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
long sensorSensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY);
int ONE_SECOND = 1000000000; //1 billion nanoseconds
int MICRO_SECOND = 1000000;
int MILLI_SECOND = 1000;
String exposureText = "";
if (sensorTime > ONE_SECOND) {
exposureText = String.format("%.2f s", sensorTime / 1e9);
} else if (sensorTime > MILLI_SECOND) {
exposureText = String.format("%.2f ms", sensorTime / 1e6);
} else if (sensorTime > MICRO_SECOND) {
exposureText = String.format("%.2f us", sensorTime / 1e3);
} else {
exposureText = String.format("%d ns", sensorTime);
}
int aecompensationlevel=result.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION); //only returns zero
showToast("Saved: " + mFile +" | " +exposureText );
Log.d(TAG, mFile.toString());
}
};
Вот изображение результатов моего отладчика:
![введите описание изображения здесь]()