使用 Android 相机 API 时,低质量图片和覆盖 surfaceChanged 的用途是什么
Low quality picture and what's the usage of overriding surfaceChanged when using Android Camera API
我的应用程序有问题,具体来说,当我想拍照(从 android 相机 API)并将其发送到我的服务器时,我得到了一些奇怪的图片,如下所示示例:
其中包含很多噪声点,实际上 size/resolution 非常小(176*144 像素)。这是我的 surfaceChanged 原始代码:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.e(LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
mCamera.startPreview();
}
然后我试着问了一些同学这个问题,他们不知道但是其中一位给出了以下代码:
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
try {
// camera.stopPreview();
// Camera.Parameters mParameters = camera.getParameters();
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size optiSize = getBestPreviewSize(720, 720);
if (optiSize != null) {
parameters.setPreviewSize(optiSize.width, optiSize.height);
parameters.setPictureSize(optiSize.width, optiSize.height);
}
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
mCamera.setParameters(parameters);
// mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
// camera.setParameters(mParameters); // apply the changes
} catch (Exception e) {
// older phone - doesn't support these calls
}
mCamera.startPreview();
}
private Camera.Size getBestPreviewSize(int width, int height) {
List<Camera.Size> sizes = mCamera.getParameters()
.getSupportedPreviewSizes();
if (sizes == null)
return null;
Camera.Size optimalSize = null;
int tmpSize;
int minWidthDiff = 1000;
for (Camera.Size size : sizes) {
if (size.width > size.height)
tmpSize = size.height;
else
tmpSize = size.width;
if (Math.abs(tmpSize - width) < minWidthDiff) {
minWidthDiff = Math.abs(tmpSize - width);
optimalSize = size;
}
}
return optimalSize;
}
而且这个效果很好,它可以存储全分辨率的原始图片。尽管我修改了一些其他代码以使新代码与我的系统兼容(例如添加自动对焦)。但我认为问题的发生是因为方法 surfaceChanged 因为如果我只使用自动对焦拍摄图像,它仍然不起作用。
所以我的问题是:为什么这种方法会影响我的图像质量。我以为只有当我们 "change" 表面时才会调用此方法,例如旋转屏幕。但显然它的作用不止于此?
有人可以帮我吗?或者一些帖子来解释这个事实?非常感谢您。
当表面改变时调用此方法,例如它被调整大小。调整相机的一些参数以更好地适应新配置(例如设置合适的预览尺寸)是很常见的。
你在第一个代码中所做的是获取相机的 Camera.Parameters
,设置一个键值对(顺便说一下,the documentation 没有提到任何带有键的参数"orientation"
- 它可能没有任何意义)。您忘记做的是使用 Camera.setParameters()
将新参数应用于相机。话又说回来,如果没有实际设置任何有效参数,这将不起作用。
这会导致图片质量低下的问题。您应该使用 Camera.Parameters
对象来设置所需的预览和图片大小。在第二个代码块中,这是在 getBestPreviewSize()
内完成的。获取可用预览尺寸列表,并根据预览尺寸选择最合适的尺寸。设置一个满意的图片尺寸也可能会有所帮助。
事实是,不同的设备具有不同的参数支持值集。如果您想提供一致的功能,您应该使用 Camera.Parameters.getSupported*
方法检查支持的值并相应地设置它们。
我的应用程序有问题,具体来说,当我想拍照(从 android 相机 API)并将其发送到我的服务器时,我得到了一些奇怪的图片,如下所示示例:
其中包含很多噪声点,实际上 size/resolution 非常小(176*144 像素)。这是我的 surfaceChanged 原始代码:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.e(LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
mCamera.startPreview();
}
然后我试着问了一些同学这个问题,他们不知道但是其中一位给出了以下代码:
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
try {
// camera.stopPreview();
// Camera.Parameters mParameters = camera.getParameters();
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size optiSize = getBestPreviewSize(720, 720);
if (optiSize != null) {
parameters.setPreviewSize(optiSize.width, optiSize.height);
parameters.setPictureSize(optiSize.width, optiSize.height);
}
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
mCamera.setParameters(parameters);
// mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
// camera.setParameters(mParameters); // apply the changes
} catch (Exception e) {
// older phone - doesn't support these calls
}
mCamera.startPreview();
}
private Camera.Size getBestPreviewSize(int width, int height) {
List<Camera.Size> sizes = mCamera.getParameters()
.getSupportedPreviewSizes();
if (sizes == null)
return null;
Camera.Size optimalSize = null;
int tmpSize;
int minWidthDiff = 1000;
for (Camera.Size size : sizes) {
if (size.width > size.height)
tmpSize = size.height;
else
tmpSize = size.width;
if (Math.abs(tmpSize - width) < minWidthDiff) {
minWidthDiff = Math.abs(tmpSize - width);
optimalSize = size;
}
}
return optimalSize;
}
而且这个效果很好,它可以存储全分辨率的原始图片。尽管我修改了一些其他代码以使新代码与我的系统兼容(例如添加自动对焦)。但我认为问题的发生是因为方法 surfaceChanged 因为如果我只使用自动对焦拍摄图像,它仍然不起作用。
所以我的问题是:为什么这种方法会影响我的图像质量。我以为只有当我们 "change" 表面时才会调用此方法,例如旋转屏幕。但显然它的作用不止于此?
有人可以帮我吗?或者一些帖子来解释这个事实?非常感谢您。
当表面改变时调用此方法,例如它被调整大小。调整相机的一些参数以更好地适应新配置(例如设置合适的预览尺寸)是很常见的。
你在第一个代码中所做的是获取相机的 Camera.Parameters
,设置一个键值对(顺便说一下,the documentation 没有提到任何带有键的参数"orientation"
- 它可能没有任何意义)。您忘记做的是使用 Camera.setParameters()
将新参数应用于相机。话又说回来,如果没有实际设置任何有效参数,这将不起作用。
这会导致图片质量低下的问题。您应该使用 Camera.Parameters
对象来设置所需的预览和图片大小。在第二个代码块中,这是在 getBestPreviewSize()
内完成的。获取可用预览尺寸列表,并根据预览尺寸选择最合适的尺寸。设置一个满意的图片尺寸也可能会有所帮助。
事实是,不同的设备具有不同的参数支持值集。如果您想提供一致的功能,您应该使用 Camera.Parameters.getSupported*
方法检查支持的值并相应地设置它们。