手把手教學從0到1搭建人臉融合小程式(下)
- 2019 年 12 月 26 日
- 筆記
前提提要
在上篇文章中,我們已經設計好了這次要開發的融合小程式的系統架構,給大家複習下:

下面讓我們跟著這個思路,搭建屬於自己的融合小程式~
小程式前端開發
由於本文主要介紹小程式端調用人臉融合雲介面,所以前端這裡簡單設計,整個前端頁面分為三個區域:

模版區
展示模版圖列表,標柱各模版圖人臉,每次融合只能選擇一張融合圖,每次選擇只能選中一張人臉
輸入區
展示用戶上傳的輸入圖列表,標柱各輸入圖人臉,每次選擇只能選中一張人臉
融合結果區
展示融合結果圖
使用說明

- 上傳輸入圖,展示輸入人臉->選擇模版人臉->選擇輸入人臉,組合成MergeInfos元素->點擊融合->獲取融合結果並展示
- 可以上傳多張輸入圖
- 可以重複【選擇模版人臉->選擇輸入人臉】操作,最多三組,實現多臉融合
調用人臉介面
main雲函數
main雲函數實際是一個統一請求雲sdk的介面,裡面封裝好大部分請求雲API的操作:
- 公共參數處理:組裝好包括service、version、action,以及用於身份校驗的sercetId、secretKey等參數
- 處理圖片數據:由於小程式從本地相冊或相機獲取的圖片數據,雲服務無法直接處理,因此小程式需要將這些圖片先上傳,再請求雲函數 在這個demo採取的方式是先將圖片上傳的雲開發的資料庫,獲取到fileId,在雲函數請求雲API之前,通過雲開發提供的cloud.getTempFileURL方法,獲取雲文件真實的鏈接。
async function getFileUrl(url) { // 如果是 cloud:// 則,換取雲文件真實鏈接 if (/^cloud:///.test(url)) { const { fileList } = await cloud.getTempFileURL({ fileList: [url], }); if (!fileList || !fileList[0]) throw new Error('無法獲取文件'); const file = fileList[0]; return file.tempFileURL; } else { return url; } };
- 封裝請求雲API的統一介面:
// 騰訊雲sdk const tencentcloud = require('tencentcloud-sdk-nodejs'); const { Credential } = tencentcloud.common; const { ClientProfile } = tencentcloud.common; const { HttpProfile } = tencentcloud.common; // 請求騰訊雲API介面 function requestAPI({ endpoint, // 請求域名 (可選) service, // 服務前綴 action, // 介面名稱 version, // 版本號 region, // 地域 (可選) secretId, // 密鑰ID secretKey, // 密鑰Key sessionToken, // 密鑰Token (可選) data, // 請求數據 }) { const { Client } = tencentcloud[service][version]; const { Models } = tencentcloud[service][version]; const cred = new Credential(secretId, secretKey, sessionToken); const httpProfile = new HttpProfile(); httpProfile.endpoint = endpoint || `${service}.tencentcloudapi.com`; const clientProfile = new ClientProfile(); clientProfile.httpProfile = httpProfile; const client = new Client(cred, region || 'ap-shanghai', clientProfile); const req = new Models[`${action}Request`](); const reqParams = JSON.stringify({ ...data }); req.from_json_string(reqParams); return new Promise((resolve, reject) => { client[action](req, (errMsg, response) => { if (errMsg) { reject(errMsg); return; } resolve(JSON.parse(response.to_json_string() || {})); }); }); }
main雲函數實現如下:
// 雲函數入口文件 const cloud = require('wx-server-sdk') const { handleImage, requestAPI } = require('./utils'); const actionConfig = { DetectFace: { service: 'iai', action: 'DetectFace', version: 'v20180301', secretId: '你的secretId', secretKey: '你的secretKey' }, FuseFace: { service: 'facefusion', action: 'FuseFace', version: 'v20181201', secretId: '你的secretId', secretKey: '你的secretKey' } }; // 雲函數入口函數 exports.main = async (event, context) => { const wxContext = cloud.getWXContext(); // 整理默認參數,action指定請求那個雲API介面 let config = actionConfig[event.action]; if (!config) { return { Response: { Error: { Code: -1, Message: 'Action錯誤' } } }; } // 整理本次請求入參,處理入參的圖片數據,這裡不展開邏輯 config.data = handleImage(event.data || {}) let requestRes; try { // 發起請求 requestRes = { Response: await requestAPI(config), }; } catch (err) { console.error(err); requestRes = { Response: { Error: { Code: err.code || -1, Message: err.message || '未知錯誤', }, } }; } return requestRes; }
小程式調用雲函數
參考官網文檔,實現小程式調用雲函數即可:
- 人臉檢測:獲取本地圖片後執行人臉檢測,獲取人臉框資訊:
const self = this; // 選擇本地圖片 chooseImage(async function(res) { // 上傳圖片 const fileId = await uploadImage(res); wx.showLoading({ title: '載入中', mask: true }); // 指定請求人臉檢測,填好請求入參 wx.cloud.callFunction({ name: 'main', data: { action: 'DetectFace', data: { MaxFaceNum: 3, MinFaceSize: 30, Url: fileId, NeedFaceAttributes: 0, NeedQualityDetection: 0 } }, success(result) { wx.hideLoading(); // TODO:success event }, fail(error) { wx.hideLoading(); console.log(error); } }); }, function(err) { console.log(err); })
- 人臉融合:
let { mergeInfos, activeModelId, projectId } = this.data; wx.showLoading({ title: '融合中', mask: true }); const self = this; // 發起融合 wx.cloud.callFunction({ name: 'main', data: { action: 'FuseFace', data: { RspImgType: 'url', ProjectId: projectId, ModelId: activeModelId, MergeInfos: mergeInfos } }, success(result) { wx.hideLoading(); // TODO:success event }, fail(err) { console.log(err); wx.hideLoading(); } });
有個坑
由於小程式使用的雲SDK版本問題,當我們編寫完main的雲函數,上傳並部署時,若選擇【雲端安裝依賴】,那麼此時雲端安裝的雲SDK並不包含FuseFace這個服務!! 因此這裡推薦大家本地安裝好依賴(拉取最新版本latest)後,一併上傳部署。
"dependencies": { "wx-server-sdk": "latest", "tencentcloud-sdk-nodejs": "latest" }
至此,整個人臉融合小程式就開發完畢了,有興趣的同學可以體驗一下:

感謝閱讀兩篇文章的小夥伴,對使用人臉融合服務有問題的同學可以評論區留言,下來一起討論下。