[轉] 無伺服器開發人臉識別小程式
原文作者:張誠
原文連結:
發表日期:一月 30日 2019, 10:43:49 上午
更新日期:January 31st 2019, 2:44:27 pm
版權宣告:本文采用知識共享署名-非商業性使用 4.0 國際許可協議進行許可,轉載請註明出處。
無伺服器開發人臉識別小程式
從2006年AWS釋出的第一個雲服務S3開始,儲存,計算等IT基礎設施的能力紛紛被以服務的方式提供給使用者。過去十年,雲服務深刻的改變了社會獲取和使用計算能力的方式,雲服務自身也以極快的速度演進,新的服務形態不斷湧現,無伺服器計算(serverless computing)就是其中之一。國內各大廠商也在近兩年推出了自家的無伺服器計算產品,比如騰訊雲的,阿里雲的函式計算等產品。
前言
前段時間我還在想,如果小程式能使用無伺服器計算產品那該多好,過不奇然,最近微信與騰訊雲聯合開發的原生 serverless 雲服務產品——,其具備簡化運維、高效鑑權等優勢,讓你零門檻快速上線小程式。為此,我決定嘗試下這種新的開發方式,看看是不是真的如官方所說。
那麼,用什麼專案去嘗試呢?看了下自己以前寫的文章,發現這篇文章關注量還挺多,況且騰訊雲API於2019年1月25日全量更新為了最新的3.0版本,API呼叫方式及也有較大變化。我完全可以用最新版的API結合雲開發去體驗下這個過程。
當然,最大的優勢在於省錢!!!小程式 · 雲開發這款產品還在免費階段,同時騰訊雲服務每月為各個介面提供 1 萬次 的免費呼叫,很划算。
這篇文章將分享我開發過程中的一些思路,如何考慮產品應用性,如何最佳化邏輯等問題。同時也會分享整個的開發過程,從怎麼註冊賬戶到怎麼呼叫API,以及程式碼是如何一點一點拼接的。大家也可以將這篇文章看為一篇教程,我會從0~1分享整個專案的開發過程。當然,如果你是一名Developer,請直接使用我撰寫好的程式碼,已經分享到了,歡迎大家參閱!
那麼,我們就開始吧!
準備
在撰寫程式碼之前,我們需要先準備一下小程式的開發環境,所需要的環境有Git
、NodeJS
、npm
、微信開發者工具
。同時,因為要呼叫騰訊雲人臉識別API,我們還需要註冊的賬號,同時還需要註冊騰訊雲的。
安裝Git
git是一個分散式版本控制軟體,開發小程式的時候做好程式碼版本控制非常重要,如果程式碼寫錯,可以使用Git快速恢復。安裝Git較為簡單,我們只需要開啟,點選右側的Download 2.20.1 for Windows
,當然,版本號和系統都可能不同,大家按照自己的系統及最新的版本號下載即可。
下載完成後雙擊開啟安裝包,然後一路點選下一步直至安裝完成。安裝完成後我們按鍵盤上的Win
+R
,然後輸入CMD
開啟命令提示符視窗,然後在命令提示符視窗中輸入git
,如果你看到類似下面的截圖,證明你的Git安裝成功,可以進行下一步了。
安裝NodeJS和npm
NodeJS是一個可以跨平臺在服務端執行JavaScript的執行環境,我們小程式雲開發所使用的服務端環境就是NodeJS,為了最佳化並測試程式碼,建議在本地安裝NodeJS執行環境。npm是Node包管理器,透過npm包管理器,我們可以非常方便的安裝雲開發所需要的環境。
首先,我們開啟,下載NodeJS安裝包。
下載完成後雙擊開啟,並一路下一步安裝。
安裝完成後,開啟命令提示符,試試node
命令和npm
命令是否正常。
看到如圖類似的內容,證明你的node
和npm
都已經安裝成功了。
搭建小程式開發環境
開發小程式的第一步,你需要擁有一個小程式帳號,透過這個帳號你就可以管理你的小程式。
申請賬號
點選 https://mp.weixin.qq.com/wxopen/waregister?action=step1 根據指引填寫資訊和提交相應的資料,就可以擁有自己的小程式帳號。
如果你註冊過小程式,可以點選右側的立即登入。如果沒有的話,請重新註冊,值得注意的是,郵箱必須填寫未在微信公眾平臺、未在微信開放平臺、個人未繫結的郵箱,不然這裡是無法註冊的。密碼請填寫你能記住的密碼即可。
現在登入https://mp.weixin.qq.com/,點選左側的設定——開發設定,在這裡,我們就能看到你小程式的AppID了。
當小程式的ID拿到之後,我們就可以下載安裝開發工具了。
安裝開發工具
現在,開啟 ,根據自己的作業系統下載對應的安裝包進行安裝。
我這裡使用的是Windows 64位作業系統,所以我點選Windwos 64位
按鈕進行下載。下載完成後,右鍵,然後以管理員身份執行安裝檔案。
之後,一路點選下一步安裝即可。
接下來,就可以開始執行開發者工具了。使用前需要我們掃描二維碼才能開始使用,請開啟微信,然後點選發現——掃一掃,掃描開發者工具展示的二維碼,之後在手機上點選登入即可。
- 關於小程式的快速搭建,我在有相關介紹,感興趣的小夥伴歡迎閱讀。
人臉識別API申請
如果要使用人臉識別API,必須在騰訊雲進行實名認證,實名認證後,您可以登入騰訊雲 進行使用。如果沒有賬號,請參考賬號 。註冊完成後,需要建立相關開發金鑰,不然無法使用API。
您需要在 建立金鑰,點選圖中的新建金鑰,即可建立金鑰。
建立完成後,點選SecretKey的顯示按鈕,顯示當前SecretKey,然後將APPID
、SecretId
、SecretKey
記錄下了,後面教程中使用。
現在,開發小程式所需要的所有環境就已經搭建完成,我們可以開始建立一個新的專案了。
建立雲開發專案
首先,我們新建一個雲開發的專案,注意AppID
是你自己在小程式AppID,同時不要勾選建立雲開發模版。
接下來,我們新建兩個目錄,一個目錄(client)存放小程式的客戶端,一個目錄(server)存放小程式雲開發的服務端,如圖。
接下來,開啟配置檔案project.config.json
,我們需要新增兩行檔案。
"cloudfunctionRoot": "server/",
"miniprogramRoot": "client/",
cloudfunctionRoot
引數填寫你新建的雲開發伺服器的檔案目錄,miniprogramRoot
填寫你小程式客戶端的目錄,如圖。
當你的server
資料夾圖示變成了☁的樣式,證明我們雲開發環境就搭建完成了。
- 對於雲函式的具體使用,我在這篇文章中做了詳細的介紹,感興趣請閱讀。
專案開發思考
在開始寫程式碼之前,我們先理一下思路。什麼東西放在服務端,什麼東西放在客戶端?
從安全形度考慮,我們在騰訊雲申請到的API金鑰是不能暴漏的,否則別人可以透過抓包去獲取我們的ID,從而濫用造成經濟上的損失,接下來就是為了識別人臉而上傳的圖片檔案,使用者資料十分重要,圖片千萬不能暴漏。官方也提供了一些如資料庫、儲存、雲函式所相關的能力,我們可以通雲開發提供的雲函式能力將騰訊的API金鑰存放在服務端執行,同樣的,也可以使用期所提供的雲端儲存和資料庫存放使用者的圖片及資料。
從產品開發角度考慮,希望產品執行足夠的快,減少客戶端與伺服器的通訊次數,降低運維壓力,增加併發數,同時,也要考慮到後期維護,所以程式碼儘可能的精簡。
具體思路是這樣子的:
- 客戶端選擇完圖片,然後在小程式端呼叫雲端儲存上傳API上傳圖片到雲端儲存,之後由雲端儲存返回一個檔案的ID到客戶端。
- 客戶端獲取檔案上傳後的ID,呼叫雲函式,在雲函式端去讀取雲端儲存的檔案,讀取其真實的URL地址。
- 將獲取到的地址在雲函式端傳送至騰訊雲人臉識別API,等待人臉識別介面返回相關內容。
- 人臉識別API返回內容後,雲函式原封不動的將資料發回給客戶端。
- 客戶端做解析,並展示給前端。
整個過程雲函式只與客戶端通訊兩次,同時將人臉識別API呼叫及使用者圖片存放在服務端,保證金鑰及資料的安全,能夠達到我們的要求。
- 對於雲端儲存的使用,我在有相關的講解,請參閱。雲端儲存可以在小程式的客戶端呼叫,也可以在雲函式的服務端呼叫。專案架構中,我們在客戶端上傳了相關檔案,之後獲取URL地址等操作均是在服務端完成的。
服務端開發
首先,我們先開發服務端,因為服務端作為架構的中心樞紐,負責接收和傳送資料,非常重要。當開發完服務端,撰寫客戶端資料處理的時候,才能事半功倍。
新建雲函式
接下來,我們開始新建雲函式,在server
資料夾上面點選右鍵,選擇新建NodeJS雲函式
,然後輸入你要建立雲函式的名稱,我這裡命名為Face_Detection
。
新建完成後,系統會自動生成index.js
和package.json
檔案。其中index.js
是官方給出的Demo檔案,我們將生成的程式碼稍微處理下,只保留最基本的模版。
雲函式 - index.js
// 雲函式入口檔案
const cloud = require('wx-server-sdk')
cloud.init()
// 雲函式入口函式
exports.main = async (event, context) => {
}
騰訊雲人臉識別API
我們開啟騰訊雲人臉識別的,先看看官方文件的API怎麼呼叫。
我們看到官方給了7中人臉相關的介面,因為我們只做最基本的人臉檢測,所以,選擇人臉檢測與分析相關介面
。
點選與分析DetectFace
介面,檢視API文件。我們看到介面提供了人臉(Face)的位置、相應的面部屬性和人臉質量資訊,位置包括 (x,y,w,h),面部屬性包括性別(gender)、年齡(age)、表情(expression)、魅力(beauty)、眼鏡(glass)、髮型(hair)、口罩(mask)和姿態 (pitch,roll,yaw),人臉質量資訊包括整體質量分(score)、模糊分(sharpness)、光照分(brightness)和五官遮擋分(completeness)等資訊的識別,那麼我們的小程式所返回的相關資料也逃不出這幾個內容,所以,給使用者展示的資訊建議也從這裡面的引數中選取。向下拉,檢視請求相關引數。
請求引數如圖,必填的是Action
和Version
,分別對應介面名稱及版本號,按照文件,我們這裡選擇DetectFace
和2018-03-01
。其他資料是選填的,如MaxFaceNum
人臉數,Url
圖片的地址等。我們專案架構中由雲端儲存所分享的是圖片的地址,所以URL
引數是必要的。同時我們想獲取圖片的人臉屬性資訊,所以按照表內容的內容,NeedFaceAttributes
引數也是必要的。
輸入引數看完了,我們看看輸出引數。
輸出引數有4組,分別是圖片的寬高,人臉的資訊以及請求的ID。當然,最重要的還是我們的FaceInfos
引數,我看點選藍色的FaceInfos
,看看具體有什麼內容。
資料蠻多的,這裡的FaceAttributesInfo
引數我們會用到,因為在輸入引數中,我們需要NeedFaceAttributes
,所以當NeedFaceAttributes
引數等於1
的時候,FaceAttributesInfo
引數才會返回相關的資料,我們點開FaceAttributesInfo
引數看看。
這裡就是返回引數的具體資料了,有性別,年齡,微笑程度等資訊,具體大家請看描述。我們看到還有一個Hair
引數,是頭髮的長度、劉海、髮色等資訊,點開FaceHairAttributesInfo
看看。
這裡就是該介面的相關資訊及所有的引數了,心裡大概有個底就可以了。
騰訊雲人臉識別SDK
繼續向下看文件,我們發現,API中給我們提供了相關的SDK。因為我們客戶端的程式碼是NodeJS的,官方也提供了相關的SDK,那麼就直接使用吧!
咦,等下,API Explorer
是什麼,點選去看看,原來,這是官方給我們提供的一個GUI頁面,透過簡單的設定,即可生成API呼叫的程式碼,能顯著降低使用雲 API 的難度。
我們就用這個工具來生成我們NodeJS端的程式碼吧!(注:當然,這裡也可自己寫相關程式碼去呼叫API,但是文件中對簽名驗證這塊講的模糊不清,所以我還是打算使用SDK)
點開工具,我們看到一個頁面,我們看到框內有我們前面所準備的SecretId
和SecretKey
,同時也有前文中我們提到的輸入引數Url
、NeedFaceAttributes
等。等下,必填Action
和Version
引數去哪裡了?
原來,當我們進入人臉識別的頁面後,系統已經自動幫我們填寫好了Action
和Version
引數,我們只需要直接使用就行了。
我們填寫下SecretId
和SecretKey
這兩個引數,然後Url
引數中,我們填入一張人臉的圖片,這裡大家可以自己去搜尋下,然後將圖片的地址貼上到這裡就可以。最後,將NeedFaceAttributes
引數為1
,根據文件,我們要返回人臉屬性。Region
引數大區可以不填,文件中已經說明。
如圖,當填寫完後,我們點選程式碼生成,然後選擇NodeJS
,系統會自動生成我們所需要的程式碼。(這裡有個BUG,URL地址不識別冒號,希望官方修復)
我們點選右側的線上呼叫,然後點選傳送請求,看看是否返回了正常的資料。
如圖,這樣的資料就是正常的響應結果。如果顯示說您未開通人臉識別服務,請前往開啟。我們回到程式碼生成頁面,複製NodeJS環境的所有程式碼。
const tencentcloud = require("../../../../tencentcloud-sdk-nodejs");
const IaiClient = tencentcloud.iai.v20180301.Client;
const models = tencentcloud.iai.v20180301.Models;
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG");
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com";
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile);
let req = new models.DetectFaceRequest();
let params = '{"Url":"","NeedFaceAttributes":1}'
req.from_json_string(params);
client.DetectFace(req, function(errMsg, response) {
if (errMsg) {
console.log(errMsg);
return;
}
console.log(response.to_json_string());
});
我們分析下程式碼,第一行程式碼是引入名為tencentcloud-sdk-nodejs
的包檔案,這個是騰訊雲SDK所依賴的檔案。後面幾行程式碼就是宣告人臉識別的相關版本,定義HTTP請求等。之後的cred
是宣告我們的在騰訊雲的相關金鑰,注意你使用的時候改成自己的,httpProfile.endpoint
是我們的介面地址,接下來是重點,params
引數是我們人人臉識別特有的介面,後續要增加或刪除相關引數都在這裡操作。最後的內容是回撥函式,並透過console.log
控制檯輸出,那麼如何在小程式端呼叫呢?
我們稍微修改下程式碼。
雲函式 - index.js
const cloud = require('wx-server-sdk')// 雲函式入口檔案
const tencentcloud = require("tencentcloud-sdk-nodejs"); //騰訊雲API 3.0 SDK
cloud.init() // 雲開發初始化
var synDetectFace = function (url) { //呼叫人臉識別API函式
const IaiClient = tencentcloud.iai.v20180301.Client; //API版本
const models = tencentcloud.iai.v20180301.Models; //API版本
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG"); //騰訊雲的SecretId和SecretKey
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com"; //騰訊雲人臉識別API介面
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile);
let req = new models.DetectFaceRequest();
let params = '{"Url":"","NeedFaceAttributes":1}'
req.from_json_string(params);
client.DetectFace(req, function (errMsg, response) {
if (errMsg) {
console.log(errMsg);
return;
}
console.log(response.to_json_string());
});
}
synDetectFace();
// 雲函式入口函式
exports.main = async (event, context) => {
}
這裡,我們將官方所給的程式碼封裝成名為synDetectFace
的函式,然後在最後透過synDetectFace()
去呼叫這個函式。exports.main
暫時留空,我們先做第一步測試。注意刪掉tencentcloud
引數中多餘的../../../../
因為後面我們將用npm包管理器安裝這個依賴,無需多餘的../../../../
。
接下來,我們需要安裝相關的依賴檔案,因為不管是執行雲開發還是執行騰訊雲SDK都需要相關的依賴檔案,這裡,我們就需要用到NodeJS
執行環境和npm
包管理器了。在我們的雲函式目錄上面右鍵,選擇在終端中開啟
。
然後輸入下面的命令,透過npm
包管理器,安裝雲函式和騰訊雲SDK的依賴檔案。
npm install tencentcloud-sdk-nodejs --save
npm install wx-server-sdk --save
這兩行命令即可安裝我們需要的依賴檔案,如圖所示。
不要關閉這個視窗,我們對我們的人臉識別介面進行測試,看看能否正常返回資料,執行下面的命令。
node index.js
如果看到類似的內容,就證明你的程式碼配置沒有錯誤,可以進行下一步了。
雲端儲存API呼叫
根據上面的架構,我們在服務端獲取到檔案的ID後,使用檔案ID去雲端儲存檔案的URL地址,目前我們在雲端儲存端還沒有檔案。那麼,第一步,將檔案上傳到雲端儲存。還好,雲開發控制檯可以直接上傳檔案,開啟控制檯,點選儲存管理
,如圖。
我們在這裡隨便上傳一個檔案,建議上傳一張人臉的照片,已方便我們後續測試。上傳之後點選右側的複製按鈕,複製檔案的ID。
接下來,我們開啟,呼叫getTempFileURL
介面,然後將ID傳送給雲端儲存。等待雲端儲存返回URL地址,這裡我們直接複製給出的程式碼。
const cloud = require('wx-server-sdk')
exports.main = async (event, context) => {
const fileList = ['cloud://xxx', 'cloud://yyy']
const result = await cloud.getTempFileURL({
fileList,
})
return result.fileList
}
將程式碼中的cloud://xxx
更換為剛才複製的檔案ID。
const fileList = ['cloud://test-f97abe.7465-test-f97abe/demo.jpg']
現在,開啟我們雲函式的index.js
檔案,將上面的程式碼整合到其中,並將返回的內容result.fileList
列印到控制檯。
雲函式 - index.js
const cloud = require('wx-server-sdk')// 雲函式入口檔案
const tencentcloud = require("tencentcloud-sdk-nodejs"); //騰訊雲API 3.0 SDK
cloud.init() // 雲開發初始化
var synDetectFace = function (url) { //呼叫人臉識別API函式
const IaiClient = tencentcloud.iai.v20180301.Client; //API版本
const models = tencentcloud.iai.v20180301.Models; //API版本
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG"); //騰訊雲的SecretId和SecretKey
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com"; //騰訊雲人臉識別API介面
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile);
let req = new models.DetectFaceRequest();
let params = '{"Url":"","NeedFaceAttributes":1}'
req.from_json_string(params);
client.DetectFace(req, function (errMsg, response) {
if (errMsg) {
console.log(errMsg);
return;
}
console.log(response.to_json_string());
});
}
synDetectFace();
// 雲函式入口函式
exports.main = async (event, context) => {
const fileList = ['cloud://test-f97abe.7465-test-f97abe/demo.jpg']
const result = await cloud.getTempFileURL({
fileList,
})
return result.fileList
}
接下來,我們部署下雲函式,讓其在雲開發端執行,我們看看能不能正常讀取到我們所需要的檔案。在雲函式上右鍵,選擇上傳並部署:所有檔案
,這一步,我們將我們剛剛寫的程式碼及所需要的依賴環境部署在服務端。
當彈出的對話方塊顯示上傳並部署完成後,我們就可以開啟雲開發的控制檯進行測試了。
點選雲函式按鈕,選擇我們剛剛上傳的雲函式,然後單擊右側的測試。
當點選執行測試
按鈕後,檢視當前返回結果,如果顯示成功,返回結果內有你提交的檔案ID及檔案的URL地址,證明我們雲端儲存在服務端的呼叫執行成功。
- 對於雲端儲存的使用,我在有相關的講解,請參閱。
雲函式程式碼整合
既然騰訊雲人臉API和雲函式端的雲端儲存API已經呼叫並測試成功,那麼就需要我們整合下兩個程式碼,因為現在我們們服務端的程式碼是分離的,況且程式碼中傳入的圖片也不是我們想要的圖片。
雲函式 - index.js(最終版)
const cloud = require('wx-server-sdk') //小程式雲開發SDK
const tencentcloud = require("tencentcloud-sdk-nodejs"); //騰訊雲API 3.0 SDK
cloud.init() //雲開發初始化
var synDetectFace = function(url) { //人臉識別API
const IaiClient = tencentcloud.iai.v20180301.Client; //API版本
const models = tencentcloud.iai.v20180301.Models; //API版本
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG"); //騰訊雲的SecretId和SecretKey
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com"; //騰訊雲人臉識別API介面
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile); //呼叫就近地域
let req = new models.DetectFaceRequest();
let params = '{"Url":"' + url + '","NeedFaceAttributes":1}' //拼接引數
req.from_json_string(params);
return new Promise(function(resolve, reject) { //構造非同步函式
client.DetectFace(req, function(errMsg, response) {
if (errMsg) {
reject(errMsg)
} else {
resolve(response);
}
})
})
}
exports.main = async(event, context) => {
const data = event
const fileList = [data.fileID] //讀取來自客戶端的fileID
const result = await cloud.getTempFileURL({
fileList, //向雲端儲存發起讀取檔案臨時地址請求
})
const url = result.fileList[0].tempFileURL
datas = await synDetectFace(url) //呼叫非同步函式,向騰訊雲API發起請求
return datas
}
我們將兩個程式碼進行了整合,並增加了相關的備註。
首先,將騰訊雲人臉識別API整體封裝成為一個名為synDetectFace
非同步函式,該函式攜帶名為url
的變數,當呼叫函式的時候,我們傳入url
引數,函式會透過Promise
方式將人臉識別返回的內容重新返回給呼叫端。
接下來,為了方便雲函式的呼叫,我們將客戶端傳過來的內容(檔案ID)存為變數data
,並向雲端儲存發起URL請求,將請求的返回值傳到非同步函式synDetectFace(url)
,此時,該函式會向騰訊雲發起AI識別請求,返回的請求值最終會返回給客戶端。
**修改完程式碼,別忘了部署在服務端。**到這一步,我們服務端的開發工作就全部搞定了。
客戶端開發
服務端開發完成後,我們已經完成了三分之二的程式碼,接下來就是撰寫客戶端的程式碼。關掉server
資料夾。開啟client
資料夾,然後新建一個名為app.json
的檔案,如圖。
將下面的程式碼複製到app.json
檔案中。
{
"pages": [
"pages/index/index"
],
"window": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "人臉識別Demo",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"enablePullDownRefresh": false
},
"cloud": true
}
儲存完成後,系統將自動生成相關目錄及檔案。
選擇圖片API
根據流程,我們的第一步就是選擇圖片了,小程式官方也提供了,廢話不多說,我們直接看程式碼。首先,開啟index.js
檔案,注意,這裡選擇的是客戶端的檔案,不是服務端的。
客戶端 - index.js
// pages/index/index.js
Page({
/**
* 頁面的初始資料
*/
data: {
},
/**
* 生命週期函式--監聽頁面載入
*/
onLoad: function (options) {
},
/**
* 生命週期函式--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命週期函式--監聽頁面顯示
*/
onShow: function () {
},
/**
* 生命週期函式--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命週期函式--監聽頁面解除安裝
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函式--監聽使用者下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函式
*/
onReachBottom: function () {
},
/**
* 使用者點選右上角分享
*/
onShareAppMessage: function () {
}
})
同樣,官方也提供了一堆已經存在的函式,為了方便我們撰寫程式碼,我們刪除用不到的內容。
客戶端 - index.js
Page({
data: {
},
onLoad: function (options) {
}
})
data
存放我們一些靜態資料,以便前端呼叫,onLoad
是小程式的初始化執行函式,當小程式頁面載入成功後會自動呼叫該函式,我們後續會用到。
接下來我們新建一個函式,這個函式用於當使用者在前端點選某個按鈕的時候,會執行該函式,我們將其命名為UploadImage
。
客戶端 - index.js
Page({
data: {
},
UploadImage(){
},
onLoad: function (options) {
}
})
參考的文件中的示例程式碼,修改程式碼如下。
客戶端 - index.js
Page({
data: {
},
UploadImage(){
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths
console.log(tempFilePaths)
}
})
},
onLoad: function (options) {
}
})
參考官方的文件,引數中,我們定一個圖片的張數,圖片的尺寸、來源。之後該API回撥返回tempFilePaths
臨時圖片地址。
- 關於圖片API的具體使用,可以參考這篇文章,文章中有較為詳細的介紹。
後端函式寫完了,我們需要點選一個按鈕執行上傳,撰寫下前端,開啟index.wxml
檔案,修改程式碼如下。
客戶端 - index.wxml
<button type="primary" bindtap="UploadImage">上傳照片</button>
當使用者點選圖中的上傳照片按鈕的時候,會自動呼叫我們在後端撰寫的UploadImage
函式,如圖。
當我們選擇照片後,會在控制檯輸出當前檔案的臨時地址,有了臨時地址,接下來一步就是將臨時地址傳給雲端儲存的API,讓其將檔案上傳。
雲端儲存上傳檔案API
同選擇圖片API一樣,微信官方文件中也提供了相關的例項程式碼。我們可以直接使用,先看程式碼。
客戶端 - index.js
Page({
data: {
},
UploadImage() {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: 'example.jpg',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
當上傳圖片API返回tempFilePaths
引數後,我們需要將其傳入雲端儲存上傳檔案的目錄。,根據文件,filePath
引數就是檔案資源的目錄。我們直接將返回tempFilePaths
引數放在該引數下,當選擇完圖片,會自動呼叫該API上傳名為example.jpg
的圖片檔案,同時我們上傳的檔案只有一張,也就是臨時目錄的第一張,所以返回的引數應改為res.tempFilePaths[0]
。
根據要求,在呼叫雲開發之前,我們還必須初始化,才能正常使用。所以程式碼中我們呼叫了wx.cloud.init
方法,並填寫了env
引數,這裡的引數請改為你自己的,開啟雲開發控制檯可檢視到你的環境ID
。
上傳成功後,返回回撥內容,並在控制檯列印出其檔案ID。
控制檯第一行是我們選擇圖片後的臨時地址,第二行上傳到雲端儲存後的檔案ID。
呼叫雲函式API
當雲端儲存呼叫完成後,我們拿到了檔案的ID,下一步就是真正的呼叫雲函式了,我們將檔案ID傳給雲函式,並等待雲函式返回人臉識別的結果。看一下官方的。
我們必須填寫的有云函式的名字,選填的有data
和config
,由於我們不更改區域性配置檔案,所以config
用不到。但是我們需要將我們的檔案ID傳送給服務端,所以要填寫的還有data
引數。
參考官方程式碼,我們呼叫下上面撰寫的Face_Detection
雲函式。
客戶端 - index.js
Page({
data: {
},
UploadImage() {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: 'example.jpg',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
console.log(res.result)
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
這裡的程式碼邏輯是,當我們圖片上傳完成後,透過返回的檔案ID去呼叫名為Face_Detection
的雲函式,該函式在服務端進行一系列操作後,將資料返回給客戶端,最終透過控制檯列印出來。
如果看到類似的結果,證明客戶端基本的請求操作已經寫完,這裡返回的內容就是我們人臉識別後騰訊雲API所返回的資料,我們可以進行下一步操作了。
當然,這裡程式碼中有一個BUG,就是所有上傳的圖片名稱都是example.jpg
,一個人使用當然不會造成什麼問題,但如果多個人併發使用這個小程式,就會產生一個很大的BUG,同一時間內請求的圖片地址相同,那麼返回的結果也相同,更有可能造成雲端儲存系統BUG。
為此,我將圖片的名稱變更為一個隨機數,這個同一時間內隨機數的內容不同,那麼圖片請求的時候就不會有多大問題,修改程式碼如下。
客戶端 - index.js
Page({
data: {
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
console.log(res.result)
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
我們新增了一個名為random
的隨機數,這個隨機數是當前的UTC時間與4位隨機數相加而得到的一個結果,然後將這個隨機數存為我們的圖片檔案的名稱。這樣寫的好處是,在同1秒內,最多可以支援1000張圖片的併發。
返回值最佳化
接下來,我們將返回的資料展示在前端,先隨便找一個引數返回在前端。先簡單測試下,我們將部分資料輸出到控制檯。首先,我們看看返回的引數列表。
簡單點,我們返回人臉Beauty
引數到控制檯吧,參考人臉識別返回的json資料,修改上面程式碼中的console.log(res.result)
返回引數。
console.log(res.result.FaceInfos[0].FaceAttributesInfo.Beauty)
再次上傳一遍資料,看看返回結果變成什麼了。
這裡返回的就是當前的魅力值,接下來,我們將這裡的魅力資料傳到前端。我們可以使用官方的setData
方法。修改整體程式碼如下。
客戶端 - index.js
Page({
data: {
Beauty:""
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
console.log(res.result.FaceInfos[0].FaceAttributesInfo.Beauty)
myThis.setData({
Beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty
})
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
客戶端 - index.wxml
<button type="primary" bindtap="UploadImage">上傳照片</button>
<text>{{Beauty}}</text>
我們在data
中,新增一個Beauty
變數,然後在下面的UploadImage
函式中,使用myThis.setData
函式改變變數Beauty
資料。最後,我們在index.wxml
檔案中去顯示這個返回的內容。
當然,返回的一個引數沒有多大用,我們將後臺的所有資料都返回到前端,並參考騰訊雲官方的文件,最佳化下首頁顯示。
客戶端 - index.js
Page({
data: {
age: "請上傳照片",
glasses: "請上傳照片",
beauty: "請上傳照片",
mask: "請上傳照片",
hat: "請上傳照片",
gender: "請上傳照片",
hair_length: "請上傳照片",
hair_bang: "請上傳照片",
hair_color: "請上傳照片",
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
gender:res.result.FaceInfos[0].FaceAttributesInfo.Gender,
hair_length: res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length,
hair_bang: res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang,
hair_color: res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang
})
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
客戶端 - index.wxml
<button type="primary" bindtap="UploadImage">上傳照片</button>
<text class="text_size">性別:{{gender}}</text>
<text class="text_size">年齡:{{age}}</text>
<text class="text_size">顏值:{{beauty}}</text>
<text class="text_size">是否帶眼鏡:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">頭髮長度:{{hair_length}}</text>
<text class="text_size">有無劉海:{{hair_bang}}</text>
<text class="text_size">頭髮顏色:{{hair_color}}</text>
如圖,我們已經將所需要的資料展示在前端了。但是展示的不夠完美,很多資料給使用者展示使用者也無法看懂。比如性別:0
、頭髮長度:3
、有無劉海:1
等。參考騰訊雲API文件,我們將這裡的資料使用switch
和if
語句做下判斷,不同的資料返回不同的內容,讓使用者看明白。
客戶端 - index.js
Page({
data: {
age: "請上傳照片",
glasses: "請上傳照片",
beauty: "請上傳照片",
mask: "請上傳照片",
hat: "請上傳照片",
gender: "請上傳照片",
hair_length: "請上傳照片",
hair_bang: "請上傳照片",
hair_color: "請上傳照片",
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光頭"
});
break;
case 1:
myThis.setData({
hair_length: "短髮"
});
break;
case 2:
myThis.setData({
hair_length: "中發"
});
break;
case 3:
myThis.setData({
hair_length: "長髮"
});
break;
case 4:
myThis.setData({
hair_length: "綁發"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有劉海"
});
break;
case 1:
myThis.setData({
hair_bang: "無劉海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
現在,我們已經將返回的內容正常顯示在前端了。
互動最佳化
接下來,我們可以最佳化前端了。
文字最佳化
首先,最難看的莫過於這裡交錯的文字了,這裡就需要修改index.wxss
檔案。
客戶端 - index.wxss
.text_viwe_size{
padding-top: 20px;
padding-bottom: 30px;
padding-left: 30px;
padding-right: 30px;
}
.text_size{
display:flex;
color: #444444;
}
我們定義一下文字顯示框的大小,並定義文字顯示方式和色彩。然後,修改index.wxml
檔案,讓其引用index.wxss
檔案。
客戶端 - index.wxml
<button type="primary" bindtap="UploadImage">上傳照片</button>
<view class='text_viwe_size'>
<text class="text_size">性別:{{gender}}</text>
<text class="text_size">年齡:{{age}}</text>
<text class="text_size">顏值:{{beauty}}</text>
<text class="text_size">是否帶眼鏡:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">頭髮長度:{{hair_length}}</text>
<text class="text_size">有無劉海:{{hair_bang}}</text>
<text class="text_size">頭髮顏色:{{hair_color}}</text>
</view>
上傳進度
參考小程式官方的,呼叫progress
元件,我們新增一個進度條元件,開啟index.wxml
檔案,先在前端顯示相關內容。
客戶端 - index.wxml
<button type="primary" bindtap="UploadImage">上傳照片</button>
<view class='progress_view_size'>
<progress percent="{{progress}}" show-info />
<text class="text_size">上傳進度</text>
</view>
<view class='text_viwe_size'>
<text class="text_size">性別:{{gender}}</text>
<text class="text_size">年齡:{{age}}</text>
<text class="text_size">顏值:{{beauty}}</text>
<text class="text_size">是否帶眼鏡:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">頭髮長度:{{hair_length}}</text>
<text class="text_size">有無劉海:{{hair_bang}}</text>
<text class="text_size">頭髮顏色:{{hair_color}}</text>
</view>
當然,前端展示了還無法顯示當前進度,我們需要在後端呼叫返回相關進度,然後再向前端展示。
客戶端 - index.js
Page({
data: {
age: "請上傳照片",
glasses: "請上傳照片",
beauty: "請上傳照片",
mask: "請上傳照片",
hat: "請上傳照片",
gender: "請上傳照片",
hair_length: "請上傳照片",
hair_bang: "請上傳照片",
hair_color: "請上傳照片",
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
var uploadTask = wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光頭"
});
break;
case 1:
myThis.setData({
hair_length: "短髮"
});
break;
case 2:
myThis.setData({
hair_length: "中發"
});
break;
case 3:
myThis.setData({
hair_length: "長髮"
});
break;
case 4:
myThis.setData({
hair_length: "綁發"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有劉海"
});
break;
case 1:
myThis.setData({
hair_bang: "無劉海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
uploadTask.onProgressUpdate((res) => {
myThis.setData({
progress: res.progress //上傳進度
})
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
這裡的程式碼中,我們將wx.cloud.uploadFile
存為名為uploadTask
的變數,然後在最後呼叫onProgressUpdate(res)
方法,並透過setData
方法,將資料展示在前端。接下來,最佳化下wxss
的程式碼,將前端修改漂亮點。
客戶端 - index.wxss
.text_viwe_size{
padding-top: 20px;
padding-bottom: 30px;
padding-left: 30px;
padding-right: 30px;
}
.text_size{
display:flex;
color: #444444;
}
.progress_view_size{
padding-left: 30px;
padding-right: 30px;
}
顯示識別圖片
現在展示端還不夠完美,人臉識別,當然是要將使用者的照片展示在前端,我們在index.wxml
檔案中插入圖片。
客戶端 - index.wxml
<view class="image_viwe_size">
<image src="{{image_src}}" style="width: 200px; height: 200px;"></image>
</view>
<view class='button_viwe_size'>
<button class="button_size" type="primary" bindtap="UploadImage">上傳照片</button>
</view>
<view class='progress_view_size'>
<progress percent="{{progress}}" show-info />
<text class="text_size">上傳進度</text>
</view>
<view class='text_viwe_size'>
<text class="text_size">性別:{{gender}}</text>
<text class="text_size">年齡:{{age}}</text>
<text class="text_size">顏值:{{beauty}}</text>
<text class="text_size">是否帶眼鏡:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">頭髮長度:{{hair_length}}</text>
<text class="text_size">有無劉海:{{hair_bang}}</text>
<text class="text_size">頭髮顏色:{{hair_color}}</text>
</view>
然後,我們需要在後端去寫image_src
圖片地址,做展示,開啟index.js
檔案,在data
中指定圖片地址。同時,當使用者點選圖片上傳按鈕的時候,我們將圖片地址替換為上傳的臨時檔案。
客戶端 - index.js
Page({
data: {
age: "請上傳照片",
glasses: "請上傳照片",
beauty: "請上傳照片",
mask: "請上傳照片",
hat: "請上傳照片",
gender: "請上傳照片",
hair_length: "請上傳照片",
hair_bang: "請上傳照片",
hair_color: "請上傳照片",
image_src:"https://cdn-img.easyicon.net/image/2019/panda-index.svg"
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
myThis.setData({
image_src: res.tempFilePaths[0]
});
var uploadTask = wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光頭"
});
break;
case 1:
myThis.setData({
hair_length: "短髮"
});
break;
case 2:
myThis.setData({
hair_length: "中發"
});
break;
case 3:
myThis.setData({
hair_length: "長髮"
});
break;
case 4:
myThis.setData({
hair_length: "綁發"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有劉海"
});
break;
case 1:
myThis.setData({
hair_bang: "無劉海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
uploadTask.onProgressUpdate((res) => {
myThis.setData({
progress: res.progress //上傳進度
})
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
最後,最佳化下前端的index.wxss
檔案。
客戶端 - index.wxss
.image_viwe_size{
display:flex;
justify-content: center;
background: #FFFFFF;
}
.image_size{
width: 300px;
}
.button_viwe_size{
display:flex;
padding-top: 10px;
padding-bottom: 10px;
}
.button_size{
height:50px;
width: 200px;
}
.text_viwe_size{
padding-top: 20px;
padding-bottom: 30px;
padding-left: 30px;
padding-right: 30px;
}
.text_size{
display:flex;
color: #444444;
}
.progress_view_size{
padding-left: 30px;
padding-right: 30px;
}
現在,整個UI好看多了。
識別狀態展示
現在,我們已經有了上傳圖片進度條,但是使用者上傳圖片後沒有相關提示資訊給使用者,使用者也不知道圖片上傳後是返回結果是不是正常的。那麼,怎麼去最佳化這塊呢?幸好微信官方給我們提供了,我們直接呼叫就行,直接上程式碼。
客戶端 - index.js
Page({
data: {
age: "請上傳照片",
glasses: "請上傳照片",
beauty: "請上傳照片",
mask: "請上傳照片",
hat: "請上傳照片",
gender: "請上傳照片",
hair_length: "請上傳照片",
hair_bang: "請上傳照片",
hair_color: "請上傳照片",
image_src:"https://cdn-img.easyicon.net/image/2019/panda-index.svg"
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
wx.showLoading({
title: '載入中...',
});
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
myThis.setData({
image_src: res.tempFilePaths[0]
});
var uploadTask = wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 檔案路徑
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
wx.hideLoading()
wx.showToast({
title: '成功',
icon: 'success',
duration: 500
})
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光頭"
});
break;
case 1:
myThis.setData({
hair_length: "短髮"
});
break;
case 2:
myThis.setData({
hair_length: "中發"
});
break;
case 3:
myThis.setData({
hair_length: "長髮"
});
break;
case 4:
myThis.setData({
hair_length: "綁發"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有劉海"
});
break;
case 1:
myThis.setData({
hair_bang: "無劉海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
uploadTask.onProgressUpdate((res) => {
myThis.setData({
progress: res.progress //上傳進度
})
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
圖片檔案選擇成功後,我們呼叫wx.showLoading
介面,展示載入中的提示框。當雲函式回撥成功後,我們立刻呼叫wx.hideLoading
隱藏載入中的提示框。同時,我們呼叫wx.showToast
介面,顯示訊息成功提示框。
現在,我們就完成了一款人臉識別小程式產品的開發,並能夠正常展示給使用者。
總結
專案終於寫完了,你學會了整體的小程式·雲開發並透過騰訊雲人臉識別流程了嗎?希望這篇文章能給你帶來一些新的經驗和想法!
當然,這裡的專案還有一些問題,比如圖片上傳到雲端儲存後會一直存在,沒有清空快取的機制。比如一秒內使用者最大併發是1000,因為圖片我們設定的隨機數最大是1000,後面建議將隨機數改為讀取圖片的md5
值然後顯示出來。這些BUG我也會慢慢去最佳化,喜歡請關注(Star)我的小程式人臉識別專案()。
感謝您閱讀我的文章,如果有什麼新的意見或者建議,請在評論區留言。BUG反饋請在Github提交。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1834/viewspace-2821524/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 智慧人臉識別門禁系統開發,人臉識別開鎖流程
- 人臉識別智慧考勤系統開發_人臉識別考勤管理系統開發
- 小程式--人臉識別功能(百度ai)AI
- IOS人臉識別開發入門教程--人臉檢測篇iOS
- 前端如何玩轉人臉識別前端
- 從零玩轉人臉識別
- 人臉識別和手勢識別應用(face++)開發
- opencv 人臉識別OpenCV
- OpenCV — 人臉識別OpenCV
- Android平板百度人臉識別開發Android
- 人臉檢測識別,人臉檢測,人臉識別,離線檢測,C#原始碼C#原始碼
- 從零玩轉人臉識別之RGB人臉活體檢測
- 人臉聚類那些事兒:利用無標籤資料提升人臉識別效能聚類
- C#人臉識別入門篇-STEP BY STEP人臉識別--入門篇C#
- 人臉識別之特徵臉方法(Eigenface)特徵
- 前端人臉識別--兩張臉相似度前端
- 人臉活體檢測人臉識別:眨眼+張口
- 乾貨 | AI人臉識別之人臉搜尋AI
- 美軍開發遠端人臉識別系統,實現1公里內目標識別
- java 百度人臉識別 介面程式碼Java
- 人臉識別技術應用
- python—呼叫API人臉識別PythonAPI
- 基於開源模型搭建實時人臉識別系統(五):人臉跟蹤模型
- 基於開源模型搭建實時人臉識別系統(四):人臉質量模型
- 人臉識別相關開源專案彙總
- 最新人臉識別demo開發經驗
- 人臉識別之人臉檢測的重要性
- python ubuntu dlib人臉識別3-人臉對齊PythonUbuntu
- 保障人臉安全!頂象釋出《人臉識別安全白皮書》
- 人臉識別之Python DLib庫進行人臉關鍵點識別Python
- 人臉識別門禁系統搭建,智慧小區實施方案
- 連不上 GitHub 的朝鮮,也開發出了人臉識別技術Github
- 刷臉支付人臉識別特徵點越多是別越精確特徵
- 64行程式碼實現簡單人臉識別行程
- 清華大學人臉識別技術:每秒能認256萬張臉(轉)
- 中國人臉識別產業鏈全景圖產業
- Python人臉識別微笑檢測Python
- 刪除十億人臉資料,Facebook關閉人臉識別系統