Face Detection with camera2 works only in specific orientation (landscape) - android

I'm having trouble to enable Face Detection with android.hardware.camera2. It is recognizing faces only in landscape (only on that specific orientation).
App is coded to use only the Front camera and my activity is "locked" in portrait mode. However, it can detect faces only if device is on landscape.
I also tested allowing my activity to be rotated (default android behavior.. destroy/recreate). It did not change anything. Same result. So, I guess that's not the root cause.
Question
Do you have any similar issue and could fixed? Do you have any idea about how to fix it?
Details
Below is more information about my code... I configured only a preview session. I'm not interested in capture pictures at this moment... just wanna get a face detected regardless the device orientation (like any app).
I tested it in Samsung S7 and S8.. Result is the same in both devices:
Code to open camera (I always open the front camera...):
private void openCamera(final int width, final int height) {
final CameraManager cameraManager = (CameraManager) getSystemService(
Context.CAMERA_SERVICE);
if (cameraManager != null) {
....
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
cameraManager.openCamera(cameraId, mCameraStateCallback, null);
}
....
}
When camera is opened, I create my CaptureRequest
public void onOpened(#NonNull final CameraDevice cameraDevice) {
...
final SurfaceTexture texture = mTextureView.getSurfaceTexture();
if (texture != null) {
...
final Surface surface = new Surface(texture);
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mCameraDevice.createCaptureSession(Collections.singletonList(surface),
mSessionStateCallback, null);
}
...
}
Then, when session is configured, I set my CaptureRequest and start the session:
public void onConfigured(#NonNull final CameraCaptureSession cameraCaptureSession) {
...
// When the session is ready, we start displaying the preview.
mCameraCaptureSession = cameraCaptureSession;
// Set Face Detection to simple mode
mPreviewRequestBuilder.set(
CaptureRequest.STATISTICS_FACE_DETECT_MODE,
CameraMetadata.STATISTICS_FACE_DETECT_MODE_SIMPLE);
// Use face to control AF, exposure and white-balance
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
CaptureRequest.CONTROL_SCENE_MODE_FACE_PRIORITY);
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mCameraCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
mSessionCaptureCallback, mBackgroundHandler);
...
}
Here I try to read check the number of faces detected
public void onCaptureCompleted(#NonNull final CameraCaptureSession session,
#NonNull final CaptureRequest request, #NonNull final TotalCaptureResult result) {
final Integer mode = result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
final Face[] faces = result.get(CaptureResult.STATISTICS_FACES);
if(faces != null && mode != null) {
// IF DEVICE IS IN PORTRAIT, faces is not null but always have lenght == 0
// If DEVICE IS IN LANDSCAPE, faces is not null but return lenght == 1
}
}

Related

Camera 2 API Video Recording - Auto flash not working

I have implemented a custom camera that records a video using camera2 API. There is an option to set flash to "On", "off", and "Auto". Setting flash to "Auto" is not working while other options are working fine.
Here is the code :
private void updateFlash() {
Log.e(TAG, "Flash = " + currentFlash);
switch (currentFlash) {
case Constants.FLASH_OFF:
previewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_OFF);
break;
case Constants.FLASH_ON:
previewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
break;
case Constants.FLASH_TORCH:
previewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
break;
case Constants.FLASH_AUTO:
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
break;
}
cameraCaptureSession.setRepeatingRequest(previewRequestBuilder.build(),
null, null);
}
I have googled alot and tried almost all the stackoverflow answers for auto flash but none worked.
Please Help. I do not understand what is the issue.
I tricked! I wrote a ā€¨CaptureCallback and in onCaptureCompleted callback, I get AE_STATE and if AE_STATE is equal to CONTROL_AE_STATE_FLASH_REQUIRED then I turn on flash manually. This solution did not work for some devices such as Samsung J7 or Samsung A5. on devices Where AE_STATE returns null this solution wont work. HALF A LOAF is better than no bread. :)
private CameraCaptureSession.CaptureCallback captureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
if (previewFlashMode == FLASH_AUTO) {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState != null) {
if (currentPreviewFlashMode != FLASH_ON && aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED) {
setFlashMode(captureRequestBuilder, FLASH_ON);
setRepeatingRequestAfterSetFlash();
}
}
}
}
};
You should add the callback to setRepeatingRequest.

Check custom front camera availibility

I have been working on Custom SurfaceView Camera. I need to work with front camera as my application takes user's selfie.
For that I have checked a for whether front camera is available using below code.
public boolean checkFrontCamera() {
int numCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (CameraSource.CAMERA_FACING_FRONT == info.facing) {
return true;
}
}
return false;
}
Its working fine if device has both the camera, and it returns true. But if device has only one camera, this method always returns false as info.facing is 0 in this case and for the same in this code CameraSource.CAMERA_FACING_FRONT is 1.
for Camera, I have used gms vision library. Below code is for camera source.
CameraSource mCameraSource = new CameraSource.Builder(context, detector)
.setRequestedPreviewSize(640, 480)
.setFacing(CameraSource.CAMERA_FACING_FRONT)
.setRequestedFps(30.0f)
.build();
Here I need to pass camera facing params.
Please provide if any other alternative. All solutions are welcomed.
Well you can use this method, which returns the camera object
private Camera getCameraInstance() {
Camera c = null;
try {
if (Camera.getNumberOfCameras() >= 2) {
//Front facing camera
c = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else {
// only has one camera (Rear)
c = Camera.open();
}
} catch (Exception e) {
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}

Exception java.lang.RuntimeException: setParameters failed

I am getting following error
Exception java.lang.RuntimeException: setParameters failed
android.hardware.Camera.native_setParameters (Camera.java)
android.hardware.Camera.setParameters (Camera.java:1946)
in code below. I have no clue what wrong i am doing below.
Camera mCamera = Camera.open();
Parameters params = mCamera.getParameters();
if (params.getFlashMode() != null)
params.setFlashMode(Parameters.FLASH_MODE_OFF);
if (nightMode && params.getSceneMode() != null)
params.setSceneMode(Parameters.SCENE_MODE_NIGHT);
if (params.getSupportedFocusModes().contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
} else if (params.getSupportedFocusModes().contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Parameters.FOCUS_MODE_INFINITY);
}
mCamera.setParameters(params);
this error is occurring in some devices like samsung mostly.
Requesting for help.Thanks in advance.
Your params could be not supported by device. You can detect available focus modes with getSupportedFocusModes method of Camera.Parameters class. If some mode doesn't contain in this list, you can't set it to your camera.
Edit
As Alex said in comment you can see error message in logcat.
you must check if the focus mode supported by the user device, not all devices has camera focus mode, you do it like this:
public boolean support_focus(Camera camera){
Camera.Parameters parameters = camera.getParameters();
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))
return true;
else
return false;
}
this check if device support FOCUS_MODE_AUTO, change that with your desired Parameter.

Switch front and back camera2 in android

I am creating a camera in android using android.hardware.camera2...
I referred to this link
But, I do not know how to switch front camera and back camera.
Please give a advice!
First of all get the list of camera Ids from device
We can use CameraManager to iterate all the cameras that are available in the system, each with a designated cameraId. Using the cameraId, we can get the properties of the specified camera device. Those properties are represented by class CameraCharacteristics. Things like "is it front or back camera", "output resolutions supported" can be queried there.
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
return manager.getCameraIdList();
} catch (CameraAccessException e) {
return null;
}
Now if you want to open Front camera
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
//Do your code here (open Camera with Camera ID)
}
This is another method directly which return directly CameraId .
String getFrontFacingCameraId(CameraManager cManager){
for(final String cameraId : cManager.getCameraIdList()){
CameraCharacteristics characteristics = cManager.getCameraCharacteristics(cameraId);
int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if(cOrientation == CameraCharacteristics.LENS_FACING_FRONT) return cameraId;
}
return null;
}
For More Information about Camera2 Api you can see Here

How to switch Android back camera to front camera? [duplicate]

More generally, if a device has more than one embedded camera,
is there a way to initialize one of them in particular?
I didn't find it in Android reference documentation:
https://developer.android.com/reference/android/hardware/Camera.html
https://developer.android.com/reference/android/hardware/camera2/package-summary.html
https://developer.android.com/reference/android/hardware/camera2/CameraManager.html
Samsung SHW-M100S has two cameras. If there is no reference to use two cameras, any idea how Samsung did...?
private Camera openFrontFacingCameraGingerbread() {
int cameraCount = 0;
Camera cam = null;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
cam = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
return cam;
}
Add the following permissions in the AndroidManifest.xml file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
Note: This feature is available in Gingerbread(2.3) and Up Android Version.
All older answers' methods are deprecated by Google (supposedly because of troubles like this), since API 21 you need to use the Camera 2 API:
This class was deprecated in API level 21. We recommend using the new
android.hardware.camera2 API for new applications.
In the newer API you have almost complete power over the Android device camera and documentation explicitly advice to
String[] getCameraIdList()
and then use obtained CameraId to open the camera:
void openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)
99% of the frontal cameras have id = "1", and the back camera id = "0"
according to this:
Non-removable cameras use integers starting at 0 for their
identifiers, while removable cameras have a unique identifier for each
individual device, even if they are the same model.
However, this means if device situation is rare like just 1-frontal -camera tablet you need to count how many embedded cameras you have, and place the order of the camera by its importance ("0"). So CAMERA_FACING_FRONT == 1 CAMERA_FACING_BACK == 0, which implies that the back camera is more important than frontal.
I don't know about a uniform method to identify the frontal camera on all Android devices. Simply said, the Android OS inside the device can't really find out which camera is exactly where for some reasons: maybe the only camera hardcoded id is an integer representing its importance or maybe on some devices whichever side you turn will be .. "back".
Documentation: https://developer.android.com/reference/android/hardware/camera2/package-summary.html
Explicit Examples: https://github.com/googlesamples/android-Camera2Basic
For the older API (it is not recommended, because it will not work on modern phones newer Android version and transfer is a pain-in-the-arse). Just use the same Integer CameraID (1) to open frontal camera like in this answer:
cam = Camera.open(1);
If you trust OpenCV to do the camera part:
Inside
<org.opencv.android.JavaCameraView
../>
use the following for the frontal camera:
opencv:camera_id="1"
As of Android 2.1, Android only supports a single camera in its SDK. It is likely that this will be added in a future Android release.
To open the back camera:-
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA)
To open the front camera:-
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.O -> {
cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", CameraCharacteristics.LENS_FACING_FRONT) // Tested on API 24 Android version 7.0(Samsung S6)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", CameraCharacteristics.LENS_FACING_FRONT) // Tested on API 27 Android version 8.0(Nexus 6P)
cameraIntent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true)
}
else -> cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", 1) // Tested API 21 Android version 5.0.1(Samsung S4)
}
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA)
I could not make it work for API 28 and above. Also, opening the front camera directly is not possible in some devices(depends on the manufacturer).
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera = Camera.open();
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(holder);
Camera.Parameters p = mCamera.getParameters();
p.set("camera-id",2);
mCamera.setParameters(p);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
For API 21 (5.0) and later you can use the CameraManager API's
try {
String desiredCameraId = null;
for(String cameraId : mCameraIDsList) {
CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId);
List<CameraCharacteristics.Key<?>> keys = chars.getKeys();
try {
if(CameraCharacteristics.LENS_FACING_FRONT == chars.get(CameraCharacteristics.LENS_FACING)) {
// This is the one we want.
desiredCameraId = cameraId;
break;
}
} catch(IllegalArgumentException e) {
// This key not implemented, which is a bit of a pain. Either guess - assume the first one
// is rear, second one is front, or give up.
}
}
}
With the release of Android 2.3 (Gingerbread), you can now use the android.hardware.Camera class to get the number of cameras, information about a specific camera, and get a reference to a specific Camera. Check out the new Camera APIs here.
build.gradle
dependencies {
compile 'com.google.android.gms:play-services-vision:9.4.0+'
}
Set View
CameraSourcePreview mPreview = (CameraSourcePreview) findViewById(R.id.preview);
GraphicOverlay mGraphicOverlay = (GraphicOverlay) findViewById(R.id.faceOverlay);
CameraSource mCameraSource = new CameraSource.Builder(context, detector)
.setRequestedPreviewSize(640, 480)
.setFacing(CameraSource.CAMERA_FACING_FRONT)
.setRequestedFps(30.0f)
.build();
mPreview.start(mCameraSource, mGraphicOverlay);
Camera camera;
if (Camera.getNumberOfCameras() >= 2) {
//if you want to open front facing camera use this line
camera = Camera.open(CameraInfo.CAMERA_FACING_FRONT);
//if you want to use the back facing camera
camera = Camera.open(CameraInfo.CAMERA_FACING_BACK);
}
try {
camera.setPreviewDisplay("your surface holder here");
camera.startPreview();
} catch (Exception e) {
camera.release();
}
/* This is not the proper way, this is a solution for older devices that run Android 4.0 or older. This can be used for testing purposes, but not recommended for main development. This solution can be considered as a temporary solution only. But this solution has helped many so I don't intend to delete this answer*/
I found this works nicely.
fun frontCamera(context: Context): Int {
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
return cameraManager.cameraIdList
.find { id ->
cameraManager.getCameraCharacteristics(id)[LENS_FACING] == LENS_FACING_FRONT
}?.toInt() ?: 0
}

Categories

Resources