如何更改像 setPreviewSize 和 PictureSize 这样的 CameraSource 大小

Posted

技术标签:

【中文标题】如何更改像 setPreviewSize 和 PictureSize 这样的 CameraSource 大小【英文标题】:How to change CameraSource size like setPreviewSize and PictureSize 【发布时间】:2018-05-19 06:28:08 【问题描述】:

这与 google vision API 有关。 CameraPreview 适用于全屏。但是在框内预览相机时图像失真。

这是我使用的代码。我的问题是预览填满了框,但预览被拉伸了,我无法调整 cameraPreview 的大小。变量 CameraPreview 属于 SurfaceView 类型。我使用 CameraSource 开始预览。有什么办法可以改变 CameraPreview(SurfaceView) 的大小并使预览裁剪适合一个盒子吗?

  cameraPreview.getHolder().addCallback(new SurfaceHolder.Callback() 
            protected List<Camera.Size> mPreviewSizeList;
            protected List<Camera.Size> mPictureSizeList;
            protected Camera.Size mPreviewSize;
            protected Camera.Size mPictureSize;
            protected boolean mSurfaceChanged = false;
            private int mSurfaceChangedCallDepth = 0;
            private int mCenterPosX = -1;
            private int mCenterPosY = 0;
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) 
                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) 
                    ActivityCompat.requestPermissions(ClientIdScannerActivity.this,
                            new String[]Manifest.permission.CAMERA, RequestCameraPermissionId);
                    Toast.makeText(ClientIdScannerActivity.this, "The App requires this permission", Toast.LENGTH_SHORT).show();
                    return;
                
                try 
                    cameraSource.start(cameraPreview.getHolder());
                 catch (Exception ex) 
                    ex.printStackTrace();
                
            
            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) 
                mSurfaceChangedCallDepth++;

             /*   cameraSource.stop();

                Camera.Parameters cameraParams = mCamera.getParameters();

                if (!mSurfaceChanged) 
                    Camera.Size previewSize = determinePreviewSize(cameraWidth, cameraHight);
                    Camera.Size pictureSize = determinePictureSize(previewSize);
                    mPreviewSize = previewSize;
                    mPictureSize = pictureSize;
                    mSurfaceChanged = adjustSurfaceLayoutSize(previewSize,i1, i2);

                    if (mSurfaceChanged && (mSurfaceChangedCallDepth <= 1)) 
                        return;
                    
                

                cameraParams.setRotation(270);
                if (UtilFunctions.isTablet()) 
                 else 
                    mCamera.setDisplayOrientation(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? 270 : 90);
                */

//            cameraParams.setRotation(270);
//            mCamera.setDisplayOrientation(UtilFunctions.isTablet() ? 90 : 270);

              /*  cameraParams.set("orientation", "portrait");
                //  cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
                cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
                if (cameraParams.getSupportedFocusModes().contains(
                        Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) 
                    cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                */

                mSurfaceChanged = false;

                try 
                    if (ActivityCompat.checkSelfPermission(ClientIdScannerActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) 
                        // TODO: Consider calling
                        //    ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.
                        Toast.makeText(ClientIdScannerActivity.this, "App requires Camera permission to scan ID", Toast.LENGTH_SHORT).show();
                        return;
                    
                    cameraSource.start(cameraPreview.getHolder());
                 catch (Exception e) 
                    // Remove failed size

                    // Reconfigure
                    if (mPreviewSizeList.size() > 0)  // prevent infinite loop
                        surfaceChanged(null, 0, i1, i2);
                     else 
//                Utils.showToast(CameraNewActivity.this, "Can't start preview", Toast.LENGTH_LONG);
                    
                

                mSurfaceChangedCallDepth--;
            

            protected Camera.Size determinePreviewSize(int reqWidth, int reqHeight) 

                int reqPreviewWidth = 640;//reqHeight; // requested width in terms of camera hardware
                int reqPreviewHeight = 480;// reqWidth; // requested height in terms of camera hardware
                Camera.Size retSize = null;
                for (Camera.Size size : mPreviewSizeList) 
                    if (size.width == reqPreviewWidth && size.height == reqPreviewHeight) 
                        retSize = size;
                    
                
                //  retSize = mPreviewSizeList.get(mPreviewSizeList.size()-1);
                return retSize;
            

            protected Camera.Size determinePictureSize(Camera.Size previewSize) 
                Camera.Size retSize = null;
                for (Camera.Size size : mPictureSizeList) 
                    if (size.equals(previewSize)) 
                        return size;
                    
                

                // if the preview size is not supported as a picture size
                float reqRatio = ((float) previewSize.width) / previewSize.height;
                float curRatio, deltaRatio;
                float deltaRatioMin = Float.MAX_VALUE;
                for (Camera.Size size : mPictureSizeList) 
                    curRatio = ((float) size.width) / size.height;
                    deltaRatio = Math.abs(reqRatio - curRatio);
                    if (deltaRatio < deltaRatioMin) 
                        deltaRatioMin = deltaRatio;
                        retSize = size;
                    
                

                return retSize;
            

            protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize,
                                                      int availableWidth, int availableHeight) 

                float tmpLayoutHeight = previewSize.width;
                float tmpLayoutWidth = previewSize.height;

                float factH, factW, fact;
                factH = availableHeight / tmpLayoutHeight;
                factW = availableWidth / tmpLayoutWidth;

//        if (factH < factW) 
//            fact = factH;
//         else 
                fact = factW;
                //  

                FrameLayout.LayoutParams layoutParams =(FrameLayout.LayoutParams) cameraPreview.getLayoutParams();
                int layoutHeight = (int) (tmpLayoutHeight * fact);
                int layoutWidth = (int) (tmpLayoutWidth * fact);

                boolean layoutChanged;
                if ((layoutWidth != cameraPreview.getWidth()) || (layoutHeight != cameraPreview.getHeight())) 
                    layoutParams.height = layoutHeight;
                    layoutParams.width = layoutWidth;
                    if (mCenterPosX >= 0) 
                        layoutParams.topMargin = mCenterPosY - (layoutHeight / 2);
                        layoutParams.leftMargin = mCenterPosX - (layoutWidth / 2);
                    
                    cameraPreview.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation.
                    layoutChanged = true;
                 else 
                    layoutChanged = false;
                

                return layoutChanged;
            

            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) 
                cameraSource.stop();
            
        );

【问题讨论】:

此代码运行但无效。我之前使用过 Camera 变量,但由于不再需要它而对其进行了评论。这是我的理解。 【参考方案1】:

请注意,“全屏”相机预览也存在同样的问题。无法保证您选择的预览尺寸的纵横比与屏幕的纵横比足够接近。请在此处查看更多详细信息:Camera Preview Stretched on Few android Devices

您自然必须选择适合视图的最佳宽度和高度,但这还不够。您必须将预览表面的“悬挂”部分隐藏在一些不透明的视图后面。看看你如何make a circular preview。

这里的另一件重要事情是始终保持预览和图片尺寸同步。这并不意味着它们必须相同,但纵横比应该相同。当长宽比发生变化以拍摄照片时,某些设备会产生奇怪的效果。

【讨论】:

感谢您的建议!

以上是关于如何更改像 setPreviewSize 和 PictureSize 这样的 CameraSource 大小的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 Raspbian PI 4 上无线连接的静态 IP 地址? [关闭]

Android:更改屏幕上的相机预览大小

Facebook时间线封面照片iphone

如何确定我的 pi 计算是不是准确?

如何确定我的pi计算是否准确?

如何更改启动画面中图像的大小?