I'm using this camera code to ask the camera to rotate the captured image data:
Camera.Parameters params = camera.getParameters();
params.set("rotation", 90);
camera.setParameters(params);
this seems to work on all phones, except the Droid. Has anyone else seen this? The image data is always landscape, however, the native camera app on the Droid produces portrait images ok.
I wonder if the Droid will only respect the new Camera.Parameters.setRotation() method, but this seems to only be available in API level 5?
setRotation also didn't seem to work for me on Nexus One, but I did get image rotation to work by following the example of the android Camera app itself.
The source code is available here:
https://android.googlesource.com/platform/packages/apps/Camera
Start with the Camera.java, but you'll also be looking at ImageManager.java, Util.java, and other files.
The basic idea is, you listen for orientation changes and capture what the orientation is at the time you snapped the picture. Then, when you get the picture bytes in the callback, you manipulate the bitmap, doing a rotation on the bitmap. Then convert the rotated bitmap back to jpeg. When you are done, you'll have had to copy a shocking amount of code from the camera app just for this rotation.
The rotation may just be stored in the jpeg exif header as explained in the setRotation document. On Droid that is actually the case. You can use jpeg header reading tools like jhead to verify this. You can also use the ExifInterface API to read the orientation tag in your program.
The Droid runs Android 2.0 (well, now 2.0.1) which are API levels 5 and 6, respectively.
So it's quite possible that the Droid only respects the (more sensible) 2.0+ API for rotation.
However, I guess your concern is compatibility across a range of device types and OS versions, so I imagine you would have to invoke the 2.0+ API via reflection after detecting the OS version (using android.os.Build.VERSION_CODES).
Related
I have tried writing my own code for accessing camera via the camera2 API on Android instead of using the Google's example. On one hand, I've wasted way too much time understanding what exactly is going on, but on the other hand, I have noticed something quite weird:
I want the camera to produce vertical images. However, despite the fact that the ImageReader is initialized with height larger than width, the Image that I get in the onCaptureCompleted has the same size, except it is rotated 90 degrees. I was struggling trying to understand my mistake, so I went exploring Google's code. And what I have found is that their images are rotated 90 degrees as well! They compensate for that by setting a JPEG_ORIENTATION key in the CaptureRequestBuilder (if you comment that single line, the images that get saved will be rotated). This is unrelated to device orientation - in my case, screen rotation is disabled for the app entirely.
The problem is that for the purposes of the app I am making I need a non-compressed precise data from camera, so since JPEG a) compresses images b) with losses, I cannot use it. Instead I use the YUV_420_888 format which I later convert to a Bitmap. But while the JPEG_ORIENTATION flag can fix the orientation for JPEG images, it seems to do nothing for YUV ones. So how do I get the images to be correctly rotated?
One obvious solution is to rotate the resulting Bitmap, but I'm unsure what angle should I rotate it by on different devices. And more importantly, what causes such strange behavior?
Update: rotating the Bitmap and scaling it to proper size takes way too much time for the preview (the context is as follows: I need both high-res images from camera to process and a downscaled version of these same images in preview. Let's just say I'm making something similar to QR code recognition). I have even tried using RenderScripts to manipulate the image efficiently, but this is still too long. Also, I've read here that when I set multiple output surfaces simultaneously, the same resolution will be used for all of them, which is quite bad for me.
Android stores every image, no matter if it is taken in landscape or in portrait, in landscape mode. It also stores metadata that tells you if the image should be displayed in portrait or landscape.
If you don'r turn the image according to the metadata, you will end up with every image in landscape. I had that problem too (but I wanted compression so my solution doesn't work for you).
You need to read the metadata and turn it accordingly.
I hope this helps at least a bit.
I am making an app using Camera API.Although I can capture images, they are not orientated properly.I already tried using screen orientation to correctly orient the images, but it dosent work on all devices especially on front camera.I am new to android development, any help would be appreciated.Thankyou.
You can get rotation of captured bitmap using ExifInterface and create another bitmap with fixed rotation - here you can find example of usage.
Moreover, I recommend to use inBitmap option for reusing existing bitmap into created rotated one.
Camera1 and Camera2 APIs are kinda tricky ones.It is useful to know how they work inside but there are plenty of ready solutions. I can recommend the following ones:
https://camerakit.io - has fixes for rotation issues inside but
currently in beta, supports Camera2 features.
https://github.com/RedApparat/Fotoapparat - based on Camera1.
https://github.com/natario1/CameraView - based on Camera1, can
capture video.
I am trying to capture a high resolution frame (1280x720) from the camera in a pair of Google Glass using OpenCV 2.4.10 for Android. I have implemented the CameraBridgeViewBase.CvCameraViewListener2 in my Activity and try to grab the frame in the onCameraFrame method. So far everything works well, and i get a 512x288 Mat object.
My problem is that the 512x288 resolution is not high enough for what I need. So I tried to setup my project the same way as they do in Sample 3 that follows with OpenCV: http://goo.gl/iDyqQj. The problem is that it only works for resolutions below 512x288, as soon as I increase the resolution above this level it defaults back to to being 512x288 (without any notice).
I found some suggestions, http://goo.gl/X2wtM4, that OpenCV is restricting the frame size to a maximum of the screen resolution. But the Google Glass screen should have a 640x360 resolution? I tried to do as described in the answer, but when I override calculateCameraFrameSize and return a Size-object larger than 512x288, I get a distorted frame (but with the larger dimensions, see below).
Does anyone have a suggestion on how capture a higher captured resolution on the Google Glass using OpenCV?
So I found a solution. It seem to be two separate problems. As I thought in my question you need to override calculateCameraFrameSize in JavaCameraView to be able to fetch higher resolutions than the device's screen in onCameraFrame. This is apparently a design choice by OpenCV and have been since version 2.4.5. So this is why I could not get a frame with higher resolution.
Even though I now can get a frame with higher resolution, it still is distorted for most preview sizes. This is a bug in the GDK that seem to have been known for quite some time (since XE10 if I understood correctly), but still is not fixed. Fortunately there is a workaround! The issue is avoided by manually setting the FPS of the preview using setPreviewFpsRange after you acquire the Camera.
Camera.Parameters params = camera.getParameters();
params.setPreviewFpsRange(30000, 30000);
camera.setParameters(params);
I'm working on an Android app that shows a camera preview. Ideally I'd like the app to work in portrait mode, which means I need to deal with rotation of the camera preview image.
I only need to support API level 8 (Android version 2.2) and up, so I can use Camera.setDisplayOrientation to set the orientation, and the API docs for that method include a setDisplayOrientation function that does what I want. The only problem is that it uses the API Level 9 Camera.CameraInfo to get the orientation of the camera with respect to the device (presumably to deal with landscape vs portrait devices).
So is it safe to assume that I can do setDisplayOrientation(90) for all level 8 devices and just use CameraInfo.orientation for newer devices?
I have tried the following on an HTC Evo Shift with a project set to API8 (worked great):
Configuration cfg = mContext.getResources().getConfiguration();
if (cfg.orientation == Configuration.ORIENTATION_PORTRAIT) {
mCamera.setDisplayOrientation(90);
}
As a follow up for anyone else finding this - I didn't find a definitive answer on this, so I did as I suggested above (setDisplayOrientation(90)) for 2.2 devices and released the app. It's had about 70,000 downloads and no reports of the camera display being wrongly rotated by 90 degrees, so it looks like this is a reasonable solution.
I'm posting the link to Android's developers help in the Camera matter:
http://developer.android.com/guide/topics/media/camera.html
About your question in specific, i took a look at the API and i guess, since the surfaceChanged method is called every time a change in surface is made and the equipment have only 2 position, you are probably right, since u implement the corrected methods in the surfaceChanged method. Try to implement it and if you can't get it to work post the problem and i'll try to help more.
I changed the zxing code a little bit so in CaptureActivity.java, Bitmap barcode can be returned to my main app through an intent (I encode the bitmap using base64 and pass a string for the intent). Anyways, the problem is that barcode has a very low resolution and I'm trying to figure out if it's possible to return the preview picture (barcode) with a higher resolution (or have the width and height be greater then the preview frame).
Thanks
Sure you can do this if the device supports a preview resolution later than the screen. The app will already do this as of tthe latest version and use a little more resolution this way. Note that the LG Optimus has a notorious bug that will prevent it from working if you do this.
You don't want tto make the reticle larger or it will induce the user to hold the barcode too close to focus.