https://www.irasutoya.com/2020/02/blog-post_556.html

用OpenCV實作簡單口罩辨識

LUFOR129

--

今年以來世界各地新冠肺炎肆虐,我在今年五月多用OpenCV搭配樹梅派做了一個簡單的口罩辨識。最近翻了一下以前寫的程式後發現還蠻有趣值得一寫的,不過這一篇不會寫有關樹梅派相關內容。

這篇算是一個OpenCV的簡單應用,其他OpenCV常用方法可以見我之前寫過的文章(雖然有點懶導致斷更了。不過因為觀看人數反響不錯,寒假有空我再把他補上去)

一、 實作流程與原理

原理非常簡單,計算戴口罩的部分(口鼻)與沒帶口罩的部分(眼額頭)之間顏色RGB的差距,當差距過大即辨識為戴口罩。

實作原理與流程如下面這幾個階段:

  1. 開啟鏡頭抓取影像
  2. 偵測人臉
  3. 將臉切成上下兩部分
  4. 計算各自上下兩部分的色彩直方圖
  5. 標準化畫計算上下兩部分直方圖差距
  6. 當差距過大即辨識為戴口罩

程式也非常簡單,就容我娓娓道來…。

二、程式

1. OpenCV開啟鏡頭

import cv2 as cv#抓取鏡頭 (如果你有的話)
cap = cv.VideoCapture(0)
#設定影像尺寸大小
cap.set(cv.CAP_PROP_FRAME_WIDTH, 800)
cap.set(cv.CAP_PROP_FRAME_HEIGHT, 800)
#如果cap能夠成功打開
while(cap.isOpened()):
ret,frame = cap.read()

# 顯示影像
cv.imshow("vedio",frame)

# 按下q離開
if(cv.waitKey(1) & 0xFF == ord('q')):
break
#關閉視窗
cap.release()
cv.destroyAllWindows()

2. 偵測人臉

偵測人臉可以有兩種方式,一種是OpenCV的Haar Cascade與Dlib,Haar Cascade在網路上有較多的資料並且之後我也會寫到OpenCV方法整理的文章中,這次就來用dlib做吧 !

# 如果你是用anaconda環境安裝方式就是如下,不過我記得python環境要在3.6以下
conda install -c menpo dlib
# 一般安裝就用
pip install dlib

安裝完dlib後,就能來抓取人臉了,程式非常簡單。

import dlibdetector = dlib.get_frontal_face_detector()img = cv.imread("./某個人臉圖片.jpg")
img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
for face in face_rects:
# 取得左上角的座標、右下角座標
x1 = face.left()
y1 = face.top()
x2 = face.right()
y2 = face.bottom()

# 畫出來
cv.rectangle(img, (x1, y1), (x2, y2), (0,255, 0), 4,cv.LINE_AA)
# 印出來
plt.imshow(img)
plt.show()
結果

3. 切割人臉並計算直方圖

把抓到的人臉分成上 1/3 與下 2/3。

faceLong = y2-y1
upface = img[y1:y1+int(1/3*faceLong),x1:x2]
downface = img[y1+int(1/3*faceLong):y2,x1:x2]

計算各自之間的顏色統計圖,正規化後比較差距。計算顏色統計圖表會用到calHist

# calHist 參數
# cv2.calcHist(images, channels, mask(Size), histSize, ranges)
# image 輸入圖片
# channel RGB第幾個channel
# MASK 不要取樣的部分
# histSize 統計映射範圍,例如你設定[64],就能將255壓縮到64之間
# ranges 取樣範圍 [0,256] 取0~255
color = ('r','g','b')for i, col in enumerate(color):
histr = cv.calcHist([upface],[i],None,[256],[0, 256])
plt.plot(histr, color = col)
plt.xlim([0, 256])
plt.title("upface")
plt.show()
for i, col in enumerate(color):
histr = cv.calcHist([downface],[i],None,[256],[0, 256])
plt.plot(histr, color = col)
plt.xlim([0, 256])
plt.title("downface")
plt.show()
顏色數量統計

因為上半臉與下半臉的pixel數量不同,所以我們會先做正規化normalize。並計算兩者之間的相似度。(compareHist)

hist1 = cv.calcHist([upface], [0,1,2], None, [64, 64,64], [0, 256, 0, 256,0, 256])
# 平移縮放
cv.normalize(hist1, hist1, 0, 1.0, cv.NORM_MINMAX)
hist2 = cv.calcHist([downface], [0,1,2], None, [64,64,64], [0, 256, 0, 256,0, 256])
cv.normalize(hist2, hist2, 0, 1.0, cv.NORM_MINMAX)
# 比較方法 HISTCMP_CORREL (相關姓) 0、HISTCMP_CHISQR (卡方) 1、HISTCMP_BHATTACHARYYA(巴式) 2
near = cv.compareHist(hist1,hist2,0)
print(near)
# 相似度為: 0.15370643779881982

我們可以設定,當相似度過低代表他是戴口罩的。

4. 把上面所有東西整合。

設定上下臉相似度小於0.01就是沒有戴口罩,這個值可以透過自己的經驗去做調整。整體程式如下:

結果如下,本色演出:

三、 結論與參考資料

用這個方法優點是簡單、快速並且有著不低的準確率(我自己試的時候)。缺點是當戴著口罩時容易無法檢測到臉部、當光線過暗顏色差距不明顯容易辨識錯誤…等。總得來說是一個簡單的OpenCV應用練習。

參考資料如下

  1. https://blog.gtwang.org/programming/python-opencv-matplotlib-plot-histogram-tutorial/
  2. https://lufor129.medium.com/opencv%E5%9C%96%E7%89%87%E8%99%95%E7%90%86%E6%95%B4%E7%90%86-%E7%B7%A9%E6%85%A2%E6%9B%B4%E6%96%B0-b45e248d14bb
  3. https://chtseng.wordpress.com/2016/12/23/dlib-%E5%A5%BD%E7%94%A8%E7%9A%84%E7%9A%84machine-learning%E5%B7%A5%E5%85%B7-%E4%B8%80/

--

--