Android相机参数setPictureSize导致图片出现条纹

Posted

技术标签:

【中文标题】Android相机参数setPictureSize导致图片出现条纹【英文标题】:Android Camera Parameter setPictureSize causes streaked picture 【发布时间】:2014-05-16 22:22:38 【问题描述】:

我正在尝试使用 android 相机拍照。我需要捕获 1600 (w) x 1200 (h) 图像(第三方供应商要求)。我的代码似乎适用于许多手机摄像头,但 setPictureSize 会导致某些手机(三星 Galaxy S4、三星 Galaxy Note)崩溃,并导致其他手机(Nexus 7 平板电脑)出现条纹。至少在 Nexus 上,我想要的尺寸显示在 getSupportPictureSizes 列表中。

我已尝试指定方向,但没有帮助。使用默认图片尺寸拍摄照片效果很好。

这是一个裸奔的例子:

对于我的图像捕获,我有 1600x1200、jpg、30% 压缩的要求,所以我正在捕获一个 JPG 文件。

我认为我有三个选择: 1) 弄清楚如何在没有崩溃或条纹的情况下捕获 1600x1200 尺寸,或者 2)弄清楚如何将默认图片大小的大小更改为1600x1200的JPG。 3) 我目前不知道的其他事情。

我发现了一些其他有类似问题但不完全相同的帖子。我在尝试事情的第二天,但没有找到解决方案。这是一个接近的帖子:

Camera picture to Bitmap results in messed up image(没有任何建议对我有帮助)

这是在我遇到 S4/Note/Nexus 7 之前运行良好的代码部分。我现在添加了一些调试代码:

Camera.Parameters parameters = mCamera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);

if (size != null) 
    int pictureWidth = 1600;
    int pictureHeight = 1200;

    // testing
    Camera.Size test = parameters.getPictureSize();
    List<Camera.Size> testSizes = parameters.getSupportedPictureSizes();
    for ( int i = 0; i < testSizes.size(); i++ ) 
        test = testSizes.get(i);
    

    test = testSizes.get(3);
    // get(3) is 1600 x 1200
    pictureWidth = test.width;
    pictureHeight = test.height;

    parameters.setPictureFormat(ImageFormat.JPEG);
    parameters.setPictureSize(pictureWidth, pictureHeight);
    parameters.setJpegQuality(30);
    parameters.setPreviewSize(size.width, size.height);

    // catch any exception
    try 
        // make sure the preview is stopped
        mCamera.stopPreview();

        mCamera.setParameters(parameters);
        didConfig = true;
    catch(Exception e) 
        // some error presentation was removed for brevity
        // since didConfig not set to TRUE it will fail gracefully
    

这是我保存 JPG 文件的代码部分:

PictureCallback jpegCallback = new PictureCallback() 
    public void onPictureTaken(byte[] data, Camera camera) 
        if ( data.length > 0 ) 

            String fileName = "image.jpg";

            File file = new File(getFilesDir(), fileName);
                String filePath = file.getAbsolutePath();

             boolean goodWrite = false;
             try 
                 OutputStream os = new FileOutputStream(file);
                 os.write(data);
                 os.close();

                goodWrite = true;
             catch (IOException e) 
                 goodWrite = false;
             

             if ( goodWrite ) 
                // go on to the Preview
              else 
                // TODO return an error to the calling activity
             

        

        Log.d(TAG, "onPictureTaken - jpeg");
    
;

有关如何正确设置相机参数以拍摄照片或如何裁剪或调整结果照片大小的任何建议都会很棒。特别是如果它适用于旧相机(API 级别 8 或更高版本)!基于需要图片的全宽,我只能裁剪顶部。

谢谢!

编辑:这是我最终做的:

我首先处理 Camera.Parameters getSupportedPictureSizes 以使用第一个高度和宽度都大于我想要的大小且宽度:高度比相同的参数。我将相机参数设置为该图片大小。

然后一旦拍照:

BitmapFactory.Options options = new BitmapFactory.Options();;
options.inPurgeable = true;

// convert the byte array to a bitmap, taking care to allow for garbage collection
Bitmap original = BitmapFactory.decodeByteArray(input , 0, input.length, options);
// resize the bitmap to my desired scale 
Bitmap resized = Bitmap.createScaledBitmap(original, 1600, 1200, true);

// create a new byte array and output the bitmap to a compressed JPG
ByteArrayOutputStream blob = new ByteArrayOutputStream();
resized.compress(Bitmap.CompressFormat.JPEG, 30, blob);

// recycle the memory since bitmaps seem to have slightly different garbage collection
original.recycle();
resized.recycle();

byte[] desired = blob.toByteArray();

然后我将所需的 jpg 写入文件以供上传。

【问题讨论】:

【参考方案1】:
test = testSizes.get(3);
// get(3) is 1600 x 1200

不要求数组有 4 个以上的元素,更不用说第四个元素是 1600x1200。

1) 弄清楚如何捕获 1600x1200 尺寸而不会出现崩溃或条纹

无法保证每台设备都能以该精确分辨率拍摄照片。您不能为分辨率指定任意值——它必须是支持的图片尺寸之一。 一些设备支持任意值,而其他设备会给你提供损坏的输出(就像这里的情况一样)或者会彻底崩溃。

2) 弄清楚如何将默认图片大小更改为 JPG 即 1600x1200

我不知道有“默认图片大小”,除此之外,这样的大小将是不可变的,因为它是默认值。更改图片大小是您上面的选项#1。

3) 我目前不知道的其他事情。

对于支持两个轴上更大分辨率的设备,请以该分辨率拍照,然后裁剪为 1600x1200。

对于所有其他设备,如果一个或两个轴都小于所需的,请以适合您的任何分辨率(最大、最接近 4:3 纵横比等)拍照,然后拉伸/裁剪以达到1600x1200。

【讨论】:

令我感到奇怪的是,1600x1200 尺寸被列为支持的图片尺寸,但我仍然得到损坏的输出。由于供应商的要求,我无法拉伸或收缩一个方向(检查图像捕获以获取存款)。我可以根据用户在预览窗口中对齐图像的方式来裁剪顶部。我需要使用位图进行图像处理然后转换为 jpg 吗? (默认大小是指在我更改任何设置之前来自 getPictureSize() 的大小。) @Gravitoid:“让我感到奇怪的是,1600x1200 尺寸被列为支持的图片尺寸,但我的输出仍然损坏”——这当然是可能的。我通常专注于最高的相机分辨率,并且肯定有设备报告的分辨率会产生有缺陷的输出。 “由于供应商的要求,我无法拉伸或收缩一个方向”——那么您就无法编写您的应用程序,因为没有要求相机在任何给定轴上完全支持 1600 或 1200 像素。 @Gravitoid:此外,我很困惑你为什么担心“裸奔”。您自己承认,您的应用在某些设备上崩溃。相比之下,有条纹的图像是阳性结果。 感谢您提供的好信息。我担心崩溃发生在三星 Galaxy S4 上,这是一款非常受欢迎的手机,我不愿意说我的应用程序不支持这款手机。我宁愿找到一个适用于 S4 以及所有已经工作的手机的解决方案。裸奔/损坏出现在 Nexus 7 平板电脑上,虽然比崩溃要好,但仍然不是可用的结果(我碰巧拥有 Nexus,但没有 S4)。如果我使用尽可能高的分辨率,或者如果它与 4:3 的比例匹配,则使用当前设置的分辨率,关于如何达到 1600x1200 的任何建议? @Gravitoid:“我不愿意说我的应用程序不支持手机”——您的供应商需要接受现实,并非每个相机都会屈服于他们的意愿。裁剪和/或缩放是不可避免的。 “关于如何达到 1600x1200 的任何建议?” - 正如我在回答中所述,您必须裁剪或缩放。有createBitmap()createScaledBitmap() 可以处理这个问题。

以上是关于Android相机参数setPictureSize导致图片出现条纹的主要内容,如果未能解决你的问题,请参考以下文章

Android:Camera2错误参数传递给相机服务

android studio怎么调用相机

android相机surfaceview方向

android如何获取相机分辨率?

获取相机焦距 OpenCV Android

Android Camera 调用系统相机应用