2017-01-30 83 views
11

如何在拍照时获取Android手机的AutoExposureCompensation级别(亮度)如何在拍照时通过Java手机从Android手机摄像头获得曝光补偿等级?

我可以拍照。我可以访问摄像机的参数,包括曝光补偿(当我检查时总是为零),但我需要在拍摄照片时获得自动曝光补偿等级,而不是在之前和之后。

背景:我希望在特定时间拍摄的所有照片都使用相同的自动曝光补偿等级拍摄照片。我不希望对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设备上查看目前正使用上述类代码:

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; 
} 
+0

你试图让AE当[ShutterCallback](https://developer.android.com/reference/android/hardware/ Camera.ShutterCallback.html)被解雇了吗? – NAmorim

+0

NAmorim 是的,我试过类似的东西。我正在研究传感器的曝光时间和传感器的灵敏度,以便让我知道我要去哪里。不知道这是否会起作用。但谢谢你看这个。 – Brian

+0

正在使用android.hardware.camera2 API一个选项?也许你会在这里找到一些东西:https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys() – Fildor

回答

3

我觉得camera2 API(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
  • 等待:

    1. 在自动曝光模式开始输出第一个被锁定的结果
    2. 将该结果的曝光设置复制到请求中,将请求设置为手动AE
    3. 提交捕获请求,根据需要继续运行手动AE。
  • 另外,作为每AE模式的描述(相同的源)

    当设置为任何的ON模式,由相机 设备自动曝光例程重写的所选择的值一个给定的 捕获的字段将在其CaptureResult中可用。

    所以一旦你做第一个CaptureRequest,您可以从以下回调使用TotalCaptureResult

    void onCaptureCompleted (CameraCaptureSession session, 
           CaptureRequest request, 
           TotalCaptureResult result) 
    { 
         int aecompensationlevel = result.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION) 
    } 
    
    +0

    好的,让我检查一下,看看它是否有效。我希望它有效;那会比我现在做的事情容易得多。 – Brian

    +0

    Manish, 它没有工作。我其实没有成功就尝试过。我不知道为什么,但CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION仅返回相机的默认设置“0”,即使在CaptureCallback(onCaptureComplete)事件中使用时也是如此。 Control_AE_Exposure_Compensation不起作用,但我会在此后发布工作。 – Brian

    0

    OK,我要这个回答自己对谁发现了类似的问题。

    Manish接近他的回答,但即使在onCaptureSession事件中使用时,CONTROL_AE_EXPOSURE_COMPENSATION也只返回0(零),这是没用的。这只是相机的默认初始值。

    但是,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()); 
    
          } 
         }; 
    

    下面是从我调试的结果的图片:

    enter image description here

    1

    OK,问题就来了了如何设置在编写代码来控制Android相机时具体说明曝光,传感器灵敏度和其他变量。这只适用于棒棒糖或更高版本。有很多代码需要发布,但是我会尝试放入高亮区域

    简而言之,我使用带有CameraManager的TextureView(AutoFitTextureView)。当我打开相机,我称之为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; 
    } 
    
    +0

    谢谢你的时间@Brian。由于我还是Android的新手,我无法弄清楚你在这里做了什么。你能否介绍一下你的工作?那真的很有帮助。 –

    +0

    有太多的代码可以帮助你做更多的事情。抱歉。 – Brian