相机表面视图图像看起来拉伸

问题描述 投票:15回答:6

在纵向模式下,图像看起来垂直拉伸,在横向模式下,它看起来水平拉伸。

虽然捕获图像后显示的大小合适。

如何解决这个问题?

android android-camera
6个回答
8
投票

您需要选择与您的显示尺寸相匹配的预览尺寸。我建议更改预览大小设置以匹配您的SurfaceView而不是相反。虽然预览数据很好,但它没有扭曲,当它投射到具有不同宽高比的表面时会看起来扭曲。

如果您有全屏视图,那么您应该会发现相机的预览尺寸与该尺寸相匹配 - 至少会有一个具有相同宽高比的相机。例如,如果您的屏幕是640x480,那么320x240预览尺寸将不会在全屏SurfaceView上显示。


4
投票

您必须根据(1)可用预览尺寸(2)视图来约束预览尺寸。如果您仍然需要,我的解决方案如下:

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

    private void startPreview() {
        try {
        /**
         * Orientation should be adjusted, see http://stackoverflow.com/questions/20064793/how-to-fix-camera-orientation/26979987#26979987
         */

            Camera.Parameters parameters = mCamera.getParameters();
            List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
            Camera.Size previewSize = null;
            float closestRatio = Float.MAX_VALUE;

            int targetPreviewWidth = isLandscape() ? getWidth() : getHeight();
            int targetPreviewHeight = isLandscape() ? getHeight() : getWidth();
            float targetRatio = targetPreviewWidth / (float) targetPreviewHeight;

            Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio);
            for (Camera.Size candidateSize : previewSizes) {
                float whRatio = candidateSize.width / (float) candidateSize.height;
                if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) {
                    closestRatio = whRatio;
                    previewSize = candidateSize;
                }
            }

            Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height);
            parameters.setPreviewSize(previewSize.width, previewSize.height);
            mCamera.setParameters(parameters);
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }
 }

3
投票

我在调用camera.startPreview()之前添加了这个来修复它:

Camera.Parameters parameters = camera.getParameters(); 
parameters.setPreviewSize(yourSurfaceView.getWidth(), yourSurfaceView.getHeight());
camera.setParameters(parameters);

它可能对某人有帮助。


0
投票

只需添加以下功能即可设置宽高比和预览大小

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

    if (sizes == null) return null;

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

    int targetHeight = h;

    for (Size size : sizes) {
        double ratio = (double) size.getWidth() / size.getHeight();
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.getHeight() - targetHeight);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.getHeight() - targetHeight);
            }
        }
    }
    return optimalSize;
}

像这样用

 final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
    try {
        final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

        final StreamConfigurationMap map =
                characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);


        // For still image captures, we use the largest available size.
        final Size largest =
                Collections.max(
                        Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),
                        new CompareSizesByArea());

        sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

        // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
        // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
        // garbage capture data.
       /* previewSize =
                chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                        inputSize.getWidth(),
                        inputSize.getHeight());*/

        previewSize = getOptimalPreviewSize(Arrays.asList(map.getOutputSizes(SurfaceTexture.class)),textureView.getWidth(),textureView.getHeight());
    } catch (final CameraAccessException e) {
        Log.e(TAG, "Exception!" + e);
    } catch (final NullPointerException e) {
        // Currently an NPE is thrown when the Camera2API is used but not supported on the
        // device this code runs.
        // TODO(andrewharp): abstract ErrorDialog/RuntimeException handling out into new method and
        // reuse throughout app.
        ErrorDialog.newInstance(getString(R.string.camera_error))
                .show(getChildFragmentManager(), FRAGMENT_DIALOG);
        throw new RuntimeException(getString(R.string.camera_error));
    }

-1
投票

解决方案很简单!如果你在actionbar下使用surfaceview,这可能是问题所在。我使用这一行,我可以修复,但我不测试使用操作栏。

用这个:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

-3
投票

如果您正在谈论预览,请尝试将SurfaceView的大小设置为与相机的预览大小相同。这样,预览不应该缩放。

© www.soinside.com 2019 - 2024. All rights reserved.