2

I have tried a simple code from Android Dev. (https://developer.android.com/guide/topics/media/camera.html) which display a camera preview. However, when I run the app on my phone, the resolution is low (blurred). My Question is how to increase the resolution?

The Code I use is written below

public class CameraApp extends AppCompatActivity {
  Button captureButton;

  private static final String TAG = CameraApp.class.getSimpleName();

  private Camera mCamera;
  private CameraPreview mPreview;


  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera_app);

    // Create an instance of Camera
    mCamera = getCameraInstance();

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview);
    //previewHolder =

    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(R.id.button_capture);
    captureButton.setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // get an image from the camera
                    mCamera = getCameraInstance();
                    if (mCamera != null)
                        mCamera.takePicture(null, null, mPicture);
                }
            }
    );
}

private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Intent saveImageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        Uri savedImage = Uri.fromFile(pictureFile);
        saveImageIntent.putExtra(MediaStore.EXTRA_OUTPUT, savedImage);
        if (pictureFile == null) {
            Log.d(TAG, "Error creating media file, check storage permissions: ");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
        camera.startPreview();
    }
};


/**
 * Check if this device has a camera
 */
/*
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}*/

/**
 * A safe way to get an instance of the Camera object.
 */
public static Camera getCameraInstance() {
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    } catch (Exception e) {
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

/**
 * A basic Camera preview class
 */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            }
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        //holder.getSurface().release();



        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/**
 * Create a file Uri for saving an image or video
 */
private static Uri getOutputMediaFileUri(int type) {
    return Uri.fromFile(getOutputMediaFile(type));
}

/**
 * Create a File for saving an image or video
 */
private static File getOutputMediaFile(int type) {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
        mediaStorageDir.mkdirs();
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "IMG_" + timeStamp + ".jpg");
    } else if (type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "VID_" + timeStamp + ".mp4");
    } else {
        return null;
    }
    return mediaFile;
  }
}
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
user8447949
  • 43
  • 1
  • 7

1 Answers1

4

Please follow Picture distorted with Camera and getOptimalPreviewSize, which discusses how you should choose the supported preview size which is best for your screen (and layout). I gave more explanations here.

Here I paste for the future generations the best implementation I ever found, kudos to Shaked Klein Orbach:

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;
    if (sizes == null) {
        return null;
    }
    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;
    int targetHeight = h;
    for (Camera.Size size : sizes) {
        double ratio = (double) size.height / size.width;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
            continue;
        }
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

Note that you use deprecated hardware.Camera API. If your code does not primarily target older (pre-Lollipop) devices, consider switching to the new camera2 API. It can produce better images, and its performance is better. But the basic principles of choosing the optimal preview resolution stay the same.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Hi @AlexCohn, I tried the code but unfortunately the resolution is still low (blurred). Do you have any other idea?...Thank you – user8447949 Sep 03 '17 at 22:37
  • I am afraid you must disclose more details if you need help with this. At least: what is your device, what is the size of `camera_preview` frame, what resolution was chosen. – Alex Cohn Sep 04 '17 at 12:42
  • Device: Sony C5303 (Android 4.3, API 18) | Frame Size: both W. and H. are fill_parent | If you mean by resolution the output of getBestPreviewSize() then it is 480*320 – user8447949 Sep 05 '17 at 05:03
  • Note that I want the resolution to be high in all devices not only the device I mentioned...Thank you – user8447949 Sep 05 '17 at 05:10
  • My fault, I have copied a wrong link. This one should be better: https://gist.github.com/Shaked/f66134ea62755c0cbd69#file-getoptimalpreviewsize-java – Alex Cohn Sep 05 '17 at 11:12
  • 1
    I added the code you sent with the line: parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); and it was fine | Could you please update your answer so that I can credit it....Thank You Very Much – user8447949 Sep 11 '17 at 08:01
  • yes, keeping the picture in focus can improve image quality – Alex Cohn Sep 11 '17 at 09:35