AR紅包Android端實現原理

前不久支付寶推出了AR紅包的功能,風靡一時,最近剛好完成了這樣的需求,特此整理分享,以求相互學習、共同進步。有鑒于公司接下來可能的商用,就不在這里貼源碼了,僅簡單說一下實現思路和原理。

話不多講,先上流程圖:

AR紅包.png

藏紅包

一、初始化相機

相機類android.hardware.Camera,但是很遺憾它過時了,Google在Android5.0后推出了更強大的android.hardware.camera2包,但是為了兼容低版本這里依然使用android.hardware.Camera類(有興趣的同學可以通過Android Camera2 拍照入門學習這篇了解camera2的實現方式)。

  1. Camera.open()開啟相機;
  2. Camera.getParameters()獲取參數類并設置,缺少這一步相機的預覽畫面會變成橫向的、模糊的。
    需要設置的內容:
    parameters.setPictureSize圖片分辨率,
    parameters.setPreviewSize預覽圖像分辨率,這兩項需要根據設備支持的列表具體計算這里不再贅述parameters.setPreviewFormat預覽圖像轉碼格式,
    parameters.setJpegQuality照片質量,這里并不需要拍照可以忽略,
    parameters.setFocusMode對焦模式,連續對焦需要加camera.cancelAutoFocus()
    camera.setDisplayOrientation預覽畫面方向,這里旋轉90。

記得權限(Android6.0后需要動態申請。):

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />

二、綁定surfaceView

  1. 找到surfaceView后getHolder()獲得surfaceHolder引用;
  2. holder.setType設置類型;
  3. holder.addCallback添加回調;
  4. Camera.setPreviewDisplay(holder)將surfaceHolder傳入Camera;
  5. Camera.startPreview()開啟預覽圖像。

三、獲取一幀預覽圖像

Camera.setOneShotPreviewCallback(PreviewCallback cb)方法可以獲取一幀預覽圖像,數據會返回到PreviewCallback 回調中的 onPreviewFrame(byte[] data,Camera camera)方法中,data即為幀數據。

四、預處理圖像

首先明確一點,處理圖像和接下來的其他耗時計算都要放到子線程中,不要問我為什么,編譯器會告訴你答案。onPreviewFrame方法中的data并不能直接直接轉為bitmap,需要先進行轉碼:

        Camera.Size size = camera.getParameters().getPreviewSize();
        YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
        Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

五、奇數幀?偶數幀?

為什么要分奇數偶數呢?當做好相機的準備工作后,要藏紅包,實際上需要解決的就是排除不需要的圖像,首先要做到的就是舍棄用戶移動時獲取的圖像,最先的想法是利用加速度傳感器,但是隨后發現手機勻速移動的時候是沒有加速度的,而這時獲取的圖像仍需舍棄。后來找到的解決方案是:不停獲取幀圖像,比較相鄰兩幀的相似度,當相似度達到某個閾值時視為相似,連續數次比較皆為相似可知用戶所對位置即用戶想要藏紅包的地方,將此時獲取的幀圖保存即可。

  • 設置一個計數器記錄獲取幀圖的次數,計數器%2即可區分奇偶;
  • 奇數幀存到圖1,偶數幀存圖2,比較圖1圖2;
  • 不足兩圖、比較不相似就獲取新的一幀,即可實現不停的比較相鄰兩幀圖像。

六、相似?

比較相似的方法網上有挺多,有直接拿像素比較的,有處理成灰度圖像比較的,有轉成哈希值比較的,比較方法不同得到的數值也不同,所要設定的閾值也隨之改變,具體看需求能達到目的就好。細心的同學會發現支付寶在藏紅包的時候并不是所有地方都可以藏,有些沒有意義、過度單調的地方是沒辦法藏的,這里實現的方式是計算圖片像素“豐富度”(缺少圖像學知識暫且這么叫吧)。得到圖片所有像素點的值,去除重復,所得到的所有不同像素值的個數越小說明圖片顏色越“單調”,然后根據這個個數值設置閾值進行判斷。

七、確定紅包位置

得到滿足要求的幀圖后,停止獲取幀圖,停止相機預覽Camera.stopPreview(),將圖片直接上傳服務器或者轉成哈希值傳給服務器,也可以同時傳些位置坐標等參數,這個看具體需求,這些數據即為所藏紅包的“指紋”。

找紅包

找紅包相對簡單,相同的邏輯不在贅述,只需要:

  1. 獲取已藏紅包的位置圖片,
  2. 與獲取的預覽幀圖比較,
  3. 不相似繼續取幀圖,相似停止取幀,即找到紅包。

可以根據需求增加位置坐標范圍判斷和用戶身份判斷。

一點思考

首先我們對比下掃描二維碼和掃描AR紅包的實現原理:

二維碼與找紅包對比.png

不難發現,整個掃描流程十分相似。其實在我看來,AR紅包可以理解為是一個特殊的“二維碼”,只不過這個“二維碼”上不再是特殊的幾何圖形,而是一張圖片。支付寶“掃一掃”中左邊是“二維碼”右邊是“AR”,有力地支持了我的邏輯。那么按照這個邏輯再來看整個AR紅包,可以發現“藏紅包”其實就是一個生成“二維碼”的過程,“找紅包”自然就是掃描“二維碼”了。

那么AR紅包又與二維碼有什么區別?

我們知道二維碼是按照一定規律生成的特殊幾何圖形,可以進行編碼解析,即二維碼中是內含信息的;而AR紅包實際上只是一張圖片,不包含信息。這也是為什么支付寶要通過紅包地圖和用戶的方式將AR紅包區分開的原因,否則如果兩個用戶在同一個位置藏了紅包,掃描時將無法區分它們。既然如此那為什么還要有AR紅包的存在呢?

AR紅包相對于二維碼的優缺點

優點:

  • AR紅包藏匿于現實生活中。不同于二維碼:“我是一個二維碼,你們快來掃我呀O(∩_∩)O~~”,只要你不公開你的紅包位置圖,沒人知道這有紅包,當然你也可以讓部分人看到。媽媽再也不用擔心兒子的私房錢被老婆發現了!
  • AR紅包來源于現實生活。所以就省去了張貼“二維碼”和更換“二維碼”的麻煩,同時也減少了二維碼給環境帶來的污染。試想一下:今天《金剛》首映掃“帝國大廈”可獲得電影票一張,掃“央視大褲衩”看今日新聞是不是很cooool~
  • AR紅包可以一地兒多用。同樣一個“央視大褲衩”,央視掃是新聞聯播,網易掃是網易頭條,UC掃是UC震驚。
  • 良好的用戶體驗。舉個栗子:相比于掃公司logo打卡和掃公司logo上的二維碼打卡,我選擇前者。

缺點:

  • 本身不包含信息,需要其他參數輔助。沒有位置坐標和用戶信息,AR紅包幾乎無法運行。
  • 人不能倆次踏入同一條河流。你藏紅包的地方可能隨時間變化再也無法復現,比如碎掉的存錢罐、昨天的夕陽和年少的你。
  • 算法不夠完善。AR紅包剛出現不久,尚沒有統一的算法,每種比較的算法根據需求不同結果相差很大,識別效果和效率不夠完美,無法像二維碼一樣瞬間識別,還有待進一步完善。

實現AR紅包的過程中,讓我深深的感到對圖像處理知識的缺乏,這篇文章權當總結,一些淺見難免有疏忽紕漏,還往大家不吝賜教,共同進步。

參考:

Android二維碼掃描開發(一):實現思路與原理
Android實現圖片相似度
Android 手把手帶你玩轉自定義相機
Android Camera2 拍照入門學習

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容