Camera Preview distorted - android

I cannot help myself anymore, I have read every thread about this on stackoverflow, but nothing would fix my problem.
I try to set up my camera preview in a FrameLayout, everything works fine. I determine the correct size for the preview with this code:
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
Afterwards I apply it to my camera:
Camera.Parameters params = mCamera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, params);
params.setPreviewSize(size.width, size.height);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);
The Preview is still distorted afterwards, and my FrameLayout, which I expected to have the same size as the Preview Size I calculated, remains Fullscreen.
Fullscreen means 1920x1200
Preview Size means 1920x1080
So what I did is I set my Size of the FrameLayout manually to the calculated Preview Size. Then, however, my Preview looks even more skewed.
I have no idea what I am doing wrong. I thought when I use a supported Preview Size, this should not happen.
UPDATE:
I ran my application on another device, there everything works fine. Can this be a hardware bug? The device that is not working for me is the Nexus 7 Tablet.

I have finally come to a solution, this is really related to the hardware. There is a bug with some devices:
Bug-Report
The workaround:
This is a known low-level issue with some devices; they require that the still picture size and the preview size have matching aspect ratios, to avoid stretching artifacts.
If possible for your application, match the aspect ratios for setPreviewSize and setPictureSize.
Hope this helps you as well!

Related

Camera2 Api, Size object, getHeight method returns width and getWidth returns height

This doesn't make any sense to me as I said in the title. The method that should return the width returns 1920, and the method that should return the height returns 1080. Am I doing something wrong?
My camera activity is locked in portrait mode. My phone is a Samsung Note 4. Since my phone is in portrait mode and locked in that orientation, my height should be 1920 and my width 1080, however when I don't lock my camera activity in portrait mode, it still returns the wrong value, but when it is turned to landscape mode, the height is 1080 and the width is 1920.
My code:
mPreviewSize =
chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth,
rotatedHeight);
private static Size chooseOptimalSize(Size[] choices, int width, int
height) {
List<Size> bigEnough = new ArrayList<Size>();
for(Size option : choices) {
Log.d("detectivepikachu","option: h: "+option.getHeight()+" w:
"+option.getWidth());
if(option.getHeight() == option.getWidth() * height / width &&
option.getWidth() >= width && option.getHeight() >=
height) {
bigEnough.add(option);
}
}
if(bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizeByArea());
} else {
return choices[0];
}
}
You can rotate the texture, but camera hardware is still producing same images even in portrait mode. See Why camera2 supported preview size width always bigger than height? for more details.
If you use MediaRecorder to produce video, or employ ImageReader to capture the preview images on the fly, they will also arrive in the orientation dictated by camera hardware. To fit your device orientation, you must explicitly rotate them.

Android camera - taken picture inconsistent with preview

I'm having an issue with the camera on Android, basically when I take a photo with the Camera class, the taken output picture actually shows more than the preview. The best way to put it would be the preview is cropped. How would I fix this?
I've run the app on Samsung Galaxy S4, Samsung Galaxy S3, HTC One M8 and Nexus One and all exhibit this same issue. (All running Android 4.0 ICS)
The camera preview is full screen in an Activity with no Action Bar and the status bar hidden.
The camera i'm trying to create is portrait so I've set displayOrientation to 90.
The code I use for determining preview size and output photo size is as follows (I believe the problem is most likely here somewhere):
public static Camera.Size getBestAspectPreviewSize(int displayOrientation,
int width,
int height,
Camera.Parameters parameters,
double closeEnough) {
double targetRatio=(double)width / height;
Camera.Size optimalSize=null;
double minDiff=Double.MAX_VALUE;
if (displayOrientation == 90 || displayOrientation == 270) {
targetRatio=(double)height / width;
}
List<Size> sizes=parameters.getSupportedPreviewSizes();
Collections.sort(sizes,
Collections.reverseOrder(new SizeComparator()));
for (Size size : sizes) {
double ratio=(double)size.width / size.height;
if (Math.abs(ratio - targetRatio) < minDiff) {
optimalSize=size;
minDiff=Math.abs(ratio - targetRatio);
}
if (minDiff < closeEnough) {
break;
}
}
return(optimalSize);
}
public static Camera.Size getLargestPictureSize(CameraHost host,
Camera.Parameters parameters,
boolean enforceProfile) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
// android.util.Log.d("CWAC-Camera",
// String.format("%d x %d", size.width, size.height));
if (!enforceProfile
|| (size.height <= host.getDeviceProfile()
.getMaxPictureHeight() && size.height >= host.getDeviceProfile()
.getMinPictureHeight())) {
if (result == null) {
result=size;
}
else {
int resultArea=result.width * result.height;
int newArea=size.width * size.height;
if (newArea > resultArea) {
result=size;
}
}
}
}
if (result == null && enforceProfile) {
result=getLargestPictureSize(host, parameters, false);
}
return(result);
}
Size comparator class:
private static class SizeComparator implements
Comparator<Camera.Size> {
#Override
public int compare(Size lhs, Size rhs) {
int left=lhs.width * lhs.height;
int right=rhs.width * rhs.height;
if (left < right) {
return(-1);
}
else if (left > right) {
return(1);
}
return(0);
}
}
This is using cwac-camera and using SimpleCameraHost with no changes.
Any help is appreciated!
How would I fix this?
If you are using the full-bleed preview, the preview will be cropped in most cases, as the aspect ratio of the CameraView is unlikely to match the aspect ratio of the preview frames.
Quoting the documentation:
The original default behavior of CameraFragment and CameraView was to show the entire
preview, as supplied by the underlying Camera API. Since the aspect ratio of
the preview frames may be different than the aspect ratio of the CameraView,
this results in a "letterbox" effect, where the background will show through on
one axis on the sides.
The new default behavior is to completely fill the CameraView, at the cost of
cropping off some of the actual preview frame, what is known as "full-bleed preview"
(stealing some terminology from the world of print media).
To control this behavior:
Have your CameraHost
return true or false from useFullBleedPreview()
Or, call useFullBleedPreview()
on your SimpleCameraHost.Builder, passing in a boolean value to use by default.
Note that the pictures and videos taken by this library are unaffected by
useFullBleedPreview(). Hence, if useFullBleedPreview() returns true, the
picture or video may contain additional content on the edges that was not
visible in the preview.

How come that a camera preview in a textureview is much more fuzzy than in a surfaceview?

I have found out that when using a textureview instead of a surfaceview as a camera preview (both hooked up to the camera via a mediarecorder) then the preview is much more fuzzy.
What I mean by fuzzy is that in a texture view you can see the pixels, especially when zooming. That is not the case when using a surfaceview. Why is that the case?
UPD:
Sorry,but after I re-write my shit code, the key is the preview size too small that caused "fuzziness", so you should set a reasonable preview Size,not the reason strikeout below, but auto-focus is suggested ...
Size size = getBestSupportSize(parameters.getSupportedPreviewSizes(), width, height);
parameters.setPreviewSize(size.width, size.height);
As to the method getBestSupportSize(), how to get the bestSize for your project needs, in this case, it is as large as the screen width andhe ratio is 4/3 your's may be some other, I calculate the ration dividing width/height.
private Size getBestSupportSize(List<Size> sizes, int width, int height) {
Size bestsize = sizes.get(0);
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int dt = Integer.MAX_VALUE;
for (int i = sizes.size() - 1; i >= 0; i--) {
Log.d(TAG, "-index : " + i);
Size s = sizes.get(i);
if (s.width * 3.0f / 4 == s.height) {
int newDT = Math.abs(screenWidth - s.width);
if (newDT < dt && screenWidth < s.width) {
dt = newDT;
bestsize = s;
}
}
}
return bestsize;//note that if no "4/3" size supported,default return size[0]
}
So this "fuzziness" was caused by a small previewSize calcualate a best size for the camera using this getSupportedPreviewSizes() method
And I will keep the autoFocus snippet below, strikeout though, FYR if is needed.
Well i got the solution for this "fuzzy" problem,and my case is just using TextureView andsurfaceTexture to take a pic instead of old surfaceView withsurfaceHolderway.
The key is set this mCamera.autofocus(), why the pic is"fuzzy" is bacause we lack of this autoFocus setting.
like below :
mCamera.setPreviewTexture(surface);
//enable autoFocus if moving
mCamera.setAutoFocusMoveCallback(new AutoFocusMoveCallback() {
#Override
public void onAutoFocusMoving(boolean start, Camera camera) {
if (start) { //true means you are moving the camera
mCamera.autoFocus(myAutoFocus);
}
}
});
mCamera.startPreview();
The autoFocusCallback like this:
AutoFocusCallback myAutoFocus = new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
}
};

How to solve distorted image issue in android custom camera for galaxy S4

I am working on custom camera application for android. The problem is that the camera capture and showing preview good in other devices (example Samsung Galaxy S3) , but It shows distorted
image on Galaxy s4, Can any one help me??
My code for Picturesize() method is as follows:
Camera.Size getBestPicturSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result=null;
float dr = Float.MAX_VALUE;
float ratio = (float)width/(float)height;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
float r = (float)size.width/(float)size.height;
if( Math.abs(r - ratio) < dr && size.width <= width && size.height <= height ) {
dr = Math.abs(r - ratio);
result = size;
}
}
return result;
}
I had the same problem, if you mean that photos were taken with aspect ratio 4:3 and saved with aspect ratio 16:9 (they were outstretched). My problem was, that since I chose one of supported PictureSizes, I didn't do the same with the PreviewSizes.
Supported PictureSizes for Samsung G S4 are only with aspect ratio 16:9, however default PreviewSize was set to 1440x1080, which is 4:3. When I set both sizes with the same aspect ratio, picture was taken with no distortion.
Hope it will help.

RuntimeException on Camera.setParameters() on nexus one

I copied the code from the answer here and I still am getting a RuntimeException: setParameters failed error on my nexus one. My manifest file has camera and wake_lock permissions. This works on the emulator, and on the droid I don't get the error but it does have a rotation problem.
You're most likely requsting an invalid preview size. If you check the results of adb logcat you'll probably see something like this:
E/QualcommCameraHardware(22732): Invalid preview size requested: 480x724
The solution is to request the closest available preview size to the one you'd like; you can get a list of available preview sizes by calling getSupportedPreviewSizes in the Camera.Parameters object returned by Camera.getParameters.
I corrected this by doing what Roman said, with the code:
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size cs = sizes.get(0);
parameters.setPreviewSize(cs.width, cs.height);
camera.setParameters(parameters);
For what it's worth, the source of my issue ended up being that I was trying to call parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); without first verifying that flash modes were supported by checking that parameters.getFlashMode() != null.
There's more than one cause for this poorly documented exception, so check all of your parameters and not just that you're using a supportedPreviewSize.
None of the above solved this for me. Adding this code before setting the parameters did though.
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
//now set your parameters
For me this would happen after taking a photo and the preview would freeze, until I updated my call for parameters to be the following. It is always important with this error to make sure you check all of the parameters that the camera is asking to set to make sure that every parameter you are asking the camera to set itself to is possible for the camera.
Camera.Parameters parameters = myCamera.getParameters();
With the preview size:
if (myCamera.getParameters().getSupportedPreviewSizes() != null){
Camera.Size previewSize = getOptimalPreviewSize(myCamera.getParameters().getSupportedPreviewSizes(), width, height);;
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
With the flash/focus modes:
if(parameters.getSupportedFocusModes() != null && parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)){
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
if (parameters.getSupportedFlashModes() != null && parameters.getSupportedFlashModes().contains(Camera.Parameters.FLASH_MODE_AUTO)){
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
}
myCamera.setParameters(parameters);
etc. All of this wrapped in a nice try{}catch(){} works great. Good luck.
Here is the getOptimalPreview Size from this great tutorial:
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
Camera.Size optimalSize = null;
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) height / width;
// Try to find a size match which suits the whole screen minus the menu on the left.
for (Camera.Size size : sizes){
if (size.height != width) continue;
double ratio = (double) size.width / size.height;
if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE){
optimalSize = size;
}
}
// If we cannot find the one that matches the aspect ratio, ignore the requirement.
if (optimalSize == null) {
// TODO : Backup in case we don't get a size.
}
return optimalSize;
}
the solution from Sam is correct but the output image is still zoomed a little bit on several tablet devices. One of the best practices that I found on Internet, we should set in Camera host so that the properties will be re-used each time the camera is resumed. Here is implemented method in CameraHost:
#Override
public Parameters adjustPreviewParameters(Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size cs = sizes.get(0);
parameters.setPreviewSize(cs.width, cs.height);
return super.adjustPreviewParameters(parameters);
}
Some open source camera project like opencamera always use try-catch to call Camera.setParameters:
private void setCameraParameters(Camera.Parameters parameters) {
if( MyDebug.LOG )
Log.d(TAG, "setCameraParameters");
try {
camera.setParameters(parameters);
if( MyDebug.LOG )
Log.d(TAG, "done");
} catch (RuntimeException e) {
// just in case something has gone wrong
if( MyDebug.LOG )
Log.d(TAG, "failed to set parameters");
e.printStackTrace();
count_camera_parameters_exception++;
}
}
in addition,always get the latest getParameters before you call setParameters like this:
void setRotation(int rotation) {
Camera.Parameters parameters = this.getParameters();
parameters.setRotation(rotation);
setCameraParameters(parameters);
}

Categories

Resources