草庐IT

Android 相机预览看起来很奇怪

coder 2023-11-29 原文

我正在实现一个相机应用程序,当我查看预览时(尤其是使用前置摄像头时),图像非常胖。看起来图像被水平拉伸(stretch)了。我按照 sdk 示例使用优化的相机尺寸,但它没有帮助。如何调整我的相机设置,使其像其他相机应用程序一样预览?

谢谢。

我的代码如下。

public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback {

Camera m_camera;
SurfaceView m_surfaceView;
int m_numOfCamera;
int m_defaultCameraId;
int m_currentCamera;
int m_surfaceWidth;
int m_surfaceHeight;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera);
    getActionBar().setDisplayHomeAsUpEnabled(true);


    m_surfaceView = (SurfaceView)findViewById(R.id.cameraPreview);
    m_surfaceView.getHolder().addCallback(this);

    m_camera = Camera.open();

    m_numOfCamera = Camera.getNumberOfCameras();

    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < m_numOfCamera; ++i) {
        Camera.getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            m_defaultCameraId = i;
            m_currentCamera = m_defaultCameraId;
        }       
    }

    if (m_numOfCamera < 1) {
        MenuItem switchCam = (MenuItem)findViewById(R.id.menu_switch_camera);
        switchCam.setVisible(false);
    }
}

@Override
public void onPause() {
    super.onPause();
    m_camera.stopPreview();
}

@Override
public void onDestroy() {
    super.onDestroy();
    m_camera.release();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_camera, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) 
{
    if (item.getItemId() == android.R.id.home) 
    {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);

        return true;
    } 
    else if (item.getItemId() == R.id.menu_switch_camera)
    {
        if (m_camera != null) {
            m_camera.stopPreview();
            m_camera.release();
            m_camera = null;
        }   

        m_camera = Camera.open((m_currentCamera + 1) % m_numOfCamera);
        m_currentCamera = (m_currentCamera + 1) % m_numOfCamera;

        Camera.Parameters params = m_camera.getParameters();
        List<Camera.Size> sizes = params.getSupportedPreviewSizes();
        Camera.Size size = getOptimalPreviewSize(sizes, m_surfaceWidth, m_surfaceHeight);

        params.setPreviewSize(size.width,  size.height);

        m_camera.setParameters(params);
        setCameraDisplayOrientation(this, m_currentCamera, m_camera);
        m_camera.startPreview();
        try {
            m_camera.setPreviewDisplay(m_surfaceView.getHolder());
        } catch (Exception e) {
            e.printStackTrace();
        }   
        return true;
    }
    return true;
}

public void onPictureTaken(byte[] arg0, Camera arg1) {
    // TODO Auto-generated method stub

}

public void onShutter() {
    // TODO Auto-generated method stub

}

public void surfaceChanged(SurfaceHolder arg0, int format, int w, int h) {
    m_surfaceWidth = w;
    m_surfaceHeight = h;
    Camera.Parameters params = m_camera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size selected = getOptimalPreviewSize(sizes, w, h);

    params.setPreviewSize(selected.width,  selected.height);


    m_camera.setParameters(params);
    setCameraDisplayOrientation(this, m_currentCamera, m_camera);
    m_camera.startPreview();    
}

private static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }


public void surfaceCreated(SurfaceHolder arg0) {
    try {
        m_camera.setPreviewDisplay(m_surfaceView.getHolder());
    } catch (Exception e) {
        e.printStackTrace();
    }   
}

public void surfaceDestroyed(SurfaceHolder arg0) {
    // TODO Auto-generated method stub

}

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {


    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) w / h;
    if (sizes == null)
        return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (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);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }

    return optimalSize;
}

}

最佳答案

相机预览总是填满显示它的 SurfaceView。如果 m_surfaceView 的纵横比与相机的纵横比不匹配,预览将被拉伸(stretch)。

您需要创建匹配宽高比的 m_surfaceView。这意味着,您需要从代码而不是布局 XML 文件创建它。

您可以在 android 示例项目中找到一个示例项目 APIDemos。在项目中有一个名为 CameraPreview 的东西。这对在 SurfaceView 中设置相机预览有很好的演示。它有一个 extends ViewGroup 的类,并从代码中添加 SurfaceView 作为其子级。 onMeasure() 方法已被覆盖以确定 SurfaceView 的高度和宽度,因此纵横比得以保留。看看这个项目,我希望它会很清楚。

[抱歉,我无法在此处发布链接 - this应该是链接,但我发现它坏了。但是如果你已经安装了带有 Android SDK 的示例项目,你可以在示例中找到该项目。打开一个新的 Android 示例项目,选择 APIDemos,然后查找名为 CameraPreview 的类。据我所知,它应该在 com.example.android.apis.graphics 包中。]

关于Android 相机预览看起来很奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12751016/

有关Android 相机预览看起来很奇怪的更多相关文章

  1. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  2. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  3. ruby-on-rails - 浮点乘法的 Ruby 奇怪问题 - 2

    有没有人用ruby​​解决这个问题:假设我们有:a=8.1999999我们想将它四舍五入为2位小数,即8.20,然后乘以1,000,000得到8,200,000我们是这样做的;(a.round(2)*1000000).to_i但是我们得到的是8199999,为什么?奇怪的是,如果我们乘以1000、100000或10000000而不是1000000,我们会得到正确的结果。有人知道为什么吗?我们正在使用ruby​​1.9.2并尝试使用1.9.3。谢谢! 最佳答案 每当你在计算中得到时髦的数字时使用bigdecimalrequire'bi

  4. ruby - 奇怪的 ruby​​ for 循环行为(为什么这样做有效) - 2

    defreverse(ary)result=[]forresult[0,0]inaryendresultendassert_equal["baz","bar","foo"],reverse(["foo","bar","baz"])这行得通,我想了解原因。有什么解释吗? 最佳答案 如果我使用each而不是for/in重写它,它看起来像这样:defreverse(ary)result=[]#forresult[0,0]inaryary.eachdo|item|result[0,0]=itemendresultendforainb基本上就

  5. ruby-on-rails - ruby数组奇怪的东西(无限数组) - 2

    当我写下面的代码时:x=[1,2,3]x我得到这个输出:[1,2,3,[...]][1,2,3,[...]][1,2,3,[...]]我不应该只得到[1,2,3,[1,2,3]]吗?解释是什么? 最佳答案 这没什么奇怪的。数组的第四个元素就是数组本身,所以当你求第四个元素时,你得到的是数组,当你求第四个元素的第四个元素时,你得到的是数组,当你求第四个元素时,你得到的是数组。第四个元素的第四个元素的第四个元素的元素......你得到了数组。就这么简单。唯一有点不寻常的是Array#to_s检测到这样的递归,而不是进入无限循环,而是返回

  6. ruby - 比较 rspec 中的 float 时的奇怪行为 - 2

    以下测试中的第3个失败:specify{(0.6*2).shouldeql(1.2)}specify{(0.3*3).shouldeql(0.3*3)}specify{(0.3*3).shouldeql(0.9)}#thisonefails这是为什么呢?这是浮点问题还是ruby​​或rspec问题? 最佳答案 从rspec-2.1开始specify{(0.6*2).shouldbe_within(0.01).of(1.2)}在那之前:specify{(0.6*2).shouldbe_close(1.2,0.01)}

  7. ruby-on-rails - ruby:将数组的每个元素用附加引号引起来 - 2

    我有以下字符串:a="001;Barbara;122"我拆分成字符串数组:names=a.split(";")names=["001","Barbara","122"]我应该怎么做才能将每​​个元素另外用''引号括起来?结果应该是names=["'001'","'Barbara'","'122'"]我知道这听起来很奇怪,但我需要它在ruby​​onrails中进行数据库查询。出于某种原因,如果我的名字在“”引号中,我将无法访问数据库记录。我在数据库中确实有mk1==0006但rails不想以某种方式访问​​它。但是,它确实访问1222。sql="SELECTmk1,mk2,pk1,pk

  8. ruby - Rails 3 应用程序的 respond_with 语法有奇怪的行为吗? - 2

    在为提供json的Rails3.0.3应用构建API时,发生了一些意外行为。以下是Controller。问题是关于respond_with。我已经在应用程序Controller中有respond_to:json。createAction正常运行,创建后数据也被发回。但是更新操作的respond_with不会发回任何数据。响应主体为空白。defcreateline=get_lineinput_header=line.input_headers.create(params[:input_header])respond_with(input_header,:location=>api_v1_

  9. ruby-on-rails - Rake 预览在 Octopress 中不起作用 - 2

    我在我的机器上安装了ruby​​版本1.9.3,并且正在为我的个人网站开发一个octopress项目。我为我的gems使用了rvm,并遵循了octopress.org记录的所有步骤。但是我在我的rake服务器中发现了一些错误。这是我的命令日志。Tin-Aung-Linn:octopresstal$ruby--versionruby1.9.3p448(2013-06-27revision41675)[x86_64-darwin12.4.0]Tin-Aung-Linn:octopresstal$rakegenerate##GeneratingSitewithJekyllidenticals

  10. arrays - 数组元素赋值的奇怪行为 - 2

    今天我遇到了数组元素赋值的一些奇怪行为:arr=["a","b"]arr2=[1,2]arr.unshift(arr2)#=[[1,2],"a","b"]arr.push(arr2)#=>["a","b",[1,2]]但是,这是有道理的:arr[0,0]=arr2#=>[1,2,"a","b"]我知道在[0,0]中,第一个零是index,第二个是该数组中从index开始的元素数。在我看来它应该与unshift相同,但事实并非如此。谁能解释一下这种行为? 最佳答案 如果我们diveintotherubysourcecode,我们会找到

随机推荐