11

Jak uzyskać AutoExposureCompensation poziom (jasność) z telefonu Android , gdy zdjęcie jest zrobione?Jak uzyskać poziom kompensacji ekspozycji z aparatu telefonicznego z systemem Android, przez Javę, kiedy wykonywane jest zdjęcie?

Mogę zrobić zdjęcie. Mogę uzyskać dostęp do parametrów kamery, w tym do kompensacji ekspozycji (zawsze zerowej, gdy sprawdzam), ale muszę uzyskać poziom kompensacji AE w momencie robienia zdjęcia, a nie przed, a nie później.

Tło: Chcę, aby wszystkie zdjęcia zrobione o określonej porze używały tego samego poziomu kompensacji AE, co zdjęcia. Nie chcę tych setek korekt do poziomu ekspozycji ani balansu bieli, jakie zwykle robią aparaty z Androidem. Chcę uzyskać jeden raz i ustawić dla wszystkich kolejnych zdjęć, te same ustawienia.

Próbowałem używać "intencji" do zdjęć, OpenCV, fragmentów, itp. Nie mogę uzyskać ustawienia kompensacji AE z żadnym z nich. Oto najnowszy kod próbowałem, wychodząc z rozszerzoną wersję 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); 
    } 
} 

Oto niektóre kodu z Androidem View, który jest przy użyciu wyżej wymienionego Klasa:

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

Czy próbowałeś uzyskać AE gdy [ShutterCallback] (https://developer.android.com/reference/android/hardware/ Camera.ShutterCallback.html) jest uruchamiany? – NAmorim

+0

NAmorim Tak, próbowałem czegoś takiego. Zajmuję się czasem naświetlania czujnika i czułością czujnika, żeby dostać się tam, dokąd zmierzam. Nie jestem pewien, czy to zadziała, czy nie. Ale dzięki za patrzenie na to. – Brian

+0

Czy korzystanie z interfejsu API Android.hardware.camera2 jest opcją? Może znajdziesz coś tutaj: https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys() – Fildor

Odpowiedz

3

myślę camera2 Interfejsy API (https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html) będą wystarczające.

Źródło: https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html#CONTROL_AE_LOCK

Ponieważ urządzenie Aparat posiada rurociąg wniosków w locie, ustawienia że zablokowane różnić ustawień , które były obecne w najnowszej wyniku wychwytu otrzymanych od urządzenie kamery , ponieważ dodatkowe przechwytywania i aktualizacje AE mogły mieć wartość , nawet zanim wynik został wysłany. Jeśli aplikacja jest przełączanie między trybem automatycznym i ręcznym sterowaniem i pragnie wyeliminować żadnego migotania podczas przełącznika, zalecana jest następująca procedura:

  1. Uruchamianie w trybie auto-AE:
  2. blokady AE
  3. Wait aby pierwszy wynik był wydrukowany z blokadą AE
  4. Skopiuj ustawienia ekspozycji z tego wyniku do żądania, ustaw żądanie na ręczne AE
  5. Prześlij żądanie przechwytywania, postępuj zgodnie z wymaganiami.

Również według opisu trybu AE (to samo źródło)

Po ustawieniu dowolnego z trybów, wartości wybrane przez aparat urządzenia automatycznej ekspozycji rutyny dla przesłonięte pola dla danego przechwycenia będą dostępne w CaptureResult.

Więc kiedy zrobić pierwszy CaptureRequest, można użyć TotalCaptureResult z następującym zwrotnego:

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

OK, pozwól mi to sprawdzić i sprawdź, czy działa. Mam nadzieję, że to działa; byłoby to o wiele łatwiejsze niż to, co teraz robię. – Brian

+0

Manish, To nie zadziałało. Próbowałem tego wcześniej, bez powodzenia. Nie wiem dlaczego, ale CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION zwraca tylko "0", domyślne ustawienie kamery, nawet jeśli jest używane w zdarzeniu CaptureCallback (onCaptureComplete). Control_AE_Exposure_Compensation nie działa, ale opublikuję pracę po tym. – Brian

0

OK, idę do siebie za to odpowiedzieć, kto znajdzie się podobny problem.

Manish zbliżył się do swojej odpowiedzi, ale nawet jeśli użyto go w zdarzeniu onCaptureSession, zwracane jest tylko 0 (zero) przez CONTROL_AE_EXPOSURE_COMPENSATION, co jest bezużyteczne; to tylko domyślna wartość początkowa dla kamery.

Jednak CameraCaptureSession.CaptureCallback (zdarzenie onCaptureSession) pozwala uzyskać wartości z SENSOR_EXPOSURE_TIME i SENSOR_SENSITIVITY, aby stworzyć pracę związaną z problemem z automatyczną ekspozycją związaną z pracą z kamerami z systemem Android.

Poniżej znajduje się fragment kodu użyłem:

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()); 

      } 
     }; 

Oto zdjęcie z wynikami mojego debugger:

enter image description here

1

OK, pytanie wymyślił, jak ustawić w betonowanie ekspozycji, czułości czujnika i innych zmiennych podczas pisania kodu w celu sterowania kamerą z Androidem. To zadziała tylko w Lollipop lub później. Jest wiele kodu do opublikowania, ale postaram się umieścić najciekawsze zdjęcia.

W skrócie używam TextureView (AutoFitTextureView) z CameraManager. Kiedy otworzyć aparat, wzywam funkcję void zwane 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

Dziękuję za Twój czas @Brian. Ponieważ wciąż jestem nowicjuszem w Androidzie, nie jestem w stanie uzyskać jasnego obrazu tego, co tu zrobiliście. Czy możesz rzucić trochę światła na swoją pracę? To byłoby naprawdę pomocne. –

+0

Za dużo kodu zaangażowanego, aby pomóc Ci znacznie dalej. Przepraszam. – Brian

Powiązane problemy