萬(wàn)粉博主推薦,微信小程序 +Flask 后端調(diào)用 AnimeGanV2
作者 | Yunlord
博客 | Yunlord
做一個(gè)小程序,直接在手機(jī)端就能一鍵生成專(zhuān)屬于自己的動(dòng)漫頭像,下面是展示效果?。?!
核心功能設(shè)計(jì)
該小程序想要實(shí)現(xiàn)的是將微信頭像或者選擇相冊(cè)中的照片動(dòng)漫化,所以拆解需求后,整理的核心功能如下:
授權(quán)登錄獲取頭像及昵稱
選擇相冊(cè)中的圖片
點(diǎn)擊動(dòng)漫化按鈕,調(diào)用Flask后端生成圖像
保存圖像
微信小程序前端實(shí)現(xiàn)步驟
首先新建一個(gè)空白的微信小程序項(xiàng)目。
1、登錄界面
在 pages/index/index.wxml 設(shè)計(jì)頁(yè)面:
<view wx:if="{{canIUse}}"> <view> <view> <open-data type="userAvatarUrl"></open-data> </view> </view> <view> <view>申請(qǐng)獲取以下權(quán)限</view> <text>獲得您的公開(kāi)信息(昵稱,頭像等)</text> </view> <button wx:if="{{canIUse}}" type="primary" bindtap="bindGetUserProfile" > 授權(quán)登錄 </button>
在 pages/index/index.js 添加用戶信息驗(yàn)證:
bindGetUserProfile(e) //當(dāng)用戶點(diǎn)擊授權(quán)登錄按鈕觸發(fā) bindGetUserInfo函數(shù) { var that=this wx.getUserProfile({ desc: '用于完善會(huì)員資料', // 聲明獲取用戶個(gè)人信息后的用途,后續(xù)會(huì)展示在彈窗中,請(qǐng)謹(jǐn)慎填寫(xiě) success: (res) => { // console.log(res.userInfo) var avantarurl=res.userInfo.avatarUrl; wx.navigateTo({ url: '../../pages/change/change?url='+ avantarurl , }) }, fail:(res)=>{ console.log(1) } }) },
其中將頭像的url傳遞給avanta界面。
效果如下:
2、avantar頁(yè)面
在該頁(yè)面進(jìn)行選取照片以及頭像動(dòng)漫化。
在 pages/avantar/avantar.wxml 設(shè)計(jì)頁(yè)面:
<!--pages/avantar/avantar.wxml--> <view> <view> <image src='{{prurl}}' mode='aspectFit'></image> </view> <view> <button bindtap='selectImg'>選擇圖片</button> <button bindtap='generateAvantar'>動(dòng)漫化</button> <button bindtap='save'>保存頭像</button> </view> </view>
在 pages/avantar/avantar.js 定義函數(shù):
其中 onload 函數(shù)接收 index 傳遞的 url。
onLoad: function (options) { if(options.url){ // console.log(options.url) var path = this.headimgHD(options.url) console.log(path) this.setData({ image:path, // image1:path, // baseURL:path }) }
其中 chooseImage函數(shù)實(shí)現(xiàn)選擇圖片。
chooseImage() { var that = this; wx.showActionSheet({ itemList: ['從相冊(cè)中選擇', '拍照'], itemColor: "#FAD143", success: function (res) { if (!res.cancel) { wx.showLoading({ title: '正在讀取...', }) if (res.tapIndex == 0) { that.chooseWxImage1('album', 1) } else if (res.tapIndex == 1) { that.chooseWxImage1('camera', 1) } } } }) },
savePic函數(shù)保存照片。
savePic(e) { let that = this var baseImg = that.data.baseImg //保存圖片 var save = wx.getFileSystemManager(); var number = Math.random(); save.writeFile({ filePath: wx.env.USER_DATA_PATH + '/pic' + number + '.png', data: baseImg, encoding: 'base64', success: res => { wx.saveImageToPhotosAlbum({ filePath: wx.env.USER_DATA_PATH + '/pic' + number + '.png', success: function (res) { wx.showToast({ title: '保存成功', }) }, fail: function (err) { console.log(err) } }) console.log(res) }, fail: err => { console.log(err) } }) },
generateAvantar函數(shù)調(diào)用postdata函數(shù)實(shí)現(xiàn)頭像動(dòng)漫化。
generateAvantar:function(e){ var that = this console.log(that.data.prurl) wx.uploadFile({ url: 'http://127.0.0.1:8090/postdata', filePath: that.data.prurl, name: 'content', success: function (res) { console.log(res.data); var resurl=JSON.parse(res.data)['resurl'] that.setData({ prurl: resurl }) if (res) { wx.showToast({ title: '轉(zhuǎn)換完成', duration: 3000 }); } }, fail: (res) =>{ console.log('fail===',res) } }) },
Flask后端實(shí)現(xiàn)步驟
1、配置RESTful路由方法
@app.route('/postdata', methods=['POST']) def postdata(): f = request.files['content'] print(f) user_input = request.form.get("name") basepath = os.path.dirname(__file__) # 當(dāng)前文件所在路徑 src_imgname = str(uuid.uuid1()) + ".jpg" upload_path = os.path.join(basepath, 'static/srcImg/') if os.path.exists(upload_path)==False: os.makedirs(upload_path) f.save(upload_path + src_imgname) # img = cv2.imread(upload_path + src_imgname, 1) save_path = os.path.join(basepath, 'static/resImg/') if os.path.exists(save_path) == False: os.makedirs(save_path) generateAvantar(src_imgname,upload_path,save_path) resSets["value"] = 10 resSets["resurl"] = "http://127.0.0.1:8090" +'/static/resImg/' + src_imgname return json.dumps(resSets, ensure_ascii=False)
該代碼主要接受前端傳來(lái)的圖片url,進(jìn)行處理并且通過(guò)json傳回去。
2、調(diào)用AnimeGanv2實(shí)現(xiàn)動(dòng)漫化
net = Generator() net.load_state_dict(torch.load(args.checkpoint, map_location="cpu")) net.to(args.device).eval() # print(f"model loaded: {args.checkpoint}") # os.makedirs(args.output_dir, exist_ok=True) def load_image(image_path, x32=False): img = cv2.imread(image_path).astype(np.float32) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w = img.shape[:2] if x32: # resize image to multiple of 32s def to_32s(x): return 256 if x < 256 else x - x%32 img = cv2.resize(img, (to_32s(w), to_32s(h))) img = torch.from_numpy(img) img = img/127.5 - 1.0 return img def generateAvantar(src_imgname,upload_path,save_path): image = load_image((upload_path+src_imgname), args.x32) with torch.no_grad(): input = image.permute(2, 0, 1).unsqueeze(0).to(args.device) out = net(input, args.upsample_align).squeeze(0).permute(1, 2, 0).cpu().numpy() out = (out + 1)*127.5 out = np.clip(out, 0, 255).astype(np.uint8) cv2.imwrite(os.path.join(save_path, src_imgname), cv2.cvtColor(out, cv2.COLOR_BGR2RGB))
該代碼主要是調(diào)用AnimeGanv2實(shí)現(xiàn)圖像動(dòng)漫化。
最后實(shí)現(xiàn)效果:
總結(jié)
其實(shí)這個(gè)小程序?qū)崿F(xiàn)起來(lái)并不是很難,只需要配置基礎(chǔ)的深度學(xué)習(xí)環(huán)境和Flask編程就好了,再了解一些小程序基本的api,就能夠開(kāi)發(fā)出來(lái),大家有時(shí)間的可以去試試,后臺(tái)我已經(jīng)搭好了,大家可以直接使用,可以看看效果。有什么問(wèn)題可以在評(píng)論區(qū)留言~
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。
基爾霍夫電流相關(guān)文章:基爾霍夫電流定律