如何更改像 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 大小的主要内容,如果未能解决你的问题,请参考以下文章