1. 程式人生 > >Android多媒體之---Camera實時視訊採集預覽時方向處理

Android多媒體之---Camera實時視訊採集預覽時方向處理

手機攝像頭(Camera)的影象資料來源於攝像頭硬體的影象感測器,這個影象感測器被固定到手機上後會有一個預設的取景方向,這個取景方向恰好是當手機左側橫放時的方向,其座標原點於手機橫放時的左上角。手機的正常方向和影象感測器預設取景方向示意圖如下:
這裡寫圖片描述

Camera預覽方向處理:

從上面的示意圖可知,影象感測器的取景方向與手機正常方向成90讀夾角,按理來說,當我們以正常的手機方向來開啟相機時,看到的預覽影象應該是橫向的。但是,當我們開啟系統相機後,看到的預覽影象卻是正常的,即預覽影象與手機方向一致。這是因為系統自帶的相機在Android系統底層根據當前手機螢幕的方向對影象感測器採集到的資料進行了旋轉,所以無論我們怎麼旋轉手機螢幕,看到的相機預覽圖片始終是“正常”的。而對於自定義的相機,,如果沒有對影象感測器的圖片進行旋轉處理,那麼看到的預覽圖片就是橫向的:

這裡寫圖片描述

為了解決自定義相機預覽方向不正常情況,Android系統提供了一個API來手動設定Camera的預覽方向,即Camera.setDisplayOrientation(int rotateDegree),預設情況下該方法的值為0,與影象感測器取景方向一致。旋轉方法:

首先,通過Display的getOrientation()獲得當前手機的方向,如Surface.ROTATION_0表示手機豎屏時正常方向、Surface.ROTATION_90表示手機方向向右手邊橫向放置等(沿順時針判斷)。其中,Display display = getWindowManager().getDefaultDisplay()獲得。
其次,對於後置攝像頭來說,它的預覽成像為CameraInfo.orientatio- phoneDegree,但由於這個值可能為負,角度值不能為負故需要加上360求正;對於前置攝像頭(front camera)來說,它的預覽影象在旋轉之前是水平翻轉的,也就是前置攝像頭的預覽成像是沿影象的中央垂直線翻轉過來,就像使用者照鏡子一樣的效果。因此,在得到前置攝像頭的旋轉角度後(rotation = CameraInfo.orientatio + degrees),還需要對其進行水平翻轉(rotation = 360-rotation),即取rotation的負數即可,但是由於旋轉的角度不能是負數,因此再加上360求正。其中,CameraInfo.orientatio是影象感應器相對於手機豎直正常方向的角度值、手機方向為相對於豎直正常方向沿順時針轉動的方向值。另外,當我們得到前後置攝像頭旋轉的方向後還需要對360求餘,以防止旋轉的角度超過一週360度的情況。

具體程式碼如下:

private int getPreviewRotateDegree(){  
    int phoneDegree = 0;  
    int result = 0;  
    //獲得手機方向  
    int phoneRotate =getWindowManager().getDefaultDisplay().getOrientation();  
    //得到手機的角度  
    switch (phoneRotate) {  
        case Surface.ROTATION_0: phoneDegree = 0; break;        //0  
case Surface.ROTATION_90: phoneDegree = 90; break; //90 case Surface.ROTATION_180: phoneDegree = 180; break; //180 case Surface.ROTATION_270: phoneDegree = 270; break; //270 } //分別計算前後置攝像頭需要旋轉的角度 Camera.CameraInfo cameraInfo = new CameraInfo(); if(isFrontCamera){ Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, cameraInfo); result = (cameraInfo.orientation + phoneDegree) % 360; result = (360 - result) % 360; }else{ Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, cameraInfo); result = (cameraInfo.orientation - phoneDegree +360) % 360; } return result; }

//進行Camera預覽旋轉  
Camera mCamera = Camera.open();  
int rotateDegree = getPreviewRotateDegree();  
mCamera.setDisplayOrientation(rotateDegree);  

注意:上述方法適用於預設預覽為豎屏應用,setDisplayOrientation (int degrees)只對預覽時旋轉圖片有效,但對onPreviewFrame(byte[],Camera)、JPEG拍照、視訊錄製的圖片旋轉無效。

.Camera拍照方向處理

由於使用Camera進行拍照時,是直接將影象感測器採集到的影象資料直接儲存到Sdcard卡,它通常不與預覽時看到的畫面方向一致,而是與影象感測器的方向一致。也就是說,當我們豎著拿著手機拍攝時,得到的照片看起來是不正常的(橫向的),這是因為豎著拿著手機正好與影象感測器的方向相差了90度;當橫著拿著手機拍攝時,得到的照片看起來才是正常的,。效果如下圖所示。

這裡寫圖片描述

Camera拍攝照片方向的處理與手機的方向緊密相關,而由於拍攝照片時手機的方向是不確定的,因此需要手機的方向感應器(OrientationEventListener)來捕獲手機的實時旋轉角度,當手機方向發現偏轉時OrientationEventListener的onOrientationChanged(int orientation)方法會立即被回撥,orientation即為實時變化的角度。旋轉方法:
首先,為了使相機對方向不那麼敏感,可以採用一個範圍來限定手機當前方向的角度值,比如當手機的方向處於45度~ 90度時,我們就認定手機當前轉動的角度為90度,依次類推得到手機大概的方向角度值。
其次,計算前後置攝像頭需要旋轉的角度。Camera的預覽效果是獲得影象感測器採集的影象資料後再將其顯示在顯示屏上,而拍攝照片則是直接將影象感測器採集的影象資料儲存到Sdcard上,因此,它們處理旋轉時的角度計算是不同的。由於影象感測器的取景方向與手機豎直方向恰好相差90度,因此,對於後置攝像頭來說,其旋轉的角度應該手機實際變化的角度加上影象感測器與手機之間的夾角,即mOrientation=cameraInfo.orientation +phoneDegree;對於前置攝像頭來說,旋轉的角度mOrientation=cameraInfo.orientation – phoneDegree。以手機方向改變270度為例,效果如下圖(2)所示,後置攝像頭需旋轉的角度為(270+90),可見剛好為360度使攝像頭與影象感測器方向一致,那麼旋轉的角度進行求餘處理後剛好為0。由於前置攝像頭是水平翻轉的,因此需要對需要進行水平翻轉處理,也就是180度的問題,最終旋轉的角度為|(90-270)|=180。

這裡寫圖片描述

這裡寫圖片描述

具體程式碼如下:

private void startOrientationListener() {  
OrientationEventListener mOrEventListener = new OrientationEventListener(mContext) {  
@Override  
public void onOrientationChanged(int orientation) {  
//計算手機當前方向的角度值  
int phoneDegree = 0;  
if (((orientation >= 0) && (orientation <= 45))|| (orientation > 315) &&(orientation<=360)) {  
phoneDegree = 0;  
} else if ((orientation > 45) && (orientation <= 135)) {  
phoneDegree = 90;  
} else if ((orientation > 135) && (orientation <= 225)) {  
phoneDegree = 180;  
} else if ((orientation > 225) && (orientation <= 315)) {  
phoneDegree = 270;  
}  
//分別計算前後置攝像頭需要旋轉的角度  
Camera.CameraInfo cameraInfo = new CameraInfo();  
if(mFragment.isFrontCamera()){  
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, cameraInfo);  
mOrientation = (cameraInfo.orientation - phoneDegree +360) % 360;  
}else{  
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, cameraInfo);  
mOrientation = (cameraInfo.orientation + phoneDegree) % 360;  
}  
};  
//啟動方向感應器  
mOrEventListener.enable();  
}  

注意:由於上述涉及的角度值都是正數且不大於360度,因此,需要對相關角度進行求正和求餘處理。

JPEG圖片方向處理

有這麼一種情況,如果有一款自定義相機的拍照功能忘記處理圖片旋轉的問題,那麼我們
在使用的過程中就會看到拍下的JPEG照片顯示方向“不正常”。針對於這種情況,可以通過Android API提供的ExifInterface介面來解決,該介面儲存了指定JPEG圖片的詳細資訊,比如拍攝時的角度、曝光度、解析度等等。旋轉方法:
首先,根據圖片路徑建立一個ExifInterface物件,再呼叫其getAttributeInt(
ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL)方法,得到JPEG拍攝時的角度。
其次,呼叫Matrix的postRotate(degree)方法對圖片進行旋轉,然後再使用Bitmap.createBitmap方法得到最終的點陣圖物件。
具體程式碼如下:

public static int getPictureDegress(String filePath) {  
int degree = 0;  
ExifInterface exifInterface = null;  
try {  
exifInterface = new ExifInterface(filePath);  
} catch (IOException e) {  
e.printStackTrace();  
}  
if (exifInterface != null) {  
//獲得圖片拍攝角度,第二個的作用是如果這個屬性不存在,則作為預設值返回  
int orientation = exifInterface.getAttributeInt(  
ExifInterface.TAG_ORIENTATION,  
ExifInterface.ORIENTATION_NORMAL);  
switch (orientation) {  
case ExifInterface.ORIENTATION_ROTATE_90:  
degree = 90;  
break;  
case ExifInterface.ORIENTATION_ROTATE_180:  
degree = 180;  
break;  
case ExifInterface.ORIENTATION_ROTATE_270:  
degree = 270;  
break;  
default:  
degree = 0;  
break;  
}  
return degree;  
}  
return 0;  
}  
/** 旋轉圖片 
* @param imgPath 原圖路徑 
* @ param imgPath 
*/  
public static Bitmap setBitmapDegreeZero(String imgPath) {  
Bitmap mBitmap = null;  
int degree = getPictureDegress(imgPath);  
if (degree != 0) {  
mBitmap = BitmapFactory.decodeFile(imgPath);  
Matrix matrix = new Matrix();  
matrix.postRotate(degree);  
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),  
mBitmap.getHeight(), matrix, true);  
}  
return mBitmap;  
}  

效果演示:

這裡寫圖片描述

相關推薦

Android多媒體---Camera實時視訊採集方向處理

手機攝像頭(Camera)的影象資料來源於攝像頭硬體的影象感測器,這個影象感測器被固定到手機上後會有一個預設的取景方向,這個取景方向恰好是當手機左側橫放時的方向,其座標原點於手機橫放時的左上角。手機的正常方向和影象感測器預設取景方向示意圖如下: C

Android多媒體技術(一)Camera實時視訊採集、拍照、JPEG圖片方向處理

Camera實時視訊採集預覽、拍照、JPEG圖片方向的處理                          作者:     蔣東國    時間:  2017年1月12日 星期四  

Android多媒體Camera的相關操作

零、前言 今天主要有兩點 1).介面佈局,檢視仿一下我手機自帶的相機 2).Camera的簡單使用,雖然Camera已經過時了,但還是來看一下,由簡入深 下一篇會介紹替代者:Camera2 溫馨提示:本文多圖預警,請Wifi觀看~ 許可權申請自行解決 <uses-permissi

Android自定義Camera,用SurfaceView

佈局檔案不用說了,就它了SurfaceView。其他花裡古哨的佈局,自己想著加吧! <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" an

Android 實時視訊採集/編碼/傳輸/解碼/播放—方案調研

實時視訊流採集 方案一:  通過Android Camera拍攝預覽中設定setPreviewCallback實現onPreviewFrame介面,實時擷取每一幀視訊流資料  方案二:  通過Android的MediaRecorder,在SetoutputFile函式中繫

Android多媒體視訊播放器高階開發

1.獲取播放的資料來源 播放視訊的資料來源一般有兩個,一個是請求網路,從伺服器後臺直接獲取播放的視訊資訊,另一種是播放手機中本地的視訊,這裡我們採用的播放源為播放手機本地的視訊 1.1 查詢獲取手機中的視訊的資訊 1.1.1 查詢方法一 定義要查詢到的視訊的資訊,包括視

Android實時視訊採集方案

實時視訊流採集 方案一:  通過Android Camera拍攝預覽中設定setPreviewCallback實現onPreviewFrame介面,實時擷取每一幀視訊流資料  方案二:  通過Android的MediaRecorder,在SetoutputFile函式中繫結

AndroidAndroid Camera實時資料採集及通過MediaCodec硬編碼編碼資料的流程

// video device. private Camera camera; private MediaCodec vencoder; private MediaCodecInfo vmci; private MediaCodec.BufferInfo vebi; private byte[] vbuff

Android 用MediaRecorder實時視訊採集

都是摸著石頭過河,花了整整一個星期,終於把技術難點給突破了,貌似網上對這個討論的較少。 主要需要實現的功能是在android手機上實時採集視訊,並在遠端比如PC機上實時顯示出來,也就是以android手機作為監控攝像頭。 一開始查到的是smartcam的一個開源專案,看了下原始碼,發現其實現原理是利用an

【我的Android進階旅】自定義控制元件使用ViewPager實現可以的畫廊效果,並且自定義畫面切換的動畫效果的切換時間

我們來看下效果 在這裡,我們實現的是,一個ViewPager來顯示圖片列表。這裡一個頁面,ViewPage展示了前後的預覽,我們讓預覽頁進行Y軸的壓縮,並設定透明度為0.5f,所有我們看到gif最後,左右兩邊的圖片有點朦朧感。讓預覽頁和主頁面有主從感。我們用分

Android Camera開發 給攝像頭介面加個ZoomBar(附完整程式碼下載)

                廢話不說了,就是加個seekbar,拖動的話能夠調節焦距,讓畫面變大或縮小。下面是核心程式:一,camera的佈局檔案<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    x

玩轉Android Camera開發(一):SurfaceviewCamera,基礎拍照功能完整demo

雜家前文是在2012年的除夕之夜倉促完成,後來很多人指出了一些問題,瑣事纏身一直沒有進行升級。後來隨著我自己的使用,越來越發現不出個升級版的demo是不行了。有時候就連我自己用這個demo測一些效能、功能點,用著都不順手。當初程式碼是在linux下寫的,弄到windows裡下

Android多媒體認識聲音、錄音與播放(PCM)

一、對聲音的簡單認識 1、模擬訊號[摘錄於此] 模擬訊號傳輸過程中就是利用感測器把各種自然界各種連續的訊號轉換為幾乎一模一樣的電訊號。 比如說話聲音,原本是聲帶的震動。經過麥克風的採集,將聲波訊號轉換為電訊號, 電訊號波形是和原來的聲波波形一樣的。只是換種物理量來表示和傳遞。(電訊號模擬振動訊號)。 複製

Android多媒體認識MP3與內建媒體播放(MediaPlayer)

零、前言 作為90後,mp3格式的音樂可謂靈魂之友。 小時候帶著耳機,躺在桌子上聽歌看月亮心情依稀。 當某個旋律想起,還會不會浮現某個風景,某個人……, 今天全程單曲播放——梁靜茹-勇氣(獻上頻譜) 主要任務:SD卡音樂、網路音訊流的播放及控制 MP3的

Android多媒體SoundPool+pcm流的音訊操作

零、前言 今天比較簡單,先理一下錄製和播放的四位大將 再說一下SoundPool的使用和pcm轉wav 講一下C++檔案如何在Android中使用,也就是傳說中的JNI 最後講一下變速播放和變調播放 一、AudioRecord和MediaRecorder,AudioTrack和MediaPl

Android多媒體Camera2的相關操作

零、前言 Android 5.0+ (API 21) ---->[原始碼裡讓我們用camera2] * @deprecated We recommend using the new {@link android.hardware.camera2} API for n

Android多媒體GL-ES戰記第一集--勇者集結

前言 1.本系列借花獻佛,結合了很多前人的文章以及書籍,我儘可能去總結並用我的思想進行加工 2.OpenGL一直是我的心結,也是時候去解開了,本系列稱不上原創,但每行程式碼都有著我思考的痕跡 3.本系列所有的圖片都是[張風捷特烈]所畫,如果有什麼錯誤還請指出,定會最快改正 4.本系列文章允許轉載、擷取

Android多媒體GL-ES戰記第二集--謎團立方

旁白:上集說到,為了獲取黑龍寶藏,勇者集結,共闖黑龍洞穴 經過一路艱辛,終於過了第四副本,前面還有什麼困難等待著他們?一起收看 第五副本:龍之圖陣 1.第一關卡:畫一個矩形 NPC:隱藏任務,解謎:GLES20.GL_TRIANGLE_STRIP繪製方式 發現逆時針畫的點貌似連的方式

Android多媒體GL-ES戰記第三集--聖火

前情回顧 旁邊: 勇者們為求黑龍寶藏,集結起來共闖黑龍副本,經歷重重艱辛, 終於獲得立方開啟了黑龍之門,這也只是新徵程的起點,後面將有更大的挑戰等著他們 張風捷特烈打開了門之後,看到了什麼?讓我們繼續收看 副本九:黑暗之淵 在開啟門後,光芒全部消失,眼中一團黑暗,張風捷特烈踏出一步

android 多媒體 MediaStore 學習記錄

1、開啟照相機,並將圖片儲存到  photoUri 路徑 Uri photoUri=Uri.fromFile(picFile); Intent cameraIntent =new Intent(MediaStore.ACTION_IMAGE_CAPTURE); camer