android - 全屏的相机显示/预览不保持纵横比 - 图像倾斜、拉伸(stretch)以适合屏幕

标签 android android-camera

我开发了一个小应用程序,用于全屏显示相机预览。我正在为此使用 Camera API。

这是 Activity 布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <!-- This is the container for the camera preview screen -->
    <FrameLayout android:id="@+id/camera_preview"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"/>
</LinearLayout>

当设备处于纵向时,显示会垂直缩放以匹配设备屏幕的高度 - 因此纵横比与原生相机的纵横比不同。这是 2 张图片,可以更好地解释我的意思:

enter image description here enter image description here

第一张图片是使用原生相机设备制作的。 第二张图片是用我的应用制作的,相机全屏显示 - 图像倾斜、拉伸(stretch)以适合屏幕。

我需要相机预览是全屏的,不管 getSupportedPreviewSizes() 方法给出的预览大小如何并且没有失真。 有没有办法做到这一点?当相机预览全屏时,有没有办法保持适当的纵横比?我希望这将由操作系统自动完成 - 裁剪图像以匹配请求的分辨率,同时保持纵横比,但这不会发生。

我试图使 SurfaceView 大于显示器(遵循这个问题:Fitting a camera preview to a SurfaceView larger than the display),但在我的情况下不行,因为我正在捕获快照(6 帧/秒) 并且这些不是用户在屏幕上看到的(帧包含所有相机预览,即使不是所有的都在屏幕上可见)。

我在这里发帖:https://www.dropbox.com/s/3d52xt8kazynsae/CameraFullScreen.7z?v=0mcn我所做的整个项目。

任何想法/解决方案对我来说都非常重要。非常感谢。

================================================ ==========================

更新由于 ss1271 答案:

我会稍微分析一下你上面为Samsung Galaxy Ace II写的分辨率。

我。屏幕分辨率:480x800 - 纵横比 3:5 = 0,6

二。 getSupportedPreviewSizes - 我几乎可以肯定这些值来自后置摄像头。以下是这些分辨率的纵横比:

   2560x1920   - 0,75

   2560x1536   - 0,60

   2048x1536   - 0,75

   2048x1232   - 0,60

   960x720     - 0,75

   640x480     - 0,75

因此,您的方法将返回对应于 2560x15362048x1232Size - 这些具有与屏幕分辨率相同的纵横比并使用这些值不会扭曲图片。 对我来说,问题是我不能使用这么大的分辨率,因为我每秒捕获 6 帧,这些需要以较低的分辨率保存。

我将在下面展示来自 Samsung S2 设备的一些结果:

我。屏幕分辨率:480 x 800 - 纵横比 3:5 = 0,6

二。后置摄像头
一个)。 getSupportedPreviewSizes:

800 / 480   - 480/800 = 0,60
800 / 450   - 450/800 = 0,56
720 / 480   - 0,66 
640 / 480   - 0,75
352 / 288   - 0,81
320 / 240   - 0,75
176 / 144   - 0,81

b)。原生相机分辨率:

3264 / 2448  - 0,75  - not full screen
3264 / 1968  - 0,60  - FULL SCREEN (since has the same aspect ratio as device screen)
2048 / 1536  - 0,75  - not full screen
2048 / 1232  - 0,60  - FULL SCREEN (same aspect ratio as device screen)
800 / 480    - 0,60  - FULL SCREEN (same aspect ratio as device screen)
640 / 480    - 0, 75 - not full screen

三。前置摄像头
一个)。 getSupportedPreviewSizes:

640 / 480   - 0,75
352 / 288   - 0,81
320 / 240   - 0,75
176 / 144   - 0,81

b)。原生相机未全屏显示,我无法选择分辨率 - 该选项已禁用。

对于 S2,后置摄像头,我想知道为什么 getSupportedPreviewSizes() 方法返回的分辨率与 native 摄像头的分辨率不同,或者 native 摄像头显示的分辨率是图片尺寸?我想知道为什么我没有 getSupportedPreviewSizes() 方法给出的 3264/1968、2048/1232 之类的选项? : enter image description here

最佳答案

简而言之,您可以全屏进行相机预览,但您需要自己在支持的预览尺寸中找出合适的尺寸,前提是您需要自定义相机预览。

对于您的问题,根据 Android Developers -- Camera

If you want to set a specific size for your camera preview, set this in the surfaceChanged() method as noted in the comments above. When setting preview size, you must use values from getSupportedPreviewSizes(). Do not set arbitrary values in the setPreviewSize() method.

除了 getSupportedPreviewSizes() 提供的尺寸之外,您似乎无法手动传递所需的尺寸。仔细检查手机摄像头支持的尺寸,您会发现支持的尺寸比例可能与您的屏幕比例并不完全相同。

例如三星Galaxy Ace II有480x800分辨率的屏幕,通过读取getSupportedPreviewSizes()返回的Size,其相机支持:

2560x1920

2560x1536

2048x1536

2048x1232

960x720

640x480

如果您想正确全屏显示您的相机预览(不拉伸(stretch)),您需要计算、比较和应用这些支持的预览尺寸中的合适比例。

找到合适的预览尺寸的实现并不是那么复杂的事情。这样做的常用方法是这样的:

    /**
     * Calculate the optimal size of camera preview
     * @param sizes
     * @param w
     * @param h
     * @return
     */
    private Size getOptimalSize(List<Size> sizes, int w, int h) {

        final double ASPECT_TOLERANCE = 0.2;        
        double targetRatio = (double) w / h;         
        if (sizes == null)             
            return null;          
        Size optimalSize = null;         
        double minDiff = Double.MAX_VALUE;          
        int targetHeight = h;          
        // Try to find an size match aspect ratio and size         
        for (Size size : sizes) 
        {             
//          Log.d("CameraActivity", "Checking size " + size.width + "w " + size.height + "h");            
            double ratio = (double) size.width / size.height;            
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)                
                continue;             
            if (Math.abs(size.height - targetHeight) < minDiff) 
            {                 
                optimalSize = size;                 
                minDiff = Math.abs(size.height - targetHeight);             
            }         
        }          
        // Cannot find the one match the aspect ratio, ignore the requirement     

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

        SharedPreferences previewSizePref;
        if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
            previewSizePref = getSharedPreferences("PREVIEW_PREF",MODE_PRIVATE);
        } else {
            previewSizePref = getSharedPreferences("FRONT_PREVIEW_PREF",MODE_PRIVATE);
        }

        SharedPreferences.Editor prefEditor = previewSizePref.edit();
        prefEditor.putInt("width", optimalSize.width);
        prefEditor.putInt("height", optimalSize.height);

        prefEditor.commit();

//      Log.d("CameraActivity", "Using size: " + optimalSize.width + "w " + optimalSize.height + "h");            
        return optimalSize;     
    }

你也可以做类似的事情来找出合适的相机尺寸(输出图片尺寸)。

注意:我从互联网上找到了上面代码的原始版本,并出于自己的目的进行了一些修改/优化。

如果这对你有用,请告诉我。

关于android - 全屏的相机显示/预览不保持纵横比 - 图像倾斜、拉伸(stretch)以适合屏幕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16727836/

相关文章:

android - Android 1.5 上的 Gears 或 HTML5 Location API

android - 致命异常 : During Retrofit network request : Kotlin Coroutine

android - 原生共享库依赖静态库,如何将基于Android.mk文件的Android NDK项目迁移到Gradle?

android - Espresso,使用登录屏幕测试快乐路径

android - 同时使用前置和后置摄像头android

java - 如何在整个应用程序中保持 session 直到用户在 android 中注销?

安卓:编码的相机预览帧总是横向的。如何旋转?

android - 如何显示我的相机预览

android - ACTION_IMAGE_CAPTURE 和 EXTRA_OUTPUT 创建已处理的 "Handling Media Storage Error"

android - 如何在相机预览打开时(以编程方式)保持手电筒打开