這篇教學會使用 Teachable Machine 訓練「戴口罩」以及「沒戴口罩」的影像模型,再透過 OpenCV 搭配 tensorflow 讀取攝影鏡頭影像進行「是否有戴口罩」的影像辨識。
原文參考:辨識是否戴口罩
因為程式使用 Jupyter 搭配 Tensorflow 進行開發,所以請先閱讀「使用 Anaconda」和「Jupyter 安裝 Tensorflow」,安裝對應的套件,如果不要使用 Juputer,也可參考「使用 Python 虛擬環境」,建立虛擬環境進行實作。
開啟 Teachable Machine 網站後,點擊「開始使用」建立新專案 ( 最下方可以切換語系為繁體中文 ),選擇 「圖片專案 > 標準圖片模型」,進入圖片模型訓練流程。
準備 40~50 張人物戴戴口罩的圖片,圖片要求人物臉部清楚,背景從全白到複雜 ( 可以使用 Google 圖片搜尋一些名人戴口罩的照片 )。
再準備 40~50 張人物沒有戴口罩的圖片,圖片要求人物臉部清楚,背景從全白到複雜 ( 可以使用 Google 圖片搜尋一些名人沒有戴口罩的照片 )。
參考「使用 Teachable Machine」文章,使用「上傳圖片」的方式,建立「戴口罩」、「沒戴口罩」和「背景」共三個分類。
為什麼要訓練「背景」呢?因為如果沒有背景分類,會在沒有出拳的時候自動判斷最接近的分類,導致判斷出錯,所以建議一定要訓練一個背景的分類 ( 背景的分類除了單純的背景,也可以加入許多雜亂的圖片,增加背景的準確度 )。
分類建立後點擊「訓練模型」,等待訓練完成,可以從預覽區域測試模型。
確認辨識結果沒問題,就可以將模型匯出為 Keras 類型,解壓縮後將 .h5 的模型檔案放到指定的資料夾裡。
下方的程式碼使用 OpenCV 讀取攝影鏡頭的影像,即時判斷現在出現的影像是什麼分類,並透過 putText() 方法,在影像中加入分類的名稱。
參考:影像加入文字
import tensorflow as tf
import cv2
import numpy as np
model = tf.keras.models.load_model('keras_model.h5', compile=False) # 載入模型
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32) # 設定資料陣列
def text(text): # 建立顯示文字的函式
global img # 設定 img 為全域變數
org = (0,50) # 文字位置
fontFace = cv2.FONT_HERSHEY_SIMPLEX # 文字字型
fontScale = 1 # 文字尺寸
color = (255,255,255) # 顏色
thickness = 2 # 文字外框線條粗細
lineType = cv2.LINE_AA # 外框線條樣式
cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType) # 放入文字
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, frame = cap.read()
if not ret:
print("Cannot receive frame")
break
img = cv2.resize(frame , (398, 224))
img = img[0:224, 80:304]
image_array = np.asarray(img)
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
data[0] = normalized_image_array
prediction = model.predict(data)
a,b,bg= prediction[0] # 印出每個項目的數值資訊
print(a,b,bg)
if a>0.999: # 判斷有戴口罩
text('ok~')
if b>0.001: # 判斷沒戴口罩
text('no mask!!')
cv2.imshow('oxxostudio', img)
if cv2.waitKey(1) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
如果要加入中文,必須要使用 pillow 函式庫,開啟命令提示字元或終端機,啟動 tensorflow 虛擬環境安裝 pillow 函式庫,再使用下方的程式碼,就能夠加入中文的文字。
import tensorflow as tf
import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image # 載入 PIL 相關函式庫
fontpath = 'NotoSansTC-Regular.otf' # 設定字型路徑
model = tf.keras.models.load_model('keras_model_3.h5', compile=False) # 載入模型
data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32) # 設定資料陣列
def text(text): # 建立顯示文字的函式
global img # 設定 img 為全域變數
font = ImageFont.truetype(fontpath, 30) # 設定字型與文字大小
imgPil = Image.fromarray(img) # 將 img 轉換成 PIL 影像
draw = ImageDraw.Draw(imgPil) # 準備開始畫畫
draw.text((0, 0), text, fill=(255, 255, 255), font=font) # 寫入文字
img = np.array(imgPil) # 將 PIL 影像轉換成 numpy 陣列
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, frame = cap.read()
if not ret:
print("Cannot receive frame")
break
img = cv2.resize(frame , (398, 224))
img = img[0:224, 80:304]
image_array = np.asarray(img)
normalized_image_array = (image_array.astype(np.float32) / 127.0) - 1
data[0] = normalized_image_array
prediction = model.predict(data)
a,b,bg= prediction[0]
print(a,b,bg)
if a>0.999:
text('很乖')
if b>0.001:
text('沒戴口罩!!')
cv2.imshow('oxxostudio', img)
if cv2.waitKey(1) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我已經寫了超過 400 篇 Python 的教學,有興趣可以參考下方連結呦~ ^_^