亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android相機開發的方法是什么

發布時間:2022-01-12 14:46:07 來源:億速云 閱讀:179 作者:iii 欄目:云計算

本篇內容主要講解“Android相機開發的方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Android相機開發的方法是什么”吧!

一.Android中開發相機應用的兩種方式

Android系統提供了兩種使用手機相機資源實現拍攝功能的方法,一種是直接通過Intent調用系統相機組件,這種方法快速方便,適用于直接獲得照片的場景,如上傳相冊,微博、朋友圈發照片等。另一種是使用相機API來定制自定義相機,這種方法適用于需要定制相機界面或者開發特殊相機功能的場景,如需要對照片做裁剪、濾鏡處理,添加貼紙,表情,地點標簽等。這篇文章主要是從如何使用相機API來定制自定義相機這個方向展開的。

二.相機API中關鍵類解析

通過相機API實現拍攝功能涉及以下幾個關鍵類和接口:

Camera:最主要的類,用于管理和操作camera資源。它提供了完整的相機底層接口,支持相機資源切換,設置預覽/拍攝尺寸,設定光圈、曝光、聚焦等相關參數,獲取預覽/拍攝幀數據等功能,主要方法有以下這些:

  • open():獲取camera實例。

  • setPreviewDisplay(SurfaceHolder):綁定繪制預覽圖像的surface。surface是指向屏幕窗口原始圖像緩沖區(raw buffer)的一個句柄,通過它可以獲得這塊屏幕上對應的canvas,進而完成在屏幕上繪制View的工作。通過surfaceHolder可以將Camera和surface連接起來,當camera和surface連接后,camera獲得的預覽幀數據就可以通過surface顯示在屏幕上了。

  • setPrameters設置相機參數,包括前后攝像頭,閃光燈模式、聚焦模式、預覽和拍照尺寸等。

  • startPreview():開始預覽,將camera底層硬件傳來的預覽幀數據顯示在綁定的surface上。

  • stopPreview():停止預覽,關閉camra底層的幀數據傳遞以及surface上的繪制。

  • release():釋放Camera實例

  • takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg):這個是實現相機拍照的主要方法,包含了三個回調參數。shutter是快門按下時的回調,raw是獲取拍照原始數據的回調,jpeg是獲取經過壓縮成jpg格式的圖像數據的回調。

SurfaceView:用于繪制相機預覽圖像的類,提供給用戶實時的預覽圖像。普通的view以及派生類都是共享同一個surface的,所有的繪制都必須在UI線程中進行。而surfaceview是一種比較特殊的view,它并不與其他普通view共享surface,而是在內部持有了一個獨立的surface,surfaceview負責管理這個surface的格式、尺寸以及顯示位置。由于UI線程還要同時處理其他交互邏輯,因此對view的更新速度和幀率無法保證,而surfaceview由于持有一個獨立的surface,因而可以在獨立的線程中進行繪制,因此可以提供更高的幀率。自定義相機的預覽圖像由于對更新速度和幀率要求比較高,所以比較適合用surfaceview來顯示。

SurfaceHolder:surfaceholder是控制surface的一個抽象接口,它能夠控制surface的尺寸和格式,修改surface的像素,監視surface的變化等等,surfaceholder的典型應用就是用于surfaceview中。surfaceview通過getHolder()方法獲得surfaceholder 實例,通過后者管理監聽surface 的狀態。

SurfaceHolder.Callback接口:負責監聽surface狀態變化的接口,有三個方法:

  • surfaceCreated(SurfaceHolder holder):在surface創建后立即被調用。在開發自定義相機時,可以通過重載這個函數調用camera.open()、camera.setPreviewDisplay(),來實現獲取相機資源、連接camera和surface等操作。

  • surfaceChanged(SurfaceHolder holder, int format, int width, int height):在surface發生format或size變化時調用。在開發自定義相機時,可以通過重載這個函數調用camera.startPreview來開啟相機預覽,使得camera預覽幀數據可以傳遞給surface,從而實時顯示相機預覽圖像。

  • surfaceDestroyed(SurfaceHolder holder):在surface銷毀之前被調用。在開發自定義相機時,可以通過重載這個函數調用camera.stopPreview(),camera.release()來實現停止相機預覽及釋放相機資源等操作。

    三.自定義相機的開發過程

    定制一個自定義相機應用,通常需要完成以下步驟,其流程圖如圖1所示:

  • 檢測并訪問相機資源 檢查手機是否存在相機資源,如果存在,請求訪問相機資源。

  • 創建預覽類 創建繼承自SurfaceView并實現SurfaceHolder接口的拍攝預覽類。此類能夠顯示相機的實時預覽圖像。

  • 建立預覽布局 有了拍攝預覽類,即可創建一個布局文件,將預覽畫面與設計好的用戶界面控件融合在一起。

  • 設置拍照監聽器 給用戶界面控件綁定監聽器,使其能響應用戶操作(如按下按鈕), 開始拍照過程。

  • 拍照并保存文件 將拍攝獲得的圖像轉換成位圖文件,最終輸出保存成各種常用格式的圖片。

  • 釋放相機資源 相機是一個共享資源,必須對其生命周期進行細心的管理。當相機使用完畢后,應用程序必須正確地將其釋放,以免其它程序訪問使用時,發生沖突。

    圖1 定制自定義相機的過程
    對應到代碼編寫上可以分成三個步驟:
    第一步:在AndroidManifest.xml中添加Camera相關功能使用的權限,具體聲明有以下這些:

    第二步:編寫相機操作功能類CameraOperationHelper。采用單例模式來統一管理相機資源,封裝相機API的直接調用,并提供用于跟自定義相機Activity做UI交互的回調接口,其功能函數如下,主要有創建\釋放相機,連接\開始\關閉預覽界面,拍照,自動對焦,切換前后攝像頭,切換閃光燈模式等,具體實現可以參考官方API文檔。


    第三步:編寫自定義相機Activity,主要是定制相機界面,實現UI交互邏輯,如按鈕點擊事件處理,icon資源切換,鏡頭尺寸切換動畫等。這里需要聲明一個SurfaceView對象來實時顯示相機預覽畫面。通過SurfaceHolder及其Callback接口來一同管理屏幕surface和相機資源的連接,相機預覽圖像的顯示/關閉。

    四. 開發過程遇到的一些坑

    下面再講講我在開發自定義相機時踩過的一些坑:

    1. Activity設為豎屏時,SurfaceView預覽圖像顛倒90度。

說明這個問題之前,先介紹下Android手機上幾個方向的概念:
屏幕方向:在Android系統中,屏幕的左上角是坐標系統的原點(0,0)坐標。原點向右延伸是X軸正方向,原點向下延伸是Y軸正方向。
相機傳感器方向:手機相機的圖像數據都是來自于攝像頭硬件的圖像傳感器,這個傳感器在被固定到手機上后有一個默認的取景方向,如下圖2所示,坐標原點位于手機橫放時的左上角,即與橫屏應用的屏幕X方向一致。換句話說,與豎屏應用的屏幕X方向呈90度角。

圖2 相機傳感器方向示意圖
相機的預覽方向:由于手機屏幕可以360度旋轉,為了保證用戶無論怎么旋轉手機都能看到“正確”的預覽畫面(這個“正確”是指顯示在UI預覽界面的畫面與人眼看到的眼前的畫面是一致的),Android系統底層根據當前手機屏幕的方向對圖像傳感器采集到的數據進行了旋轉處理,然后才送給顯示系統,因此可以保證預覽畫面始終“正確”。在相機API中可以通過setDisplayOrientation()設置相機預覽方向。在默認情況下,這個值為0,與圖像傳感器一致。因此對于橫屏應用來說,由于屏幕方向和預覽方向一致,預覽圖像不會顛倒90度。但是對于豎屏應用,屏幕方向和預覽方向垂直,所以會出現顛倒90度現象。為了得到正確的預覽畫面,必須通過API將相機的預覽方向旋轉90,保持與屏幕方向一致,如圖3所示。

圖3 相機預覽方向示意圖
(紅色箭頭為預覽方向,藍色方向為屏幕方向)
相機的拍照方向:當點擊拍照按鈕,拍攝的照片是由圖像傳感器采集到的數據直接存儲到SDCard上產生的,因此,相機的拍照方向與傳感器方向是一致的。

2. SurfaceView預覽圖像、拍攝照片拉伸變形

說明這個問題之前,同樣先說一下幾個跟相機有關的尺寸。
SurfaceView尺寸:即自定義相機應用中用于顯示相機預覽圖像的View的尺寸,當它鋪滿全屏時就是屏幕的大小。這里surfaceview顯示的預覽圖像暫且稱作手機預覽圖像。

Previewsize:相機硬件提供的預覽幀數據尺寸。預覽幀數據傳遞給SurfaceView,實現預覽圖像的顯示。這里預覽幀數據對應的預覽圖像暫且稱作相機預覽圖像。
Picturesize:相機硬件提供的拍攝幀數據尺寸。拍攝幀數據可以生成位圖文件,最終保存成.jpg或者.png等格式的圖片。這里拍攝幀數據對應的圖像稱作相機拍攝圖像。圖4說明了以上幾種圖像及照片之間的關系。手機預覽圖像是直接提供給用戶看的圖像,它由相機預覽圖像生成,拍攝照片的數據則來自于相機拍攝圖像。

圖4 幾種圖像之間的關系
下面說下我在開發過程中遇到的三種拉伸變形現象:
1、手機預覽畫面中物體被拉伸變形。
2、拍攝照片中物體被拉伸變形。
3、點擊拍照瞬間,手機預覽畫面會停頓下,此時的圖像是拉伸變形的,然后預覽畫面恢復后圖像又正常了。

現象1的原因是SurfaceView和Previewsize的長寬比率不一致。因為手機預覽視圖的圖像是由相機預覽圖像根據SurfaceView大小縮放得來的,當長寬比不一致時必然會導致圖像變形。后兩個現象的原因則是Previewsize和Picturesize的長寬比率不一致所致,查了相關的資料,發現其具體原因跟某些手機相機硬件的底層實現有關。總之為了避免以上幾種變形現象的發生,在開發時最好將SurfaceView、PreviewSize、PictureSize三個尺寸保證長寬比例一致。具體實現可以先通過camera.getSupportedPreviewSizes()和camera.getSupportedPictureSizes()獲得相機硬件支持的所有預覽和拍攝尺寸,然后在里面篩選出和SurfaceView的長寬比一致并且大小合適的尺寸,通過camera.setPrameters來更新設置。注意:市場上手機相機硬件支持的尺寸一般都是主流的4:3或者16:9,所以SurfaceView尺寸不能太奇葩,最好也設置成這樣的長寬比。

3. 各種crash



前兩個Crash的原因是:相機硬件在聚焦和拍照前必須要保證已經連接到surface,并且開啟相機預覽,surface有收到預覽數據。如果在還沒有執行camera. setPreviewDisplay或者未調用camera. startPreview之前,就調用camera.autofocus或camera.takepicture,就會出現這個運行時異常。對應到自定義相機的代碼中,要注意在拍照按鈕事件響應中執行camera.autofocus或camera.takepicture前,一定要檢驗camera有沒有設置預覽Surfaceview并開啟了相機預覽。這里有個方法可以判斷預覽狀態:Camera.setPreviewCallback是預覽幀數據的回調函數,它會在SurfaceView收到相機的預覽幀數據時被調用,因此在里面可以設置是否允許對焦和拍照的標志位。

還有一點要注意,camera.takePicture()在執行過程中會執行camera.stopPreview來獲取拍攝幀數據,表現為預覽畫面卡住,而如果此時用戶點擊了按鈕的話,也就是調用camera.takepicture,也會出現上面的crash,因此在開發時,可能還需要屏蔽拍照按鈕的連續點擊。
第三個crash則涉及圖像的裁剪,由于要支持1:1或者4:3尺寸鏡頭,所以會需要對預覽視圖進行裁剪,由于是豎屏應用,所以裁剪區域的坐標系跟相機傳感器方向是成90度角的,表現在裁剪里就是,屏幕上的x方向,對應在拍攝圖像上是高度方向,而屏幕上的y方向,對應到拍攝圖像上則是寬度方向。因此在計算時要一定注意坐標系的轉換以及越界保護。

4. 前置攝像頭的鏡像效果

Android相機硬件有個特殊設定,就是對于前置攝像頭,在展示預覽視圖時采用類似鏡面的效果,顯示的是攝像頭成像的鏡像。而拍攝出的照片則仍采用攝像頭成像。看到這里,大家可能會有些懷疑,不妨現在就試試自己Android手機上的前置攝像頭,對比下預覽圖像和拍攝出照片的區別。這是由于底層相機在傳遞前置攝像頭預覽數據時做了水平翻轉變換,即將x方向鏡像翻轉180度。這個變化對之前豎屏預覽的方向也會造成影響,本來對于后置攝像頭旋轉90度即可使預覽視圖正確,而對前置攝像頭,如果也旋轉90度的話,看到的預覽圖像則是上下顛倒的(因為x方向翻轉了180度),因此必須再旋轉180度,才能顯示正確,如圖5所示,大家可以結合之前相機預覽方向的示意圖一起理解。


圖5 前置攝像頭的預覽方向示意圖
此外,由于拍攝圖像并沒有做水平翻轉,所以對于前置攝像頭拍出來的照片,用戶會發現跟預覽時所見的是左右翻轉的。這個在一定程度上會影響用戶體驗。為了解決這個問題,可以對前置攝像頭拍攝的圖像在生成位圖文件時增加一個水平翻轉矩陣變換。

5. 鎖屏下相機資源的釋放問題

為了節省手機電量,不浪費相機資源,在開發的自定義相機里,如果預覽圖像已不需要顯示,如按Home鍵盤切換后臺或者鎖屏后,此時就應該關閉預覽并把相機資源釋放掉。參考官方API文檔,當surfaceView變成可見時,會創建surface并觸發surfaceHolder.callback接口中surfaceCreated回調函數。而surfaceview變成不可見時,則會銷毀surface,并觸發surfacedestroyed回調函數。我們可以在對應的回調函數里,處理相機的相關操作,如連接surface、開啟/關閉預覽。 至于相機資源釋放,則可以放在Acticity的onpause里執行。相應的,要重新恢復預覽圖像時,可以把相機資源申請和初始化放在Acticity的onResume里執行,然后通過創建surfaceview,將camera和surface相連并開啟預覽。

但是在開發過程中發現,對于按HOME鍵切后臺場景,程序可以正常運行。對于鎖屏場景,則在重新申請相機資源時會發生crash,說相機資源訪問失敗。那么原因是什么呢?我在代碼里增加了調試log, 檢查了代碼的執行順序,結果如下:
在自定義相機頁面按HOME鍵時的執行流程:

  • 程序運行->按HOME鍵

  • Activity調用的順序是onPause->onStop

  • SurfaceView調用了surfaceDestroyed方法

  • 然后再切回程序

  • Activity調用的順序是onRestart->onStart->onResume

  • SurfaceView調用了surfaceCreated->surfaceChanged方法

  • 而對于鎖屏,其執行流程則是:

  • Activity只調用onPause方法

  • 解鎖后Activity調用onResume方法

  • SurfaceView中surfaceholder.callback的所有方法都沒有執行

問題找到了,由于鎖屏時,callback的回調方法沒有執行,導致相機和預覽的連接還沒有斷開,相機資源就被釋放了,所以導致在重新申請相機資源時,系統報crash。根據上面的文檔,推測是鎖屏下系統并沒有改變surfaceview的可見性,于是我嘗試在onPause和onResume時通過手動設置surfaceview的visibile屬性,結果發現可以正常觸發回調函數了。由于在切后臺或者鎖屏時,用戶本來就應該看不到surfaceview,因此這種手動更改surfaceview的可見性的方法,并不會對用戶的體驗造成影響。

到此,相信大家對“Android相機開發的方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

普宁市| 梁山县| 巴中市| 濮阳市| 丰都县| 大石桥市| 武安市| 崇州市| 穆棱市| 治县。| 宁陕县| 昌吉市| 双鸭山市| 社会| 谢通门县| 芦山县| 景泰县| 且末县| 清远市| 桐乡市| 谢通门县| 平原县| 西和县| 卫辉市| 邛崃市| 宜宾县| 万宁市| 彰武县| 临海市| 湘潭市| 武宣县| 清镇市| 丁青县| 永善县| 河北区| 清徐县| 屯留县| 文化| 南昌市| 舒城县| 崇文区|