【问题标题】:Camera landscape preview in portrait mode纵向模式下的相机横向预览
【发布时间】:2018-06-17 20:27:30
【问题描述】:

我有一个对话框设计,其中相机预览应该是纵向模式下的横向(参见图片)。我通过 getOptimalPreviewSize() 正确选择预览大小,当我不使用 setDisplayOrientation(90) 时,我得到了这个:

当我使用 setDisplayOrientation(90) 时,我得到了这个:

有人知道如何解决它吗?安卓能做那种事吗?

回答(感谢 Eddy Talvala):
由于当您在 xml 中的凸轮视图是水平的时,您无法纵向处理整个凸轮图片,您应该裁剪。我决定水平放置并在底部裁剪所有内容:

|           |
| _________ |   _____
||         ||  |     |
||         ||  | ^-^ |
||  ______ ||  | \_/ |
|| | ^-^  |||  |  |  |    
|| |_\_/_ |||  |__|__|
||   image ||   sensor
||         ||
||         ||
||_________||
||  < O [] ||
|___________|
    device

您应该使用 TextureView 来指定适合和裁剪的矩阵。类似的东西(kotlin):

fun camInit() {
    val camParam = camera.parameters
    val optimalSize = getOptimalPortraitPreviewSize(camParam.supportedPreviewSizes, width, height)

    camParam.setPreviewSize(optimalSize.width, optimalSize.height)
    camera.parameters = camParam

    camera.setPreviewTexture(surface)

    val scaleDelta = optimalSize.height - preview.width // for portrait
    val scaleY: Float = (optimalSize.width.toFloat() - scaleDelta) / preview.height // for portrait

    val matrix = Matrix()
    matrix.setScale(1f, scaleY)    // 1f cause we fit horizontally

    preview.setTransform(matrix)

    camera.startPreview()
}

请注意,对于纵向模式,您应该使用特定的 getOptimalProtraitPreviewSize(),因为每个人用来获得相机预览最佳尺寸的标准函数(使用 ASPECT_TOLERANCE 和其他东西)可以返回一个小分辨率的尺寸。试试这样的:

fun getOptimalPortraitPreviewSize(sizes: List<Camera.Size>, previewWidth: Int) {

    var selectedSize: Camera.Size = sizes[0]

    for (size in sizes) {
        // use size's height cause of portrait
        val currentSizeWidthDelta = abs(size.height - previewWidth)
        val selectedSizeWidthDelta = abs(selectedSize.height - previewWidth)
        if (currentSizeWidthDelta < selectedSizeWidthDelta) selectedSize = size
    }

    return selectedSize
}

【问题讨论】:

  • 我想达到同样的效果,但我做不到。我已按照您的回答,但没有达到预期的结果。非常感谢任何帮助。
  • @WaqasAhmedAnsari 你遇到了什么问题?

标签: android android-camera surfaceview landscape-portrait


【解决方案1】:

图像传感器的长边与设备的长边对齐。

(bad ascii art):
____________
|           |
| _________ |   _____
||         ||  |     |
||         ||  |     |
||         ||  |     |
||         ||  |     |
||         ||  |_____|
||         ||   sensor
||         ||   physical 
||         ||   orientation
||_________||
||  < O [] ||
|___________|
    device

鉴于此,您无法像这样绘制图像:

_____________
|           |
| _________ |   _____
||         ||  |     |
||         ||  |     |
||  ______ ||  |     |
|| |      |||  |     |
|| |______|||  |_____|
||   image ||   sensor
||         ||
||         ||
||_________||
||  < O [] ||
|___________|
    device

除非您旋转图像(在这种情况下不会向上):

_____________
|           |
| _________ |   _____
||         ||  |     |
||         ||  | ^-^ |
||  ______ ||  | \_/ |
|| | <-\__|||  |  |  |    
|| |_<-/__|||  |__|__|
||   image ||   sensor
||         ||
||         ||
||_________||
||  < O [] ||
|___________|
    device

或者你水平拉伸图像,这看起来很糟糕:

_____________
|           |
| _________ |   _____
||         ||  |     |
||         ||  | ^-^ |
||  ______ ||  | \_/ |
|| | ^___^|||  |  |  |    
|| |___|__|||  |__|__|
||   image ||   sensor
||         ||
||         ||
||_________||
||  < O [] ||
|___________|
    device

或者您裁剪图像的一部分,这会大大减少 FOV:

_____________
|           |
| _________ |   _____
||         ||  |     |
||         ||  | ^-^ |
||  ______ ||  | \_/ |
|| | ^-^  |||  |  |  |    
|| |_\_/__|||  |__|__|
||   image ||   sensor
||         ||
||         ||
||_________||
||  < O [] ||
|___________|
    device

因为当手机是横向时图像传感器是横向的,所以如果不发生这三件事中的任何一件,就无法在纵向 UI 中放置横向预览。您要么需要在纵向 UI 中进行纵向预览,要么需要裁剪图像。这不是 Android 的限制,它只是几何的限制。

如果您想要裁剪,您可能需要将相机数据发送到 SurfaceTexture,然后在 OpenGL 中裁剪,如果您想要实时预览。

【讨论】:

    【解决方案2】:

    感谢@Eddy Talvala 和@blinker!我用我的函数来正确更新任何方向的尺寸:

      public void invalidateSize(TextureView textureView) {
            Point cameraResolution = getCameraResolution();
            int previewRotation = getPreviewRotation();
    
            // Camera and preview on screen in the opposite orientation
            if (previewRotation == 90 || previewRotation == 270) {
                //noinspection SuspiciousNameCombination
                cameraResolution = new Point(cameraResolution.y, cameraResolution.x);
            }
    
            float cameraAspectRatio = cameraResolution.x / (float) cameraResolution.y;
            float textureAspectRatio = textureView.getWidth() / (float) textureView.getHeight();
    
            float scaleX = cameraAspectRatio / textureAspectRatio;
            float scaleY = textureAspectRatio / cameraAspectRatio;
    
            if (scaleX > scaleY) {
                scaleY = 1;
            } else {
                scaleX = 1;
            }
    
            Matrix matrix = new Matrix();
            matrix.setScale(scaleX, scaleY,
                    textureView.getWidth() / 2f, textureView.getHeight() / 2f);
    
            textureView.setTransform(matrix);
    }
    

    【讨论】:

      【解决方案3】:

      如果您使用的是 Camera2 API。当通过 ChooseOptimalSize 获取 mPreviewSize 时,您可以交换宽度和高度。 (宽度和高度来自您的视图)。 然后

      textureView.setAspectRatio(mPreviewSize.Height, mPreviewSize.Width);
      

      创建预览会话时

      texture.SetDefaultBufferSize(mPreviewSize.Width, mPreviewSize.Height);
      

      然后你会预览正常的图像

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-03
        • 2015-04-12
        • 1970-01-01
        • 2010-10-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多