camera 预览角度,拍照角度,视频角度,Exif Meida 角度,算法角度

照片显示的角度需要转换

开发Camera过程中会遇到Camera拍照,获取照片后可以上传照片或者展示给用户。
Camera的图像数据来源于摄像头硬件的图像传感器,这个图像传感器被固定到手机上后会有一个默认的方向,一般默认方向是当手机左侧横放时(手机横放并且手机顶部在左侧)。由于默认图片传感器为横向,大部分手机拍照则是竖向,所以得到的数据依然会是横向的,这时就需要对图片进行旋转。
图像传感器的取景方向与手机正常方向成90读夹角。
在这里插入图片描述

由于Camera默认是横向的,竖向拍照时得到的照片和预览的照片会有所不同,因为预览可以利用setDisplayOrientation设置预览角度调节预览图片,但是setDisplayOrientation只是改变了预览的角度,对于拍摄生成的图片依然会拿到原来的未被旋转和默认图片传感器方向相同的数据。而对于前置摄像头预览得到的图片会比后置摄像头多一个镜面效果,两者都需要对拍摄生成的图片进行旋转处理才能得到正常的符合眼睛所看到的预览图片的样式。

 

 

 

0.  获取当前设备的旋转角度

public Classs Activity{


private OrientationEventListener mOrientationListener;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   mOrientationListener = new CameraOrientationEventListener(getApplicationContext());
 }

 @Override
 protected void onResume() {
  super.onResume();
  mOrientationListener.enable();
 }

 @Override
 protected void onPause() {
  super.onPause();
  mOrientationListener.disable();
 }

 private class CameraOrientationEventListener  extends OrientationEventListener {
   CameraOrientationEventListener(Context context) {
   super(context);
 }

 @Override
 public void onOrientationChanged(int orientation) {
        // orientation ( 0- 360)
        // newOrientation (0, 90, 180, 270)
        int newOrientation = roundOrientation(orientation, mOrientation);
    if (newOrientation == mOrientation) {
             return;
    }
 
    mOrientation = newOrientation;
    int deviceRotation = getWindowManager().getDefaultDisplay().getRotation();
    Log.d(TAG, "onOrientationChanged newOrientation:" + orientation + ", nowOrientation: " + 
    mOrientation + ", deviceRotation:" + deviceRotation);
  }
 }  


//将 当前设备旋转角度 转换  ( 0- 360) ---> (0, 90, 180, 270)
public  int roundOrientation(int orientation, int orientationHistory) {
    boolean changeOrientation ;
    if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
        changeOrientation = true;
    } else {
     int dist = Math.abs(orientation - orientationHistory);
     dist = Math.min(dist, 360 - dist);
     changeOrientation = (dist >= 45 + 5);
    }

   if (changeOrientation) {
     return ((orientation + 45) / 90 * 90) % 360;
   }
    return orientationHistory;
  }

}


//获取显示角度
int getDisplayOrientation(){
    return   deviceSensorToDisplayRotation();

}


// 将 设置当前角度  与  sensor 角度计算转换,生成最终display角度
public int deviceSensorToDisplayRotation(CameraCharacteristics mCharacteristics) {
   int orientation ;
   sensorOrientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
   if (mCharacteristics.get(CameraCharacteristics.LENS_FACING) 
            ==  CameraCharacteristics.LENS_FACING_FRONT) {
        orientation = (sensorOrientation - mOrientation + 360) % 360;
        isBackCamera = false;
   } else {
        orientation = (sensorOrientation + mOrientation) % 360;
        isBackCamera = true;
   }

    int windowRotation = getWindowManager().getDefaultDisplay().getRotation();
    int windowOrientation = ORIENTATIONS.get(windowRotation);
    Log.d(TAG, "deviceSensorToDisplayRotation "
+ "  windowRotation:" + windowRotation
            + ", windowOrientation:" + windowOrientation
            + ", deviceOrientation:" + mOrientation
+ ", sensorOrientation" + sensorOrientation
+ ", displayOrientation:" + orientation);
    return orientation;
}

------  另外一种获取当前设备旋转角度方式(不是很推荐,建议用 0)-----------------------

@Override
public void onSensorChanged(SensorEvent event) {
    //手机移动一段时间后静止,然后静止一段时间后进行对焦
    // 读取加速度传感器数值,values数组0,1,2分别对应x,y,z轴的加速度
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        int x = (int) event.values[0];
        int y = (int) event.values[1];
        int z = (int) event.values[2];
    }
   mSensorRotation = calculateSensorRotation(event.values[0],event.values[1]);
}

public  int calculateSensorRotation(float x, float y) {
    //x是values[0]的值,X轴方向加速度,从左侧向右侧移动,values[0]为负值;从右向左移动,values[0]为正值
    //y是values[1]的值,Y轴方向加速度,从上到下移动,values[1]为负值;从下往上移动,values[1]为正值
    //不考虑Z轴上的数据,
    if (Math.abs(x) > 6 && Math.abs(y) < 4) {
        if (x > 6) {
            return 270;
        } else {
            return 90;
        }
    } else if (Math.abs(y) > 6 && Math.abs(x) < 4) {
        if (y > 6) {
            return 0;
        } else {
            return 180;
        }
    }
    return -1;
}
***********************  官方提供的JPEG图片方向算法 ***************
  private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
          if (deviceOrientation == OrientationEventListener.ORIENTATION_UNKNOWN){
              return 0;
          }
          int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);//获取传感器方向

          // Round device orientation to a multiple of 90
          deviceOrientation = (deviceOrientation + 45) / 90 * 90;

          // Reverse device orientation for front-facing cameras
          boolean facingFront = c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;//判断摄像头面向
          if (facingFront) {
              deviceOrientation = -deviceOrientation;
          }

          // Calculate desired JPEG orientation relative to camera orientation to make
          // the image upright relative to the device orientation
          int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;

          return jpegOrientation;
    }

1. JPEG 拍照的角度设置, 部分手机可能不管用

final CaptureRequest.Builder snapShotCaptureBuilder = 
    mOneCamera.getDisplayOrientation(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
    getSupportedThumbnailSizes();
     //设置  JPEG_ORIENTATION
    captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, 
    getDisplayOrientation(mOrientation));

2. 视频的角度设置

int orientation = getDisplayOrientation(mOrientation);
mMediaRecorder.setOrientationHint(orientation);

3.  af ae 角度设置

 

4. 保存照片的角度Exif 设置



int orientation = mOneCamera.getDisplayOrientation(mOrientation);

ExifInterface exif = onProcessCaptureExifTags(bytes, location, orientation, mTotalCaptureResult, false);

ExifInterface onProcessCaptureExifTags(byte[] bytes, Location location, int orientation, TotalCaptureResult result, Boolean mForceFlashOn) {
    ExifInterface exif;
    if(bytes == null){
         exif = new ExifInterface();
   }else{
        exif = Exif.getExif(bytes);
    }

    exif.addMakeAndModelTag();
    //add to exif
    exif.addOrientationTag(orientation);

}

 4.1 可能有些图片经过变化(裁剪,缩放等,exif中的值会变化), 可以在保存图片时,对图片本身数据进行旋转。

Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

Matrix matrix = new Matrix()

matrix.setRotate(rotation);  //rotation 和 exif中写入的一样

matrix.postScale(-1,1);

result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

5. 设置媒体库 Media中的角度




public static ContentValues getContentValuesForData(String title,
        long date, Location location, int orientation, int jpegLength,
  String path, int width, int height, String mimeType,long burstShotId, int fileType) {
  // Insert into MediaStore.
  ContentValues values = new ContentValues();
  values.put(ImageColumns.TITLE, title);
    if (mimeType.equalsIgnoreCase("jpeg") ||
        mimeType.equalsIgnoreCase("image/jpeg")) {
        values.put(ImageColumns.DISPLAY_NAME, title + ".jpg");
  } else {
        values.put(ImageColumns.DISPLAY_NAME, title + ".raw");
  }
  values.put(ImageColumns.DATE_TAKEN, date);
  values.put(ImageColumns.MIME_TYPE, "image/jpeg");
  // Clockwise rotation in degrees. 0, 90, 180, or 270.
  values.put(ImageColumns.ORIENTATION, orientation);
  values.put(ImageColumns.DATA, path);
  values.put(ImageColumns.SIZE, jpegLength);
}

6.算法设置角度


设置
setSensorOrientation(mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) )


使用
@Override
public void setSensorOrientation(int orientation) {
    mOrientation = orientation;
}
BeaurifyJniSdk.preViewInstance().nativeReset(mTextureWidth,mTextureHeight,mOrientation);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空白的泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值