【问题标题】:How To Increase The Resolution In Camera Preview?如何提高相机预览中的分辨率?
【发布时间】:2017-09-03 05:05:13
【问题描述】:

我尝试了一个来自 Android Dev 的简单代码。 (https://developer.android.com/guide/topics/media/camera.html) 显示相机预览。但是,当我在手机上运行应用程序时,分辨率很低(模糊)。我的问题是如何提高分辨率?

我使用的代码写在下面

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;
  }
}

【问题讨论】:

    标签: android android-camera resolution


    【解决方案1】:

    请关注 Picture distorted with Camera and getOptimalPreviewSize,其中讨论了您应该如何选择最适合您的屏幕(和布局)的受支持的预览尺寸。我给了更多的解释here。

    在这里我为后代粘贴我找到的最好的implementation,向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;
    }
    

    请注意,您使用已弃用 hardware.Camera API。如果您的代码并非主要针对较旧的(Lollipop 之前的)设备,请考虑切换到新的 camera2 API。它可以产生更好的图像,并且它的性能更好。但选择最佳预览分辨率的基本原则保持不变。

    【讨论】:

    • 嗨@AlexCohn,我尝试了代码,但不幸的是分辨率仍然很低(模糊)。您还有其他想法吗?...谢谢
    • 如果您需要这方面的帮助,恐怕您必须披露更多细节。至少:你的设备是什么,camera_preview 帧的大小是多少,选择了什么分辨率。
    • 设备:Sony C5303 (Android 4.3, API 18) |帧大小:W. 和 H. 都是 fill_parent |如果您的意思是 getBestPreviewSize() 的输出分辨率,那么它是 480*320
    • 请注意,我希望所有设备的分辨率都很高,而不仅仅是我提到的设备...谢谢
    • 我添加了您发送的代码:parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);很好|您能否更新您的答案,以便我可以信任它....非常感谢您
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    相关资源
    最近更新 更多