相机预览处于纵向模式,但拍摄的图像已旋转

Posted

技术标签:

【中文标题】相机预览处于纵向模式,但拍摄的图像已旋转【英文标题】:Camera preview is in portrait mode but image captured is rotated 【发布时间】:2013-04-14 06:18:29 【问题描述】:

我正在尝试使用相机拍摄照片。默认情况下预览是横向模式,我可以使用将其更改为纵向模式

    setCameraDisplayOrientation(this,1,  mCamera);
    public 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);
 

捕获的图像存储在 myImages 文件夹下。但是图像是旋转的。 (看起来图像是在横向模式下拍摄的)

那么如何旋转捕获的图像并保存?

public class MainActivity extends Activity 

private static final int REQUEST_CODE = 1; 
ImageView imageView;
Button b;
private Camera mCamera;
private CameraPreview mPreview;
private Bitmap bitmap;
private PictureCallback mPicture;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    boolean check =checkCameraHardware(MainActivity.this);
    if(check)
    
         mCamera = getCameraInstance();

        // mCamera.setDisplayOrientation(90);
         setCameraDisplayOrientation(this,
                 1,  mCamera);//requires min sdk 9
    
    // Create an instance of Camera
    mPicture = new PictureCallback() 

        @Override
        public void onPictureTaken(byte[] data, Camera camera) 

            File imagesFolder = new File(Environment.getExternalStorageDirectory(), "MyImages");
            if(!imagesFolder.exists())
            imagesFolder.mkdirs();   
            File pictureFile = new File(imagesFolder, "image.jpg");

            try 
                FileOutputStream fos = new FileOutputStream(pictureFile);

                System.out.println("hello");
                fos.write(data);
                fos.close();
             catch (FileNotFoundException e) 
                Log.d("No File", "File not found: " + e.getMessage());
             catch (IOException e) 
                //Log.d(TAG, "Error accessing file: " + e.getMessage());
            
        
    ;

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview);
     b = (Button) findViewById(R.id.button_capture);
     b.setOnClickListener(new OnClickListener()
      

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub
                 mCamera.takePicture(null, null, mPicture);
                 Toast.makeText(MainActivity.this, "Called",1000).show();

        

      );
  
 public 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);
 
private boolean checkCameraHardware(Context context) 
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))
        // this device has a camera
         Toast.makeText(this, "Phone has camera", Toast.LENGTH_LONG).show();
        return true;
     else 
        // no camera on this device
         Toast.makeText(this, "Phone has no camera", Toast.LENGTH_LONG).show();
        return false;
    

public static Camera getCameraInstance()
    Camera c = null;
    try 
        c = Camera.open(); // attempt to get a Camera instance
    
    catch (Exception e)
        // Camera is not available (in use or does not exist)
    
    return c; // returns null if camera is unavailable



@Override
protected void onDestroy() 
    // TODO Auto-generated method stub
    super.onDestroy();
    mCamera.release();

  

CameraPreview 类与开发者网站http://developer.android.com/guide/topics/media/camera.html 相同

注意:我使用的是后置摄像头而不是前置摄像头。

【问题讨论】:

我在另一个帖子***.com/a/34323194/4847767回答了类似的问题 【参考方案1】:

我在以人像模式从相机拍照时遇到了同样的问题。下面的代码行解决了我的问题:

public 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);

在surfaceCreated回调中调用setCameraDisplayOrientation()方法如下:

@Override
public void surfaceCreated(SurfaceHolder holder) 
    camera = Camera.open();
    setCameraDisplayOrientation(getActivity(), CameraInfo.CAMERA_FACING_BACK, camera);

我不得不在相机onPictureTaken()回调中旋转图像:

camera.takePicture(null, null, new PictureCallback() 

        @Override
        public void onPictureTaken(byte[] data, Camera camera) 

            if (data != null) 
                int screenWidth = getResources().getDisplayMetrics().widthPixels;
                int screenHeight = getResources().getDisplayMetrics().heightPixels;
                Bitmap bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);

                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) 
                    // Notice that width and height are reversed
                    Bitmap scaled = Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true);
                    int w = scaled.getWidth();
                    int h = scaled.getHeight();
                    // Setting post rotate to 90
                    Matrix mtx = new Matrix();
                    mtx.postRotate(90);
                    // Rotating Bitmap
                    bm = Bitmap.createBitmap(scaled, 0, 0, w, h, mtx, true);
                else// LANDSCAPE MODE
                    //No need to reverse width and height
                    Bitmap scaled = Bitmap.createScaledBitmap(bm, screenWidth,screenHeight , true);
                    bm=scaled;
                
                photoPreview.setImageBitmap(bm);
            
            isImageCaptured = true;
            photoPreview.setVisibility(View.VISIBLE);
            surfaceView.setVisibility(View.GONE);
        
);

【讨论】:

我也对相同的问题应用了相同的解决方案,但在开始时我得到了我们的内存错误。然后我存储压缩位图以摆脱这种情况。但是在我的屏幕上创建新的位图时,这个过程非常慢。半分钟我的应用程序卡在黑屏中。你有什么解决办法吗 @HemantG 你能告诉我我应该在哪里写方向代码,因为我的图片在只有前置摄像头的情况下旋转...... @HemantG 您的解决方案中的一切都很酷,而且肯定会奏效。您在旋转之前缩小位图以避免 OutOfMemory 异常。如果我们保存这个新的位图,那么它将是原始位图的缩小版本。我想以原始分辨率保存位图而不会出现 OutOfMemory 异常。我怎样才能做到这一点?为什么即使预览是纵向的,相机也会给出旋转的图像?请帮帮我。 我正在通过此代码从后置摄像头旋转图像,但在字体摄像头中,图像旋转了 180 度。我该怎么办。【参考方案2】:

以下代码适用于前置摄像头。

if (data != null) 
                try 
                    int screenWidth = getResources().getDisplayMetrics().widthPixels;
                    int screenHeight = getResources().getDisplayMetrics().heightPixels;
                    bm = BitmapFactory.decodeByteArray(data, 0,
                            (data != null) ? data.length : 0);
                    CameraInfo info = new CameraInfo();
                    Camera.getCameraInfo(cameraFace, info);
                    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) 
                        // Notice that width and height are reversed
                        // Bitmap scaled = Bitmap.createScaledBitmap(bm,
                        // screenHeight, screenWidth, true);
                        // int w = scaled.getWidth();
                        // int h = scaled.getHeight();
                        // Setting post rotate to 90
                        Matrix mtx = new Matrix();
                        mtx.postRotate(90);
                        if (cameraFace == CameraInfo.CAMERA_FACING_FRONT)
                            mtx.postRotate(180);
                        // Rotating Bitmap
                        bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
                                bm.getHeight(), mtx, true);
                     else // LANDSCAPE MODE
                        Bitmap scaled = Bitmap.createScaledBitmap(bm,
                                screenWidth, screenHeight, true);
                        bm = scaled;
                    
                 catch (Exception e) 
                 catch (Error e) 
                
            

【讨论】:

【参考方案3】:

是的,我尝试了答案中的方式,它适用于后置摄像头,对于前置摄像头,它需要旋转 270 而不是 90。:)

【讨论】:

以上是关于相机预览处于纵向模式,但拍摄的图像已旋转的主要内容,如果未能解决你的问题,请参考以下文章

在android中设置相机拍摄的图像?

Android相机预览始终是侧面的

上传到 Firebase 时出现图片方向问题

Camera2 API预览方面已损坏

仅支持纵向界面时如何保存相机图像

以纵向模式从相机拍摄的加载到画布上的照片是横向的