全屏相机显示/预览不保持纵横比 - 图像倾斜、拉伸以适应屏幕 [英] Camera display / preview in full screen does not maintain aspect ratio - image is skewed, stretched in order to fit on the screen

查看:44
本文介绍了全屏相机显示/预览不保持纵横比 - 图像倾斜、拉伸以适应屏幕的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这是活动布局:

<!-- 这是相机预览屏幕的容器--><FrameLayout android:id="@+id/camera_preview"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout>

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

第一张图片是用原生相机设备制作的.第二张图片是使用我的应用制作的,相机处于全屏模式 - 图像倾斜、拉伸以适应屏幕.

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

我试图让 SurfaceView 比显示器大(按照这个问题:

<块引用>

如果你想为你的相机预览设置一个特定的尺寸,设置这个在 surfaceChanged() 方法中,如上述注释中所述.什么时候设置预览尺寸,您必须使用来自getSupportedPreviewSizes().不要在中设置任意值setPreviewSize() 方法.

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

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

<块引用>

2560x1920

2560x1536

2048x1536

2048x1232

960x720

640x480

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

找到合适的预览尺寸的实现并不是那么复杂.执行此操作的常用方法是这样的:

/*** 计算相机预览的最佳尺寸* @param 大小* @param w* @param h* @返回*/私有大小 getOptimalSize(列表<大小>大小,int w,int h){最终双 ASPECT_TOLERANCE = 0.2;double targetRatio = (double) w/h;如果(大小 == 空)返回空;尺寸优化尺寸 = null;double minDiff = Double.MAX_VALUE;int targetHeight = h;//尝试找到一个尺寸匹配纵横比和尺寸for (尺码 : 尺码){//Log.d("CameraActivity", "检查尺寸" + size.width + "w " + size.height + "h");双倍比率 = (double) size.width/size.height;如果 (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)继续;if (Math.abs(size.height - targetHeight) 

您也可以通过类似的方法找出合适的相机尺寸(输出图片尺寸).

注意:我从网上找到了上面代码的原始版本,为了自己的目的做了一些修改/优化.

如果这对您有用,请告诉我.

I have developed a small application for displaying camera preview in full screen. I'm using Camera API for this.

This is the activity layout:

<?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>

When device is in portrait, the display is vertically scaled in order to match the height of device screen - so the aspect ratio is not the same as the one from native camera. These are 2 images which explains better what I'm saying:

The first image is made with native camera device. The second image is made with my app, with camera in full screen - the image is skewed, stretched in order to fit on the screen.

I need the camera preview to be full screen, regardless of the preview size given by getSupportedPreviewSizes() mehod and without distortion. Is there a way to accomplish this? Is there a way to maintain proper aspect ratio when camera preview is in full screen? I expected this to be done automatically by OS - cropping the image to match the requested resolution while maintaining aspect ratio, but this does not happen.

I've tried to make the SurfaceView larger than the display (following this question: Fitting a camera preview to a SurfaceView larger than the display), but is not ok in my case since I'm capture snapshots (6 frames/second) and those are not what user sees on the screen (the frame contains all camera preview even if not all of it is visible on the screen).

I posted here: https://www.dropbox.com/s/3d52xt8kazynsae/CameraFullScreen.7z?v=0mcn the entire project I've made.

Any idea/solution is more than important to me. Thanks a lot.

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

Update due to ss1271 answer:

I'll analyze a little the resolutions you wrote above for Samsung Galaxy Ace II.

I. Screen resolution: 480x800 - aspect ratio 3:5 = 0,6

II. getSupportedPreviewSizes - I'm almost sure that these values are from back camera. Below are the aspects ratio for these resolutions:

   2560x1920   - 0,75

   2560x1536   - 0,60

   2048x1536   - 0,75

   2048x1232   - 0,60

   960x720     - 0,75

   640x480     - 0,75

So, your method will return a Size corresponding to 2560x1536 or to 2048x1232 - these having the same aspect ratio as screen resolution and using these values will not distort the picture. The problem for me is that I cannot use so big resolutions since I capture 6 frames/second and these needs to be saved at a lower resolution.

I'll present below some results from a Samsung S2 device:

I. Screen resolution: 480 x 800 - aspect ratio 3:5 = 0,6

II. Back camera
a). 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). Native camera resolutions:

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

III. Front camera
a). getSupportedPreviewSizes:

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

b). Native camera is not in full screen and I cannot choose a resolution - the option is disabled.

For S2, back camera, I'm wonder why getSupportedPreviewSizes() method do not return the same resolutions as Native camera does or the ones displayed by native camera are the picture sizes ? I'm wonder why I do not have options like 3264 / 1968, 2048 / 1232 given by getSupportedPreviewSizes() method ? :

解决方案

In a nutshell, you can do a camera preview in full screen however you'll need to find out the appropriate sizes among the supported preview sizes by yourself, only if a customized camera preview is what you want.

For your question, according to the 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.

It seemed you can't manually pass the size you want other than the sizes provides by getSupportedPreviewSizes(). With a closer examine the sizes supported by your phones camera, you'll find the ratio of sizes supported might not exactly the same as your screen's ratio.

For example, Samsung Galaxy Ace II has 480x800 resolution screen, by reading the Size returned from getSupportedPreviewSizes(), its camera supports:

2560x1920

2560x1536

2048x1536

2048x1232

960x720

640x480

and if you want to display your camera preview in full screen correctly (without stretch), you'll need to calculate, compare and apply the suitable ratio in these supported preview sizes.

Implementation of finding a proper preview size is not that complicated stuff. A common method for doing this would be something like this:

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

And you can also do the similar to find out the suitable camera sizes (the output picture size).

Note: I found the original version of the code above from Internet and I did some modification/optimisation for my own purpose.

Please let me know if this works for you.

这篇关于全屏相机显示/预览不保持纵横比 - 图像倾斜、拉伸以适应屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆