Rotate resulting Camera Images when the Activity is fixed to portrait - android

I am making an application with a built in camera. The Activity is fixed to portrait orientation but I want to have the images saved properly right-side up, like so:
Camera camera = getCameraInstance(); //method found on http://developer.android.com/guide/topics/media/camera.html
Camera.Parameters params = camera.getParameters();
params.setRotation(someInteger); //I want to get the proper value for this method
camera.setParameters(params);
Has anyone been able to achieve this?

If you're just trying to rotate the JPEG images you receive from calling takePicture, then setRotation is the right method to use.
Is the question about what value to pass into setRotation? Assuming you want real-world 'up' to be 'up' in the saved JPEG image, setRotate needs to be set based on the current orientation of the camera sensor relative to the world.
You can find out what the relative orientation of the whole device to the world is, and you can find out what the orientation of the camera sensor is relative to the device's 'natural' orientation, and combine the two rotations into the final answer. The math is easy to get wrong, which is why we have it explicitly spelled out in the API documentation for setRotation, reproduced here:
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWNsetRotation) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
You'll need to inherit from OrientationEventListener and implement the above for the callback method. Of course, you should check that your camera is open, and that mParameters, etc, is valid before updating the parameters.
Please note that this only rotates the JPEGs that are sent out by the camera. If you see that your preview is not correctly oriented in your UI, you need to call setDisplayOrientation for that. The camera sensor is normally lined up with the landscape orientation of the device, so landscape camera apps can often get away without calling this function, even though they should in case they're on an unusual Android device. However, if you're writing a portrait app, it's likely mandatory you adjust the display orientation to align with your UI. As with setRotation, you need to take a few factors into account, and sample code for doing the math right is included in the documentation.

Related

How do we detect the Orientation of Image captured using CameraX if Application's default orientation is set to Portrait Mode

Basically, My camera app is set to Portrait Mode. However, user can take photos in Potrait or landscape by rotating the phone accordingly (The app doesnt rotate).
So my question is, how can we find the captured image orientation?
I tried using DisplayManager.DisplayListener, however, it works only when orientation of app happens. Since I have blocked the orientation of app to portrait mode, it doesnt get any callbacks here.
I even tried using ExifInterface, however, it always gives 6 as rotation.
I am looking for solution using CameraX apis.
I had this problem also. What solved it is by using the device sensor data to get the correct orientation, then set it in my imageCapture object. See snippet below.
orientationEventListener = object : OrientationEventListener(context) {
override fun onOrientationChanged(orientation: Int) {
// Monitors orientation values to determine the target rotation value
val rotation = if (orientation >= 45 && orientation < 135) {
Surface.ROTATION_270
} else if (orientation >= 135 && orientation < 225) {
Surface.ROTATION_180
} else if (orientation >= 225 && orientation < 315) {
Surface.ROTATION_90
} else {
Surface.ROTATION_0
}
imageCapture?.setTargetRotation(rotation)
}
}
This is also the recommended approach from a similar issue in the Google Issue Tracker: https://issuetracker.google.com/issues/144944155
Try out this same in our case ExifInterface did't work.
private int getImgimageOrientation(){
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
imageColumns, null, null, imageOrderBy);
if(cursor.moveToFirst()){
int orientation = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION));
cursor.close();
return orientation;
} else {
return 0;
}
}
Please follow the Official documentation of camerax:
By default, the camera rotation is set to match the default display's rotation during the creation of the use case. In this default case, CameraX produces outputs to allow the app to easily match what you would expect to see in the preview. You can change the rotation to a custom value to support multi-display devices by passing in the current display orientation when configuring use case objects or dynamically after they have been created.
You can use the default display rotation and/or the camerax metadata output combinations from Preview.PreviewOutput() to create transforms for GLSurfaceView display.
val previewConfig = PreviewConfig.Builder()
.setTargetRotation(windowManager.defaultDisplay.rotation)
.build()
Based on the set rotation, each use case will either rotate the image data directly or provide rotation metadata to the consumers of the non-rotated image data.
Preview: Metadata output is provided to create the right transforms
for a GLSurfaceView display using
Preview.PreviewOutput.getRotationDegrees().
ImageAnalysis: Metadata output is provided so that image buffer
coordinates are known relative to display coordinates. The analyze()
method provides a rotationDegrees parameter representing the rotation
that needs to be applied to the image analysis data to match the
viewfinder.
ImageCapture: The image Exif metadata will be altered to note the
rotation setting.

Front camera - Mirror and Rotate correctly before saving

I want to mirror my image of the front camera before saving it to the sd-card. The thing is on some devices like Sony Xperia Z5 it rotates the image with 90 degrees as well after mirroring.
I can't use the ExifInterface to get the orientation, because it requires a filepath and in my case i haven't saved it yet.
Is there any chance to get the orientation of the specific devices so i can rotate them properly?
Presetting:
Camera2 Api
Only Portrait Pictures
In your captureBuilder, you have a parameter to set the "Orientation" of the image before it is taked: CaptureRequest.JPEG_ORIENTATION
Android Developer website say:
The orientation for a JPEG image.
The clockwise rotation angle in degrees, relative to the orientation
to the camera, that the JPEG picture needs to be rotated by, to be
viewed upright.
Camera devices may either encode this value into the JPEG EXIF header,
or rotate the image data to match this orientation. When the image
data is rotated, the thumbnail data will also be rotated.
Note that this orientation is relative to the orientation of the
camera sensor, given by android.sensor.orientation.
You can set this parameter in your CaptureBuilder:
//To get the right orientation we must to get it in base of the sensor position.
mSensorOrientation = getSensorOrientation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mSensorOrientation);
Get your Sensor Orientation from your CameraCharacteristics, which you can get from CameraManager:
public int getSensorOrientation() throws CameraAccessException {
return mCameraManager.getCameraCharacteristics(mCameraId).get(
CameraCharacteristics.SENSOR_ORIENTATION);
}
Hope that it will help you!
EDIT:
I attach you a method that I found long time ago to get the "real" orientation for a picture, depending of if you are in frontal camera, the sensor device orientation and the orientation that you want to get for your picture.
public static int sensorToDeviceRotation(boolean mirror, int deviceOrientation, int sensorOrientation) {
// Reverse device orientation for front-facing cameras
if (mirror) {
deviceOrientation = -deviceOrientation;
}
// Calculate desired JPEG orientation relative to camera orientation to make
// the image upright relative to the device orientation
return (sensorOrientation + deviceOrientation + 360) % 360;
}

How can I ensure correct playback orientation of recorded video?

I'm using the MediaStore.ACTION_VIDEO_CAPTURE intent to capture video and later play it back using a VideoView. I would like to know the orientation of the video that was captured.
I don't want to use the orientation at the time of the intent call because the user may rotate the device prior to hitting the shutter button. I also don't want to implement my own custom video capture.
Is the orientation of the video stored in the saved file and/or returned in the intent result?
Is the orientation of the video stored in the saved file and/or returned in the intent result?
The AOSP VideoCamera activity does supply the rotation value of the camera device to the MediaRecorder.setOrientationHint() method. Here's an excerpt of the code in the VideoCamera.initializeRecorder() code related to this:
// See android.hardware.Camera.Parameters.setRotation for
// documentation.
// Note that mOrientation here is the device orientation, which is
// the opposite of what getWindowManager().getDefaultDisplay().getRotation()
// would return, which is the orientation the graphics need to rotate
// in order to render correctly.
int rotation = 0;
if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - mOrientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + mOrientation) % 360;
}
}
mMediaRecorder.setOrientationHint(rotation);
Here's the documentation for setOrientationHint() explaining the storage of the information:
Sets the orientation hint for output video playback. This method
should be called before prepare(). This method will not trigger the
source video frame to rotate during video recording, but to add a
composition matrix containing the rotation angle in the output video
if the output format is OutputFormat.THREE_GPP or OutputFormat.MPEG_4
so that a video player can choose the proper orientation for playback.
Note that some video players may choose to ignore the compostion
matrix in a video during playback.
Since you are using the framework's VideoView widget to playback the video, it should already handle the information in the composition matrix correctly and you should only need to compare the width and height of the video to decide whether to set a landscape or portrait orientation for your playback activity. One simple way to do this would be to just call ThumbnailUtils.createVideoThumbnail() (which internally uses MediaMetaDataRetriever) and check the resolution of the returned bitmap.
Similar to how al. suggested in his answer, I use the MediaMetadataRetriever but with the METADATA_KEY_VIDEO_ROTATION key:
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource( absoluteVideoFilePath );
String orientation = mediaMetadataRetriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION );
I checked capturing video with all 4 different orientations of the front camera, and the metadata is always different.
Note: METADATA_KEY_VIDEO_ROTATION needs API Level 17 or above.
You can use MediaMetadataRetriever to get the width and height of your video and figure out the orientation prior to loading it.

Android Camera SurfaceView Orientation

I am building an app that uses the android camera. I use a FrameLayout that has 2 children. The first child is a SurfaceView that previews the Camera and the second child is a LinearLayout with some buttons.
I have read that in Android 2.1 and below, the only way to use the camera is on Landscape mode, so I use
android:screenOrientation="landscape" android:configChanges="keyboardHidden|orientation"
in my activity in the manifest file.
Is there a way to use the SurfaceView (camera) in landscape mode only, and use the LinearLayout (buttons) either portrait/landscape?
(For example in Google Goggles the camera doesn't change orientation but the buttons rotate when changing orientation.)
The Camera app included in Android is in AOSP. Check the source out for yourself. From the looks of it, it's fixed in landscape mode as well, but simply rotates the ImageViews when the user changes the orientation.
See this part of Camera's source.
The best way to solve is like AOSP does by using RotateImageView and special ImageView that you can set a rotation in degrees.
So in your Camera Activity you have to implement OrientationListener and onOrientationChanged you set the new Degrees to your RotateImageView. Here is the simple way but you can look for a better example at Camera implementation at
private class MyOrientationEventListener extends OrientationEventListener {
public MyOrientationEventListener(Context context) {
super(context);
}
#Override
public void onOrientationChanged(int orientation) {
mOrientation = roundOrientation(orientation);
((RotateImageView)findViewById(R.id.btnFlash)).setDegree(mOrientation);
}
}
public static int roundOrientation(int orientation) {
return ((orientation + 45) / 90 * 90) % 360;
}

Using Camera in Portrait Orientation

I'm trying to develop an app which uses the Camera. So far it's been working well, except that I'm unable to force the orientation to be "portrait". It seems to work well if I force all activities to "landscape", because the camera preview seems to fit in landscape.
Is there anyway to use the Camera in portrait mode?
Android devices v2.2 and above contain and API to rotate the display to portrait. Devices below 2.2 are landscape only. Your best bet is to detect if the device is 2.2 and rotate 90 degrees. Fall back on landscape for devices under 2.2. The good news is most Android devices are on 2.2 and above.
Check out my answer here for more info:
Camera is wrong unless keyboard is open
public void surfaceCreated(SurfaceHolder holder)
{
// The Surface has been created, acquire the camera and tell it where to draw.
mCamera = Camera.open();
Parameters params = mCamera.getParameters();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE)
{
params.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
}
try
{
mCamera.setPreviewDisplay(holder);
}
catch (IOException exception)
{
mCamera.release();
mCamera = null;
}
}
edit: I was in the midst of Adobe AIR for Android development when I answered this question, and looking back at it, I realize this question didn't pertain to Adobe AIR.
Adobe says:
On devices that can change the screen orientation, such as mobile phones, a Video object attached to the camera will only show upright video in a landscape-aspect orientation. Thus, mobile apps should use a landscape orientation when displaying video and should not auto-rotate.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Camera.html
If you do really want to use the camera in portrait mode, my suggestion is to rotate the video object.
Here's some sample code that rotates the video object (_video) by an angle in degrees (source was pulled from elsewhere on stackoverflow):
var matrix:Matrix = _video.transform.matrix;
var rect:Rectangle = _video.getBounds(this);
matrix.translate(- (rect.left + (rect.width/2)), - (rect.top + (rect.height/2)));
matrix.rotate((angle/180)*Math.PI);
matrix.translate(rect.left + (rect.width/2), rect.top + (rect.height/2));
_video.transform.matrix = matrix;

Categories

Resources