【问题标题】:Camera Surface View Images Look Stretched相机表面视图图像看起来拉伸
【发布时间】:2012-06-24 11:59:14
【问题描述】:

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

虽然在捕获图像后以适当的尺寸显示

如何解决这个问题?

【问题讨论】:

    标签: android android-camera


    【解决方案1】:

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

    如果您有全屏视图,那么您应该会发现相机的预览尺寸与该尺寸相匹配——至少会有一个具有相同纵横比的预览尺寸。例如,如果您的屏幕为 640x480,则 320x240 预览尺寸在全屏时不会出现拉伸SurfaceView

    【讨论】:

    • 要设置预览大小,我使用以下代码,但表面看起来仍然拉伸:private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) { Camera.Size result = null; for (Camera.Size size : parameters.getSupportedPreviewSizes()) { if (size.width resultArea) { 结果 = 大小; } } } } 返回(结果); }
    • 你为什么要这样做?只需先寻找一个简单的完全匹配。看起来您正在从 Barcode Scanner 复制非常旧的代码。
    【解决方案2】:

    您必须根据 (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);
      

      它可能对某人有所帮助。

      【讨论】:

      • 在许多情况下,这会引发运行时异常(setParameters failed),因为surfaceView 的大小与任何支持的预览大小都不匹配。
      • 您必须根据文档设置 getSupportedPreviewSize() 提供的预览大小。它说你不能在 setPreviewSize() 上设置任何任意值。
      【解决方案4】:

      只需添加以下函数来设置纵横比和预览大小

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

      【讨论】:

        【解决方案5】:

        解决方法很简单!如果您在操作栏下使用surfaceview,这可能是问题所在。我使用这条线,我可以修复,但我没有使用操作栏进行测试。

        使用这个:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-06-14
            • 2015-04-27
            • 1970-01-01
            • 2016-09-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多