我一直在努力在Android上制作我的自定义相机活动,但当旋转相机时,表面视图的纵横比会变得混乱。
在我的oncreate for the activity中,我设置了framelayout,它保存了显示相机参数的曲面视图。
//FrameLayout that will hold the camera preview
FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);
//Setting camera's preview size to the best preview size
Size optimalSize = null;
camera = getCameraInstance();
double aspectRatio = 0;
if(camera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
aspectRatio = (float)optimalSize.width/optimalSize.height;
}
if(optimalSize!= null){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
previewHolder.setLayoutParams(params);
LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
cameraPreview.setLayoutParams(surfaceParams);
}
cameraPreview.setCamera(camera);
//Adding the preview to the holder
previewHolder.addView(cameraPreview);
然后,在曲面视图中,我设置要显示的相机参数
public void setCamera(Camera camera) {
if (mCamera == camera) { return; }
mCamera = camera;
if (mCamera != null) {
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
}
/*
Important: Call startPreview() to start updating the preview surface. Preview must
be started before you can take a picture.
*/
mCamera.startPreview();
}
}
您可以看到,当手机旋转时,乐高男会变得更高、更瘦:
如何确保相机视图的纵横比正确?
注:我的解决方案是HESAM解决方案的延续:https://stackoverflow.com/a/22758359/1718734
我的地址:Hesam说有些手机上可能会出现一些空白,如下所示:
Hesam提出了第二种解决方案,但这会挤压预览。在某些设备上,它会严重扭曲。
那么我们如何解决这个问题呢。这很简单。。。将纵横比相乘,直到填满屏幕。我注意到,Snapchat、WhatsApp等几种流行应用程序的工作方式都是一样的。
您所要做的就是将其添加到onInstrure方法中:
float camHeight = (int) (width * ratio);
float newCamHeight;
float newHeightRatio;
if (camHeight < height) {
newHeightRatio = (float) height / (float) mPreviewSize.height;
newCamHeight = (newHeightRatio * camHeight);
Log.e(TAG, camHeight + " " + height + " " + mPreviewSize.height + " " + newHeightRatio + " " + newCamHeight);
setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight);
Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | H_ratio - " + newHeightRatio + " | A_width - " + (width * newHeightRatio) + " | A_height - " + newCamHeight);
} else {
newCamHeight = camHeight;
setMeasuredDimension(width, (int) newCamHeight);
Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | A_width - " + (width) + " | A_height - " + newCamHeight);
}
这将计算屏幕高度,并获得屏幕高度与mPreviewSize高度的比率。然后将相机的宽度和高度乘以新的高度比,并相应地设置测量尺寸。
接下来你知道的是,你最终得到了这个: D
这也适用于前置摄像头。我相信这是最好的方法。现在,我的应用程序只剩下单击“捕获”保存预览本身但是,是的,就是这样。
F1Sher的解决方案很好,但有时不起作用。尤其是当你的surfaceView没有覆盖整个屏幕时。在这种情况下,需要重写onMeasure()方法。我已将代码复制到这里供您参考。
因为我是根据宽度来测量surfaceView的,所以我在屏幕的末端有一点白色的间隙,我是通过设计来填充的。如果您保持高度并将其乘以比率来增加宽度,则可以解决此问题。然而,它会稍微挤压surfaceView。
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e(TAG, str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// empty. surfaceChanged will take care of stuff
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h);
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
if (mPreviewSize!=null) {
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) 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.height / size.width;
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);
}
}
}
return optimalSize;
}
}
我在用这个方法-
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)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);
}
}
}
return optimalSize;
}
正如您所看到的,您必须输入屏幕的宽度和高度。此方法将根据这些值计算屏幕比率,然后从支持的预览大小列表中选择最适合您的可用大小。在相机对象不为空的地方,使用
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
然后在onMeasure中,您可以获得如下最佳预览大小:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
然后(在我的surfaceChanged方法中的代码中,就像我说的,我正在使用CameraActivity代码的API演示结构,您可以在Eclipse中生成它):
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();
给你一个提示,因为我和你做了几乎相同的应用程序。相机活动的良好做法是隐藏StatusBar。Instagram等应用程序正在这样做。它会降低您的屏幕高度值并改变您的比率值。在某些设备上可能会出现奇怪的预览尺寸(您的SurfaceView会被削减一点)
为了回答您的问题,如何检查预览比率是否正确?然后获取在中设置的参数的高度和宽度:
mCamera.setParameters(parameters);
您的设置比率等于高度/宽度。如果您希望相机在屏幕上看起来不错,那么您设置给相机的参数的高度/宽度比率必须与屏幕的高度(减去状态栏)/宽度比率相同。
我在玩谷歌的API2摄像头,我的代码有一些问题。我有两个不同的摄像头,一个用于视频,另一个用于图像。为了提高效率,我将代码更改为使用唯一会话,并使应用程序更高效。 在我这样做之后,我的相机预览不能充分工作。当我使用4:3宽高比时,我的预览会在高处拉伸。换句话说,当我使用16:9的比例时,它看起来很好。在这两种情况下,我的照片看起来都很好,我的意思是,预览不能正确工作,但是我拍的照片有正确的宽高比。
我使用相机仅显示预览(不拍照或录制视频)。 该应用程序始终处于竖屏状态(横向模式被禁用)。相机预览始终旋转90度ccw,我无法更改它(无论是还是和。 预览总是这样旋转还是依赖于设备?如果在纵向模式下总是这样,我可以在之后旋转图像。 或者有没有办法正确设置摄像头?我读了很多关于这个的帖子,但没有一个答案对我有用(Galaxy s2,Android v2.3)
请帮助正确配置Android摄像头(在HTC Desire 2.3.3上测试),以便在旋转(人像)模式下从摄像头预览。预览必须占用屏幕的一半以下,它的宽度必须等于设备的宽度,缩放必须根据相机的纵横比动态设置。我的当前代码: 活动布局: AndroidManifest配置为肖像: 你可以看到图像的比例不对。如何使以适当的比例显示旋转和缩放相机预览? 部分代码取自Mixare开源项目,http://w
这个问题已经问了很多次了,但我似乎找不到我到底想要什么。我试图创建一个相机应用程序,我想在日志中显示YUV或RGB值时,我把相机指向一些颜色。对于RGB或相应的YUV颜色格式,该值必须为0...255范围。我可以管理它们之间的转换,因为在堆栈溢出方面有许多这样的例子。但是,我不能将这些值存储到3个单独的变量中并在日志中显示它们。 任何帮助都将不胜感激。
null null 当然,任何其他建议都将不胜感激。 注意:也有类似的问题,我花了几个小时来研究,但没有一个正确地解决了我的问题,也没有给出足够的细节。
有没有人使用过这个打包的Xamrin版本?https://components.xamarin.com/view/emgucv-v3 我最近购买了这个许可证,并击中了与这里描述的完全相同的问题(旋转相机预览到肖像Android OpenCV相机)。一直在使用各种方法。 首先转屏方向从风景到肖像,但这只是以相同的旋转形式(90度)显示流。景观似乎是唯一一个我喜欢的作品。 我尝试使用相机对象旋转相机本