Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Picture distorted with Camera and getOptimalPreviewSize

I am on a Camera App which taking basic pictures. I have an issue when I get the best optimal preview size.

In fact, with this first code :

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }
    Camera.Parameters parameters = mCamera.getParameters();
    mCamera.setParameters(parameters);
    mCamera.startPreview();
    isPreviewRunning = true;
}

The picture has a good quality :

http://img689.imageshack.us/i/04042011172937.jpg/

But, with this code :

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.05;
    double targetRatio = (double) w / h;
    if (sizes == null) return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // Now that the size is known, set up the camera parameters and begin
    // the preview.
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }
    Camera.Parameters parameters = mCamera.getParameters();

    List<Size> sizes = parameters.getSupportedPreviewSizes();
    Size optimalSize = getOptimalPreviewSize(sizes, w, h);
    parameters.setPreviewSize(optimalSize.width, optimalSize.height);

    mCamera.setParameters(parameters);
    mCamera.startPreview();
    isPreviewRunning =true;
}

The picture is totally distorted :

http://img97.imageshack.us/i/04042011173220.jpg/

How can I resolve this problem??

I am using a HTC Desire HD.

It is probably my saving method too ? :

PictureCallback mPictureCallbackJpeg = new PictureCallback() {      
        public void onPictureTaken(byte[] imageData, Camera camera) {
    ....

    BitmapFactory.Options options=new BitmapFactory.Options();
                            options.inSampleSize = 5; 
                            Bitmap myImage = BitmapFactory.decodeByteArray(imageData, 0,imageData.length,options);
                            FileOutputStream fOut = new FileOutputStream(path + "/"+fl);
                            BufferedOutputStream bos = new BufferedOutputStream(fOut);


    myImage.compress(CompressFormat.JPEG, 100, bos);
    bos.flush();
    bos.close();
    ....
}

Thanks

like image 915
jc_35 Avatar asked Apr 04 '11 15:04

jc_35


2 Answers

I just suffered through the same problem, and came up with a similar but lighter weight solution. I don't see anything wrong with your saving method though.

private Camera.Size getBestPreviewSize(int width, int height)
{
        Camera.Size result=null;    
        Camera.Parameters p = camera.getParameters();
        for (Camera.Size size : p.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;

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    //This line helped me set the preview Display Orientation to Portrait
            //Only works API Level 8 and higher unfortunately.

    camera.setDisplayOrientation(90);

    Camera.Parameters parameters = camera.getParameters();
    Camera.Size size = getBestPreviewSize(width, height);
    parameters.setPreviewSize(size.width, size.height);
    camera.setParameters(parameters);
    camera.startPreview();

}
like image 77
Seantron Avatar answered Oct 20 '22 01:10

Seantron


The best way is to get preview size with the closest aspect ratio:

Camera.Size getBestPreviewSize(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;
    }

Where width and height parameters are your surface size.

like image 26
Max Avatar answered Oct 20 '22 01:10

Max