您好,登錄后才能下訂單哦!
前言
安卓開發(fā)中經(jīng)常有需要使用攝像頭的應用場景,對于初次接觸的同學攝像頭的方向是一個比較難弄清楚的概念,開發(fā)時很容易處理不當,本文將詳述該部分內(nèi)容幫助理解。
先看一個簡單的場景,打開手機的后置攝像頭拍攝,攝像頭捕獲的圖像幀數(shù)據(jù)可通過Camera.PreviewCallback回調(diào)中獲取,也就是攝像頭的輸出數(shù)據(jù),
void?onPreviewFrame(byte[]?data,?Camera?camera);
這里我們先忽略屏幕上的預覽,只關注攝像頭的輸出。如果把它保存為圖片或直接顯示出來,可以看到圖像和原始畫面相比逆時針旋轉(zhuǎn)了90度。
而我們?nèi)绻瑯邮褂胕Phone手機拍攝,輸出的結果是一個正向的圖片。
為什么輸出的圖像相比原始畫面旋轉(zhuǎn)了90度?因為設備的攝像頭存在一個“正向角度”,什么是攝像頭的正向?
通俗一點講,設備相當于人的身體,眼睛相當于攝像頭,眼睛把接收到的畫面反饋給大腦處理,相當于攝像頭把接收到的數(shù)據(jù)給應用程序處理。人眼能判斷出我們頭頂向上的方向是我們視覺上的正向,而后置攝像頭判斷的正向并不是手機物理屏幕向上的方向,而是物理屏幕右側的方向。我們想象一下,如果人眼是這個攝像頭,它認為右側才是我們的視覺正向,那我們看到的東西是不是都是旋轉(zhuǎn)90度的?這樣就比較好理解了。
上圖是手機在豎直和水平方向攝像頭“看”到的畫面。
固定設備,指定的攝像頭,正向角度固定的(0/90/180/270),和屏幕旋轉(zhuǎn)、橫豎屏切換無關,一般都在屏幕的右側(但不排除某些廠商修改成別的)。
這個角度在代碼中可通過Camera.CameraInfo
的orientation獲取,官方文檔也有解釋:
The orientation of the camera image. The value is the angle that the camera image needs to be rotated clockwise so it shows correctly on the display in its natural orientation. It should be 0, 90, 180, or 270.
For example, suppose a device has a naturally tall screen. The back-facing camera sensor is mounted in landscape. You are looking at the screen. If the top side of the camera sensor is aligned with the right edge of the screen in natural orientation, the value should be 90. If the top side of a front-facing camera sensor is aligned with the right of the screen, the value should be 270.
意思就是輸出的圖片需要順時針旋轉(zhuǎn)多少度,才能在自然方向上正確顯示。這里的自然方向就是以標題欄左上角為原點的屏幕渲染坐標系,圖片旋轉(zhuǎn)后,把它放到渲染坐標系中,能和原始畫面一樣正常顯示。
上圖紅點代表了圖片的坐標原點,藍點則代表屏幕渲染坐標的原點。只有做了旋轉(zhuǎn)處理,渲染到屏幕上的預覽圖像才是正確的(和原始畫面一樣),而這個旋轉(zhuǎn)的角度,就是orientation的值。
注意,正向始終在物理屏幕的右側(想象音量鍵那邊有一個正向箭頭),orientation就等于從攝像頭的角度(想象成人眼)看,從物理設備的正上方向(想象聽筒位置有個箭頭),需要順時針旋轉(zhuǎn)多少度才能到正向的箭頭。所以,根據(jù)這個想象一下前后攝像頭的區(qū)別,這個值后置攝像頭是90,前置攝像頭是270。
iPhone的攝像頭正向就是物理設備的正上方,對應的正向角度是0,所以輸出的圖像是正向的。
其實不預覽應用程序也能正確獲取到攝像頭的輸入,但是一般應用打開攝像頭后都會在屏幕上顯示當前拍攝到的畫面,這是用戶的基本的使用體驗。正確的預覽圖像就是讓攝像頭輸出的圖像能夠正確的在屏幕上顯示給用戶。
如上節(jié)所述,攝像頭采集到的圖像按照orientation旋轉(zhuǎn)和渲染坐標系對齊即可,這樣就能正確顯示圖像了。不過這是在屏幕方向鎖定的情況下,就是渲染坐標系始終在物理屏幕的左上方。
如果我們打開了設備陀螺儀(鎖屏),屏幕可以在四個方向上切換,對應渲染的坐標原點(藍點)會在物理屏幕的四個角上切換。
切換方向的角度可以通過activity.getWindowManager().getDefaultDisplay().getRotation();
獲取,和前后攝像頭無關:
這個角度可以理解為,以物理設備左上角為原點的渲染坐標系(聽筒左邊的角點),需要順時針旋轉(zhuǎn)多少度,才能變成當前的渲染坐標系。打開陀螺儀后,無論手機怎么旋轉(zhuǎn),當前的渲染坐標系永遠以絕對左上角為原點(視覺左上方角點)。這個角度恰好和物理旋轉(zhuǎn)的角度相反。
我們只要根據(jù)當前的切換角度+攝像頭正向角度正確地設置顯示角度就行了,官方文檔也有現(xiàn)成的適配代碼,詳見setDisplayOrientation。
注意,setDisplayOrientation只會對預覽顯示的圖像有影響,并不會影響onPreviewFrame回調(diào)的數(shù)據(jù)。
?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); ?}
如果還不理解這段代碼的意思,看下這張圖就明白了:
藍點是渲染的坐標原點,紅點是輸出圖片的原點。每一次旋轉(zhuǎn)圖片的原點就會變換到絕對位置的左上角,setDisplayOrientation要設置的值就是圖像要順時針旋轉(zhuǎn)的角度,使圖片能在渲染坐標系中正確顯示。從圖中也能看出來,它就是第二列的箭頭需要順時針旋轉(zhuǎn)到第一列箭頭的角度。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。