手把手教你使用pytorch+flask搭建草圖檢索系統(三)
一、提要與預告
實話說,我是絕對沒有學過前端的,所以就在網上淘了幾個樣例然後拼接在一起,無法保證我寫的是不是對的,至少跑起來是符合預期的,但是否有隱患我無法保證。
二、畫板 頁面
本畫板是魔改自@zhoushuozh的畫板。我希望畫板擁有如下幾個功能:
- 能夠繪圖
- 有按鈕保存圖案,最好是opencv的可讀格式
- 有回退功能,能夠對草圖進行修改
- 如果用戶並不想親自手畫,畫板能提供上傳按鈕將已繪製好的草圖上傳
- 草圖畫好後,有按鈕將頁面從畫板跳轉到結果展示
所以,UI界面與畫板的功能應該如下圖所示:
前4個按鈕沿用了@zhoushuozh的畫板中的內容,從左至右分別是繪製按鈕,顧名思義就是可以在畫布上繪製線條;橡皮擦按鈕,當選擇橡皮擦後,可以再次選擇繪製按鈕後切換成繪筆;清屏按鈕,點了就可以清空屏幕;撤回按鈕,撤銷上一筆畫;保存按鈕,點了的話就可以將繪製的草圖上傳到後端;最後一個按鈕是上傳按鈕,用於用戶本地上傳已繪製好的草圖。
保存按鈕
當用戶在畫板頁面繪製好草圖後,點擊這個按鈕就可以把繪製好的草圖上傳至服務端。在html代碼中,我使用保存按鈕下方再疊一層文本的方式
<form action="" enctype='multipart/form-data' method='POST'>
<button id="save" title="保存"><i class="iconfont icon-fuzhi"></i></button>
<input type="text" name="sketchUpload" id="sketchUpload" value="" style="display:none"/>
</form>
把文本的id設爲id="sketchUpload"
,然後在後端controller.py
處得到綁定的這個id,它會將繪製的草圖按base64進行編碼,不要問我原理,問就是不知道,我沒學過無法解釋。
@app.route('/canvas', methods=['POST', 'GET'])
def upload():
if request.method == 'POST':
sketch_src = request.form.get("sketchUpload")
# ...
basepath = os.path.dirname(__file__)
upload_path = os.path.join(basepath, 'static/sketch_tmp', 'upload.png')
if flag == 1:
# base64 image decode
sketch = base64.b64decode(sketch_src[22:])
user_input = request.form.get("name")
file = open(upload_path, "wb")
file.write(sketch)
file.close()
在後端,通過base64.b64decode
把傳來的代碼解碼,得到手繪圖像,然後再保存下來。
上傳按鈕
用戶不想親自畫,剛好本地就有畫好的草圖,那麼就可以通過這個按鈕進行本地上傳。同樣地,這裏我先建立了一個button屬性的圖標,然後參考網上教程,在下面綁定了一個action?學過html的一定覺得這是小兒科,對於我來說就比較難了。
<button id="upload" title="upload">
<div align="center" style="margin:10px 0px 0px 3px">
<embed src="static/css/upload.svg" type="image/svg+xml" width="30" height="30"/>
</div>
</button>
<form action="" enctype='multipart/form-data' method='POST' id="upload_form">
<input type="file" name="uploadSketch" id="uploadSketch" style="display:none" accept="image/png, image/jpg">
<input type="text" name="uploadFlag" id="uploadFlag" value="0" style="display:none"/>
</form>
在後端,就通過下列代碼獲取這個uploadSketch
的動作id
sketch_src_2 = request.files["uploadSketch"]
sketch_src_2.save(upload_path)
user_input = request.form.get("name")
三、結果展示 頁面
這是我從網上扒的一個gallery代碼,然後根據自己的需求進行了修改。我希望能夠在左側顯示草圖,右側顯示檢索內容,並且按每行6張、每頁3行、共5頁的規則進行展示,如下圖所示。
調整圖像的位置折騰了我很久很久。
四、前後端交互
我們在後端拿到了用戶上傳的圖像後,就可以像一般pytorch模型的inference過程來得到檢索結果了,例如下面的代碼,得到了檢索結果後,我們需要將這些東西都回傳給前端,這裏我使用了json來保存,在retrieval
這個函數裏,就已經將路徑集合處理成了json格式,使用json.dumps
就可以進行解析了。
# for retrieval
retrieval_list, real_path = retrieval(retrieval_net, upload_path)
real_path = json.dumps(real_path)
return render_template('panel.html', userinput=user_input, val1=time.time(), upload_src=sketch_src,
retrieval_list=retrieval_list,
json_info=real_path)
最後通過render_template
命令將路徑、輸入草圖等數據傳給前端的panel.html
,整個鏈路就打通了。
五、demo
我將整份代碼已經上傳到了github中,整個項目是可以在cpu下跑的,我測試的版本是pytorch1.4.1+cpu、python3.6、flask 0.12.2,通過運行download_prerequisites.sh
應該就可以將項目的所有依賴全部下載下來了。
執行python controller.py
,然後在瀏覽器中輸入http://localhost:5000/canvas
,就可以進入到本系統中了。
六、總結
解釋前端部分完全是噩夢,因爲我沒學過,很多地方都無從下手,我只能把我想要的功能、行爲寫下來,實際上還有js和css需要講的,但我實在說不清楚,所以就把後面的內容全砍掉了,直接看我的代碼要好些吧。拖了這麼久,終於可以把這個坑填掉了,萬幸。