最佳實踐 | 用騰訊雲AI人臉融合實現畢業照推廣活動小程式

騰訊雲AI發表於2022-05-18

近兩年,經常在朋友圈、短視訊平臺刷到很多品牌的推廣活動都融入了AI能力,形成裂變式傳播,為品牌帶來巨大的曝光量。特別是之前爆火的畢業照雲寫真活動,為很多因為疫情無法舉行線下畢業活動的畢業生提供了畢業照換裝的體驗,不僅有趣,也挺有人文關懷。

作為一名小程式開發者,類似的玩法也激發了我的興趣,想參考這個活動,研究一下如何實現相似的活動小程式。感興趣的可以在微信小程式搜尋 【騰訊雲AI體驗中心】,直接訪問小程式體驗。

活動流程如下:

首先使用者需要完成授權,因為這裡涉及使用者人臉圖片等隱私資料,需要謹慎對待。

最佳實踐 | 用騰訊雲AI人臉融合實現畢業照推廣活動小程式


然後上傳或拍攝人臉圖片,活動平臺通過人臉融合服務,將使用者上傳圖片與各種畢業造型進行融合,最終得到畢業照融合結果並展示。並且使用者可以通過點選換造型,體驗不同造型的融合效果,大大增加了趣味性。

最佳實踐 | 用騰訊雲AI人臉融合實現畢業照推廣活動小程式

準備工作

首先畢業照雲寫真是由騰訊雲AI團隊推出的小活動,今天我們同樣選擇騰訊雲AI的人臉融合服務來實現相似的小程式。

在開始之前,需要先了解騰訊雲AI人臉融合服務,下一步在騰訊雲控制檯開通服務並建立專屬的活動以及上傳活動模板圖片。

瞭解騰訊雲人臉融合服務以及API使用方式:

人臉融合 API 概覽 - API 文件 - 文件中心 - 騰訊雲

訪問人臉融合控制檯: 開通人臉融合服務

新建活動,上傳模板圖片

注意,新活動有500次免費呼叫,後續可以購買資源包或者走後付費結算。

獲取API訪問金鑰 ,這個訪問金鑰十分重要,是每個使用者請求騰訊雲請求的標識,一旦洩漏,可能被拿去刷量從而產生高額費用,要謹慎保管。

其次,需要學習小程式開發的基礎知識: 微信開放文件,充分了解這兩個內容後,就可以開始開發。

開發過程

  • 前端頁面

以畢業照活動為例,總共包括:開始頁、上傳頁以及結果頁

開始頁:點選進入上傳頁

上傳頁:使用者可上傳或拍攝帶有人臉的圖片,作為畢業照的換臉圖使用

結果頁:將換臉圖與活動設定的隨機模板圖,通過騰訊雲人臉融合服務,請求並獲得換臉結果展示出來。當前活動主題是畢業季雲寫真,因此模板圖都是畢業照相關的內容,如果需要展示其他主題內容,可更換模板圖達到效果。

  • 前端開發

開始頁:簡單的頁面跳轉不贅述

上傳頁: (僅為主要邏輯,非完整程式碼)

主要完成點選相簿、點選拍攝兩個操作邏輯,其中相簿跟拍攝都可以使用微信小程式整合的介面: wx.chooseMedia,通過sourceType區分場景。

需要注意的是處理chooseMedia的回撥,成功獲取臨時圖片資料之後,將圖片上傳到雲端儲存,方便後面其他場景使用。上傳雲端儲存使用介面: wx.cloud.uploadFile,完成後即可跳轉到下一頁。

Page({
  data: {},
  async chooseMediaSuccessCB({ tempFiles }) {
    const tempFile = tempFiles[0];
    // 將臨時圖片上傳到雲端儲存
    const { fileID } = await wx.cloud.uploadFile({
      // 可設定隨機字串作為儲存名稱儲存
      cloudPath: 'xxxxxx.jpg',
      filePath: tempFile,
    });
    // 完成後,將圖片結果作為引數傳遞到結果頁
    wx.navigateTo({
      url: 'result?userImage=' + fileID, // 結果頁地址
    });
  },
  // 相簿按鈕響應事件
  tapAlbum() {
    wx.chooseMedia({
      count: 1,
      mediaType: ['image'],
      sourceType: ['album'],
      sizeType: ['compressed'],
      success: this.chooseMediaSuccessCB,
    });
  },
  // 拍攝按鈕響應事件
  async tapShoot() {
    const { authSetting } = await wx.getSetting({});
    const shoot = () => {
      wx.chooseMedia({
        count: 1,
        mediaType: ['image'],
        sourceType: ['camera'],
        // 預設使用前置攝像頭
        camera: 'front',
        sizeType: ['compressed'],
        success: this.chooseMediaSuccessCB,
      });
    };
    // 拍攝前需要諮詢攝像頭許可權
    if (!authSetting['scope.camera']) {
      wx.authorize({
        scope: 'scope.camera',
        success() {
          shoot();
        },
      })
    } else {
      shoot();
    }
  },
})

結果頁: (僅為主要邏輯,非完整程式碼)

結果頁需要完成上傳圖片與模板圖片的融合,以及換造型的邏輯。

為了提升整個換造型的體驗,可以將融合結果跟模板id對映並快取起來,節省請求發起!最重要的是省錢!

騰訊雲API的實現,我們是使用了小程式的雲開發,下一段落再詳細描述,這裡前端直接請求封裝好的請求函式即可,參考人臉融合API文件,將入參填入發起請求,邏輯本身並不複雜。請求小程式雲函式使用函式: wx.cloud.callFunction

Page({
  data: {
    userImage: '',
    resultImage: '',
  },
  async onLoad(option) {
    const userImage = option.userImage;
    this.setData({
      userImage,
    });
    // 預設進行一次人臉融合請求,獲取結果並展示
    await this.fuseFace(userImage);
  },
  // 換造型按鈕響應事件
  async tapReplace() {
    await this.fuseFace(this.data.userImage);
  },
  async fuseFace(userImage) {
    // 獲取隨機模板ID
    const modelId = this.getModelId();
    let resultImage = this.getResult(modelId);
    // 如果該模板ID在快取中有結果,直接拿快取結果返回
    if (resultImage) {
      this.setData({
        resultImage,
      });
      return;
    }
    // 請求騰訊雲人臉融合服務獲取結果
    // 此處使用小程式雲開發,可另行在服務端實現騰訊雲請求
    const { result: res } = await wx.cloud.callFunction({
      name: 'TencentCloudAI',
      data: {
        method: 'facefusion/FuseFace',
        data: {
          ProjectId: 'xxxx', // 在控制檯建立的活動ID
          ModelId: modelId,
          RspImgType: 'url',
          MergeInfos: [{
            Url: userImage,
          }],
        },      
      },
    });
    if (res && res.Response && res.Response.FusedImage) {
      resultImage = res.Response.FusedImage;
      this.setData({
        resultImage,
      });
      // 將modelID與融合結果配對存進快取
      this.saveResult(modelId, resultImage);
    }
  },
  // 隨機返回在騰訊雲人臉融合控制檯上傳的模板id
  getModelId() {},  
  // 根據modelId返回快取結果,沒有結果返回null
  getResult(modelId) {},
  // 將modelID與融合結果配對存進快取
  saveResult(modelId, resultImage);
})
  • 雲函式開發 (僅為主要邏輯,非完整程式碼)

接上,本次開發使用了雲函式實現騰訊雲函式請求,請求邏輯參考以下程式碼:requestYunApi.js,大家有需要複製貼上使用即可。通過金鑰完成鑑權, 由於涉及騰訊雲金鑰使用,強烈建議將金鑰放到雲函式存放,不要明文寫在前端程式碼裡

/* 雲函式TencentCloudAI */
const cloud = require('wx-server-sdk');
// 騰訊雲API請求函式
const requestAPI = require('./requestYunApi');
cloud.init();
function getFileUrl(url) {
  // 如果是 cloud:// 則,換取雲檔案真實連結
  if (/^cloud:\/\//.test(url)) {
    const { fileList } = await cloud.getTempFileURL({
      fileList: [url],
    }); 
    if (!fileList || !fileList[0]) {
      throw new Error('無法獲取檔案');
    } 
    return fileList[0].tempFileURL;
  }
  return url;
}
// 雲函式入口函式
exports.main = async (event) => {
  // 有云儲存fileID則將其轉換為http url
  if (event.data.MergeInfos) {
    const mergeInfos = event.data.MergeInfos;
    event.data.MergeInfos = await Promise.all(mergeInfos.map(mergeInfo => {
      ...mergeInfo,
      Url: await getFileUrl(cloud, e.Url),
    }));
  }
  // 請求引數,可以配置不同騰訊雲請求引數
  const configs = {
    'facefusion/FuseFace': {
      service: 'facefusion',
      action: 'FuseFace',
      version: 'v20181201',
    },
  };
  // 發起請求
  const requestRes = {
    Response: await requestAPI({
      ...configs[event.method],
      data: event.data,
    }),
  };
  return requestRes;
}

處理前端請求,需要注意的是,前端傳入的圖片檔案地址,是雲端儲存的地址,需要將雲端儲存換成真實的檔案地址,通過 cloud.getTempFileURL完成轉換邏輯。

/* 雲函式TencentCloudAI */
const cloud = require('wx-server-sdk');
// 騰訊雲API請求函式
const requestAPI = require('./requestYunApi');
cloud.init();
function getFileUrl(url) {
  // 如果是 cloud:// 則,換取雲檔案真實連結
  if (/^cloud:\/\//.test(url)) {
    const { fileList } = await cloud.getTempFileURL({
      fileList: [url],
    }); 
    if (!fileList || !fileList[0]) {
      throw new Error('無法獲取檔案');
    } 
    return fileList[0].tempFileURL;
  }
  return url;
}
// 雲函式入口函式
exports.main = async (event) => {
  // 有云儲存fileID則將其轉換為http url
  if (event.data.MergeInfos) {
    const mergeInfos = event.data.MergeInfos;
    event.data.MergeInfos = await Promise.all(mergeInfos.map(mergeInfo => {
      ...mergeInfo,
      Url: await getFileUrl(cloud, e.Url),
    }));
  }
  // 請求引數,可以配置不同騰訊雲請求引數
  const configs = {
    'facefusion/FuseFace': {
      service: 'facefusion',
      action: 'FuseFace',
      version: 'v20181201',
    },
  };
  // 發起請求
  const requestRes = {
    Response: await requestAPI({
      ...configs[event.method],
      data: event.data,
    }),
  };
  return requestRes;
}

釋出

開發完成並完成測試驗證後,即可通過小程式管理平臺釋出線上供使用者訪問。

至此整個畢業照活動的主要邏輯就介紹完成了,這個邏輯可以複用到類似的主題活動小程式裡面。如果有興趣的同學可以加入一起開發嘗試哦~


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70014348/viewspace-2895109/,如需轉載,請註明出處,否則將追究法律責任。

相關文章