1.前言
显示框口的控件:SurfaceView。
控件尺寸比例: 1:1(正方形的尺寸比较适合人脸识别)
显示窗口大小:非全屏
2.拉伸原因
camera预览尺寸是从厂商list读取的
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();//获取预览的各种分辨率
获取最佳尺寸(google developer的源码)
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio;
if (w > h) {
targetRatio = (double) w / h; /* w / h : 横向 h / w :竖向*/
} else {
targetRatio = (double) h / w; /* w / h : 横向 h / w :竖向*/
}
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
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);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
Log.e(TAG, "finally choose size:optimalSize width=" + optimalSize.width + " optimalSize height=" + optimalSize.height);
return optimalSize;
}
完全是调用google的源码,并没有做改变。
那么如果,读取出来的list中,所有尺寸的宽高比都不满足我们的窗口会发生什么?
当然是预览界面的形变,比例不满足,则选出来的尺寸可能与我们预想的出入比较大,比如:
我们预览窗口的大小是:800×800,选择的camera预览尺寸是:1280×720,比窗口尺寸大则压缩,小则拉伸,来补满不足的像素点。
3.解决方案,动态改变窗口大小来适配camera预览尺寸。
还是以上述尺寸为例,正方形的预览窗口,在部分手机上没有获取到1:1的尺寸。
这时候需要调节一下自己的窗口比例,如果不希望与原来窗口大小的差异过大,则选择4:3比例(具体情况还需要根据自己的project来确定)。
800×800的窗口,调节后,为800×600
private boolean surfaceChanged = true;
定义一个全局变量来控制surfaceView是否需要调整,如果不需要则不用添加,但是要注意,这里会隐形调用surfaceChanged,如果在SurfaceView的重写方法中,有调用一下调整的方法,则必须要,否则会死循环。
double ratioSurface = (double) surfaceView.getWidth() / (double) surfaceView.getHeight();
double ratioCamera = (double) optionSize.width / (double) optionSize.height;
Log.v(TAG, "ratioSurface:" + ratioSurface + " ratioCamera:" + ratioCamera);
if (surfaceChanged && ratioCamera != ratioSurface) {
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(600, 800);//这里根据自己的需要,是竖屏还是横屏,我们是竖屏,所以选择了宽高对换了一下。
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);//这一行是让控件在父控件完全居中
surfaceView.setLayoutParams(layoutParams);
surfaceChanged = false;
}
以上代码添加在什么位置呢?
mCamera.setParameters(parameters);
在参数设置以前就可以。
4.可能遇到的问题
A.画面旋转:
这种情况下需要自己手动去调整摄像头
PS:由于这是在项目中解决问题时写的,就不方便上传源码了,不过源码估计可移植性不强。
感谢光临。