出門戴口罩,幫頭像 P 上 N95 吧 | 雲開發實戰

  • 2020 年 3 月 31 日
  • 筆記

珍愛生命,從我做起,快點戴上口罩,給大家介紹我開源的 Taro 小程式「快快戴口罩」它可以智慧識別人臉,給集體照戴上口罩。(* ̄︶ ̄)

採用 Taro 跨端框架,採用騰訊雲源開發模式,採用基於騰訊雲的五官分析的人臉識別,實現了自動為頭像戴上口罩的功能。

源碼地址:https://github.com/shenghanqin/quickly-mask[1]

我是 盛瀚欽,滬江 CCtalk 前端開發工程師,Taro 框架的 issue 維護志願者,主要側重於前端 UI 編寫和團隊文檔建設。

主要功能

  • 智慧識別人臉,進行五官定位
  • 支援多人識別
  • 支援添加加油圖片

掃碼預覽

微信搜一搜:快快戴口罩

小程式截圖

Taro 雲開發模式

Taro 是一套遵循 React 語法規範的 多端開發 解決方案。使用 Taro,我們可以只書寫一套程式碼,再通過 Taro 的編譯工具,將源程式碼分別編譯出可以在不同端(微信/百度/支付寶/字節跳動/QQ/京東小程式、快應用、H5、React-Native 等)運行的程式碼。

本來呢,我的方案是小程式配合放在騰訊雲個人伺服器搭建的 nodejs + express實現的 API 服務。只不過呢,我個人配置的 API 請求不夠理想,因為從小程式到騰訊雲個人伺服器再到騰訊雲服務,中間路徑比較長。

此時發現,Taro 已經集成了騰訊云云開發模式,從小程式 + 個人伺服器切換到騰訊雲開發模式,也就花了一個多小時的時間(歷經了熟悉雲開發、配置雲開發環境等小細節)。

// taro/src/pages/wear-a-mask  Taro.cloud.callFunction({    name: 'analyze-face',    data: { fileID: '12345' }  }).then(res => console.log(res))    // cloud/functions/analyze-face 騰訊雲人臉識別效果  return new Promise((resolve, reject) => {    // 通過client對象調用想要訪問的介面,需要傳入請求對象以及響應回調函數    client.AnalyzeFace(faceReq, function (error, response) {      // 請求異常返回,列印異常資訊      if (error) {        const { code = '' } = error          resolve({          data: {},          time: new Date(),          status: -10086,          message: status.FACE_CODE[code] || '圖片解析失敗'        })        return      }      console.log('AnalyzeFace response :', response)        // 請求正常返回,列印response對象      resolve({        data: response,        time: new Date(),        status: 0,        message: ''      })    })  });

騰訊雲五官識別

其實,啟發我做這個小程式的是這兩個文章,《「聖誕特輯」純前端實現人臉識別自動佩戴聖誕帽[2]》和《我要戴口罩 – 為微信、微博等社交網路頭像戴口罩[3]》。

因為新型冠狀病毒疫情蔓延,而戴口罩就是一個必備的預防措施。那怎樣才能創新呢,我在使用「我要戴口罩」小程式過程中發現,口罩的位置是手動移動的,我就想如何自動戴過去呢,正好先前看到的「自動識別戴聖誕帽」,那我來一個戴口罩就好了。

在「自動佩戴聖誕帽」中,使用的方案是純前端的 face-api,想放到小程式中就會有如下幾個小問題:

  • face-api 的識別模型有 5M 大小還多,即使純前端載入,也顯得比較大。而小程式的 canvas 與 web 網頁中的還是有差異的,沒法直接用 face-api。
  • face-api 放在 nodejs 上載入,還需要配合tensorflowcanvas模擬。實際實現後發現,圖片識別過程還是比較慢的(圖片上傳後、獲取圖片內容、識別五官位置、返回五官數據),容易讓介面請求發生超時的情況。

在使用騰訊雲的過程中,我就發現,騰訊雲的人工智慧大類目下居然有人臉識別功能,細緻推究發現裡面有「五官分析[4]」,其返回的數據跟face-api返回的數據格式還是非常像的,「人臉識別」的每月免費額度 10000 次,當時就讓我開心了一大把。

當然,使用過程中非常大的坑就是,我的實現過程是需要上傳 1M 以上大小的圖片,而「五官分析」簽名方法需要TC3-HMAC-SHA256,官方提供 npm 版本tencentcloud-sdk-nodejs是不支援這個簽名方法的,需要從官方 GitHub[5]庫的signature3分支上下載對應的程式碼。

裁剪圖片

在「我要戴口罩」小程式中的另一個痛點就是如果上傳一個長方形圖片,會被強行變成正方形。我就想如何裁剪出正方形圖片呢,此時在 npmjs 倉庫中發現了taro-cropper這個強大的圖片裁剪插件(Taro 物料市場亦有提供)。

口罩定位

從「五官分析」中得出人臉的五官數據後,如何基於此給人臉戴上口罩呢?「自動識別戴聖誕帽」是基於「三庭五眼」來計算出聖誕帽的位置,而口罩呢,其實更簡單,獲取嘴部的中點位置,再旋轉縮放一下就行了。

  • 獲取嘴部資訊,請先閱讀《「聖誕特輯」純前端實現人臉識別自動佩戴聖誕帽[6]》,再看taro/src/utils/face-utils.js中的getMouthInfo方法。
  • 口罩定位呢,可以看下方程式碼~
let shapeList = info.map(item => {    let { faceWidth, angle, mouthMidPoint, ImageWidth } = item    let dpr = ImageWidth / CANVAS_SIZE * (375 / windowWidth)    const maskCenterX = mouthMidPoint.X / dpr    const maskCenterY = mouthMidPoint.Y / dpr    const scale = faceWidth / MASK_SIZE / dpr    const rotate = angle / Math.PI * 180      return {      maskSize: DEFAULT_MASK_SIZE,      maskCenterX,      maskCenterY,      scale,      rotate,    }  })

口罩定位

  • 當 touchstart 時,保存此時的 touch 起始點,並以此時的底圖和口罩位置作為旋轉角度和縮放比例值計算的參考點
  • 當 touchmove 時,根據起始點 和 臨時的終止點 計算在 x/y 方向上的移動距離,計算參考點分別 加上這個距離,得到移動後的位置,通過移動前後的位置 計算移動前後位置的變動 計算旋轉角和縮放比例
  • 當 touchend 時,重置底圖和口罩的位置及旋轉角和縮放比例

Canvas 畫圖

  • 首先繪製底圖(根據螢幕大小、圖片大小計算左上角和右下角坐標)
  • 繪製口罩(計算最終口罩的大小及中心位置 旋轉角度,移動畫布原點到口罩的中心位置,旋轉畫布 並繪製口罩)

在微信小程式中,canvas 畫圖需要將網路圖片變為本地圖片的,如果繪製時再下載,存在下載時間挺長且容易下載失敗的風險,還是使用本地圖片更加靠譜一些。在 Tarojs 項目,canvas 畫圖的drawImage(src, 0, 0, 300, 300)方法,如果 src 為require('../../images/xxx.png')的話,一定要記住修改以下配置,否則小程式就會報 http 500錯誤。

{    mini: {      imageUrlLoaderOption: {        limit: 0      }  }

參考項目

  • 小程式:我要戴口罩,idealclover/Wear-A-Mask[7]
  • 自動聖誕帽:christmas-hat[8]
  • 自動識別人臉示例:bnk48-face-recognition[9]
  • 小程式:聖誕帽:jasscia/ChristmasHat[10]
  • face-api.js justadudewhohacks/face-api.js[11]
  • 騰訊雲人臉識別: https://cloud.tencent.com/product/facerecognition[12]
  • Tarojs 版本圖片裁剪:SunnyQjm/taro-cropper[13]
  • 病毒演化模擬器:qqqdu/zhonghuajia[14]

參考資料

[1]https://github.com/shenghanqin/goddess-hat: https://github.com/shenghanqin/quickly-mask

[2]「聖誕特輯」純前端實現人臉識別自動佩戴聖誕帽: https://juejin.im/post/5e02b73fe51d455807699b1f

[3]我要戴口罩 – 為微信、微博等社交網路頭像戴口罩: https://www.appinn.com/woyaodaikouzhao-wechat-miniapp/

[4]五官分析: https://cloud.tencent.com/document/api/867/32779

[5]官方 GitHub: https://github.com/TencentCloud/tencentcloud-sdk-nodejs/tree/signature3

[6]「聖誕特輯」純前端實現人臉識別自動佩戴聖誕帽: https://juejin.im/post/5e02b73fe51d455807699b1f

[7]idealclover/Wear-A-Mask: https://github.com/idealclover/Wear-A-Mask

[8]christmas-hat: https://github.com/hk029/christmas-hat

[9]bnk48-face-recognition: http://supachaic.github.io/bnk48-face-recognition

[10]jasscia/ChristmasHat: https://github.com/jasscia/ChristmasHat

[11]justadudewhohacks/face-api.js: https://github.com/justadudewhohacks/face-api.js

[12]https://cloud.tencent.com/product/facerecognition: https://cloud.tencent.com/product/facerecognition

[13]SunnyQjm/taro-cropper: https://github.com/SunnyQjm/taro-cropper

[14]qqqdu/zhonghuajia: https://github.com/qqqdu/zhonghuajia

雲開發(CloudBase)是一款雲端一體化的產品方案 ,採用 serverless 架構,免環境搭建等運維事務 ,支援一雲多端,助力快速構建小程式、Web應用、移動應用。

技術文檔:https://www.cloudbase.net/

微信搜索:騰訊云云開發,獲取項目最新進展