今天的任務是將 Day 07 - RESTful API 在 Amazon Linux 2 上傳圖片實作、Day 08 - Amazon Linux 2 上將 Django 與 Nginx 整合、Day 09 - Amazon Linux 2 上解決跨來源資源共用 (CORS) 與開機自動啟動 uwsgi 這三天完成的 Django 後端結合 Day 14 - 安裝與執行 YOLO 的 Joseph/darknet ,這樣就可以完成觀賞魚辨識系統的完整後端應用。
下圖是觀賞魚辨識系統的泳道圖,因為每個系統之間都是獨立運行,所以透過泳道圖來表示各系統之間的關係是比較適合,後端的部份是從 Nginx, Django, YOLO 模型和資料庫所組成,當我們要整合後端時必須知道各元件之間的相互關係跟流程:
圖 1、觀賞魚辨識系統泳道圖
在 Django 載入 YOLO 事先訓練好的權重與網路架構組態
因為我們需要事先載入 YOLO 事先訓練好的權重與網路架構組態,這可以減少不必要的時間浪費,我們就這段代碼寫的 Django 的 view.py,可參閱 Day 07 - RESTful API 在 Amazon Linux 2 上傳圖片實作,但在撰寫代碼之前必須先把相關環境設定好,下圖是目前的相關路徑,最上層是 Python 的虛擬環境 fishRecognition,下一層是 Django 專案 fishsite (外層),然後我們在專案的目錄下放了 Joseph/darknet 的 YOLO 模型以及我們自建的觀賞魚數據集,而主要程式區則是放在 fishsite(內層) APP 這個目錄下,但因為所有匯入 (import) 的起始目錄是在 fishsite (外層),所以我們把需要用到的文件夾都在這個目錄下建立捷徑,包含了 libdarknet.so, cfg/, data/, weights/ 。
圖 2、Django 專案區的文件夾結構
在 fishsite/view.py 中新增載入 YOLO 事先訓練好的權重與網路架構組態的語法,下圖是部分代碼截圖。
fishsite/view.py
import darknet.python.darknet as dn
import cv2
import time
import numpy as np
import urllib.parse
print('load view model')
net = dn.load_net(str.encode("./FishRecognition/cfg/yolov3.cfg"),
str.encode("./FishRecognition/weights/yolov3.backup"), 1)
meta = dn.load_meta(str.encode("./FishRecognition/cfg/obj.data"))
圖 3、view.py 的部份代碼截圖
運行 Django,因為埠號 8000 已被佔用,所以選擇 8080,結果如下圖。
python3 manage.py runserver 0.0.0.0:8080
圖 4、運行 Django 的結果
呼叫 YOLO 辨識圖片
這段代碼需要完成:呼叫 YOLO 辨識圖片;處理辨識後結果;畫方塊框與寫入名稱,並產生處理後圖片;查詢資料庫,並回傳 JSON 結果。
fishsite/view.py
def post(self, request, *args, **krgs):
print('FishView->post')
uploadFile = request.FILES.get('fileUpload')
# write the uploaded file into the server
filename = r'upload/{}'.format(uploadFile.name)
with open(filename, 'wb') as f:
for chunk in uploadFile.chunks():
f.write(chunk)
print('FishView->upload')
# 呼叫 YOLO 辨識圖片
prev_time = time.time()
pridictStr = dn.detect(net, meta, str.encode(filename))
print((time.time() - prev_time))
# 處理辨識後結果
cv2image = cv2.imread(filename)
if len(pridictStr) > 0:
# 畫方塊框與寫入名稱,並產生處理後圖片
for k in range(len(pridictStr)):
print(pridictStr[k])
print(pridictStr[k][2])
x, y, w, h = pridictStr[k][2]
text = pridictStr[k][0].decode('utf-8')
x = int(x - w/2)
y = int(y - h/2)
cv2.putText(cv2image, "{} {:.4f}".format(text,pridictStr[k][1]), (x, y-6), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1, cv2.LINE_AA)
cv2.rectangle(cv2image, (int(x),int(y)), (int(x+w),int(y+h)), (0,255,0), 2)
cv2.imwrite(r'upload/new_{}'.format(uploadFile.name), cv2image)
# 查詢資料庫,並回傳 JSON 結果
sql = "SELECT fishName, distribution, LatinName FROM fishInfoTbl WHERE LatinName='{}'".format(pridictStr[0][0].decode('UTF-8'))
with connection.cursor() as cursor:
cursor.execute(sql)
data = dictfetchall(cursor)
print('FishView->' + sql)
data[0]['fishQtn']=len(pridictStr)
data[0]['processImg'] = 'http://18.138.102.108/images/new_{}'.format(urllib.parse.quote(uploadFile.name))
else:
data = dict({"error": "cannot recognize it"})
return JsonResponse(data,safe=False)
本段代碼無法處理一張圖片中有多個不同物件,需要再自行修改。
使用 Advanced REST Client
修改完 fishsite/view.py REST API 部分,重新的運行 Django。
python3 manage.py runserver 0.0.0.0:8080
然後在前端使用 Advanced REST Client 來呼叫 REST API ,呼叫結果如下圖,上傳一個 00-frame-608x608-0002.jpg 的圖片,回傳的結果就是辨識的內容,並且會回傳處理後的圖片所在位置,這樣方便前端顯示結果文字及圖片。
圖 5、運行 Django 的結果