Haar Cascade

功能說明

哈爾特徵(haar cascade)是目前檢測人臉的流行算法之一,可以用來檢視臉部、眼睛、鼻子、耳朵等,它的計算成本較低,算法速度快,並且精度高。

OpenCV 帶有許多預訓練的分類器。這些 haar-cascade的xml文件可以通過 cv2 模塊的 cascadeClassifier 方法加載。


Haar級聯預訓練的模型

OpenCV包含預先訓練好的Haar聯集模型,包括:

其中關於正面人臉分類器就包含了4個,alt、alt2、alt_tree、default。有網友針對這4個分類器進行了實驗,發現對比下來發現alt和alt2的效果比較好,alt_tree耗時較長,default是一個輕量級的,經常出現誤檢測。針對alt和alt2兩者,在同一個視頻的對比中檢測部分alt要略微好於alt2。


語法1:

detector = cv2.CascadeClassifier(xml分類器路徑)



語法2:

cv.CascadeClassifier.detectMultiScale(image,objects,scaleFactor = 1.1, minNeighbors = 3,flags = 0,minSize = Size(),maxSize = Size() )

參數1:image–待檢測圖片,一般為灰度圖像加快檢測速度; 

參數2:objects–被檢測物體的矩形框向量組; 

參數3:scaleFactor–表示在前後兩次相繼的掃描中,搜索窗口的比例係數。預設為1.1即每次搜索窗口依次擴大10%。 由於某些人臉可能離相機更近,因此它們看起來會比後面的人臉大。 比例因數對此進行了補償。

參數4:minNeighbors–表示構成檢測目標的相鄰矩形的最小個數(預設為3個)。如果組成檢測目標的小矩形的個數和小於min_neighbors - 1 都會被排除。如果min_neighbors 為0, 則函數不做任何操作就返回所有的被檢候選矩形框。

參數5:flags–使用預設值或使用CV_HAAR_DO_CANNY_PRUNING,函數將會使用Canny邊緣檢測來排除邊緣過多或過少的區域, 因為這些區域通常不會是人臉所在區域。

 參數6、7:minSize和maxSize用來限制得到的目標區域的範圍。如果視頻中誤檢到很多無用的小方框,那麼就把minSize的尺寸改大一些,預設為30*30。


https://github.com/opencv/opencv/tree/master/data/haarcascades

程式範例:照片人臉辨識

#載入OpenCV函式庫

import cv2


#讀取照片資料

img = cv2.imread('pic.jpg')


#將照片轉成灰階,加快辨識速度

gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


#載入需要的Haar檔案

haar_cascade = cv2.CascadeClassifier('/home/pi/.local/lib/python3.9/site-packages/cv2/data/haarcascade_frontalface_alt.xml')


#人臉檢測,1.1和3分別為圖片縮放比例和需要檢測到多少有效數量才保留

faces_rect = haar_cascade.detectMultiScale(gray_img, 1.1, 3)


#匡列人臉

for (x, y, w, h) in faces_rect:

cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)


#顯示影像

cv2.imshow('Detected faces', img)


#保存圖片

#cv2.imwrite( "result.jpg", img )


#給定的時間內(單位毫秒)等待使用者的按鍵觸發,否則持續循環

cv2.waitKey(0)

程式範例:影片人臉辨識

import cv2


def CatchVideo(window_name):

    #只有一個鏡頭就填0,兩個鏡頭填0或1(選鏡頭)

    cap = cv2.VideoCapture(0)

   

    #也可以讀取影片

    #cap = cv2.VideoCapture("filename")

    #告訴OpenCV使用人臉識別分類器

    classfier_path='/home/pi/.local/lib/python3.9/site-packages/cv2/data/'

    classfier = cv2.CascadeClassifier(classfier_path + 'haarcascade_frontalface_alt.xml')

    #識別出人臉後要畫的邊框的顏色,RGB格式

    facecolor = (0, 255, 0)

    while True:

    #讀取鏡頭資料,ret為成功與否的回傳值,frame為影格

        ret, frame = cap.read()

        #如果讀取錯誤就停止  

        if ret==False:

            break

        #將當前影格轉換成灰階,加快辨識速度

        grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)


        #人臉檢測,1.1和3分別為圖片縮放比例和需要檢測到多少有效數量才保留

        faceRects = classfier.detectMultiScale(grey, scaleFactor = 1.1, minNeighbors = 3, minSize = (32, 32))

        #大於0則檢測到人臉

        if len(faceRects) > 0:

        #單獨框出每一張人臉

            for x, y, w, h in faceRects:

                cv2.rectangle(frame, (x, y ), (x + w ,y + h), facecolor, 2)

                #顯示影像

                cv2.imshow(window_name, frame)


        #10 ms等待使用者的按鍵觸發,否則持續循環,如果輸入為q則停止

        if cv2.waitKey(10) & 0xFF == ord('q'):

            break

    #釋放鏡頭

    cap.release()

    #關閉視窗

    cv2.destroyAllWindows()


if __name__ == '__main__':

    CatchVideo("Vedio")

程式範例:照片臉部各部位辨識

#載入OpenCV函式庫

import cv2


#讀取照片資料

img = cv2.imread('pic_o.jpg')

#調整圖片尺寸

#img = cv2.resize(img, (900,600))


#將照片轉成灰階,加快辨識速度

gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


#載入需要的Haar檔案

classfier_path='/home/pi/.local/lib/python3.9/site-packages/cv2/data/'

classfier_face = cv2.CascadeClassifier(classfier_path + 'haarcascade_frontalface_alt2.xml')

classfier_eye = cv2.CascadeClassifier(classfier_path + 'haarcascade_eye.xml')

#classfier_mouse = cv2.CascadeClassifier(classfier_path + 'haarcascade_smile.xml')


#人臉檢測,1.1和3分別為圖片縮放比例和需要檢測到多少有效數量才保留

faces_rect = haar_face.detectMultiScale(gray_img, 1.1, 3)


#迴圈檢測人臉

for (fx, fy, fw, fh) in faces_rect:

    #將面部範圍切出來,再進一步檢測眼睛或其他

    gray_face = gray_img[fy:(fy+fh), fx:(fx+fw)]


    #眼睛檢測,1.1和3分別為圖片縮放比例和需要檢測到多少有效數量才保留

    eyes_rect = haar_eye.detectMultiScale(gray_face, 1.1, 3)

    #mouse_rect = haar_mouse.detectMultiScale(gray_face, 1.1, 3)

    

    #繪製臉部方框

    cv2.rectangle(img, (fx, fy), (fx+fw, fy+fh), (0, 255, 0), 2)

    #加入說明文字

    cv2.putText(img, "face", (fx, fy-5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)


    #繪製眼睛方框        

    for (ex, ey, ew, eh) in eyes_rect:

        cv2.rectangle(img, (fx+ex, fy+ey), (fx+ex+ew, fy+ey+eh), (0, 0, 255), 2)

        #加入說明文字

        cv2.putText(img, "eye", (fx+ex, fy+ey-5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1)


    '''

    for (mx, my, mw, mh) in mouse_rect:

        cv2.rectangle(img, (fx+mx, fy+my), (fx+mx+mw, fy+my+mh), (255, 0, 0), 2)

    '''

    

#顯示影像

cv2.imshow('Detected faces', img)


#保存圖片

#cv2.imwrite( "result.jpg", img )


#給定的時間內(單位毫秒)等待使用者的按鍵觸發,否則持續循環

cv2.waitKey(0)

程式範例:影片臉部各部位辨識

import cv2


def CatchVideo(window_name):

    #只有一個鏡頭就填0,兩個鏡頭填0或1(選鏡頭)

    cap = cv2.VideoCapture(0)


    #也可以讀取影片

    #cap = cv2.VideoCapture("filename")


    #告訴OpenCV使用人臉識別分類器

    classfier_path='/home/pi/.local/lib/python3.9/site-packages/cv2/data/'

    classfier_face = cv2.CascadeClassifier(classfier_path + 'haarcascade_frontalface_alt2.xml')

    classfier_eye = cv2.CascadeClassifier(classfier_path + 'haarcascade_eye.xml')

    #classfier_mouse = cv2.CascadeClassifier(classfier_path + 'haarcascade_smile.xml')


    #識別出人臉後要畫的邊框的顏色,RGB格式

    facecolor = (0, 255, 0)

    eyecolor=(0,0,255)

    mousecolor=(255,0,0)


    while True:

        #讀取鏡頭資料,ret為成功與否的回傳值,frame為影格

        ret, frame = cap.read()


        #如果讀取錯誤就停止

        if ret==False: 

            break


        #將當前影格轉換成灰階,加快辨識速度

        grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 

    

        #人臉檢測,1.2和3分別為圖片縮放比例和需要檢測到多少有效數量才保留

        haar_face = classfier_face.detectMultiScale(grey, scaleFactor = 1.2, minNeighbors = 3, minSize = (32, 32)) 


        #大於0則檢測到人臉

        if len(haar_face) > 0:

            #單獨框出每一張人臉 

            for fx, fy, fw, fh in haar_face:

                #將面部範圍切出來,再進一步檢測眼睛或其他

                grey_face = grey[fy:(fy+fh), fx:(fx+fw)]


                #繪製臉部方框

                cv2.rectangle(frame, (fx, fy ), (fx + fw ,fy + fh), facecolor, 2) 

                #加入說明文字

                cv2.putText(frame, "face", (fx, fy-5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, facecolor, 2)

                

                #眼睛檢測,1.2和3分別為圖片縮放比例和需要檢測到多少有效數量才保留

                harr_eyes = classfier_eye.detectMultiScale(grey_face, 1.2, 3)

                #mouse_rect = haar_mouse.detectMultiScale(grey_face, 1.1, 3)



                #繪製眼睛方框        

                for (ex, ey, ew, eh) in harr_eyes:

                    cv2.rectangle(frame, (fx+ex, fy+ey), (fx+ex+ew, fy+ey+eh), eyecolor, 2)

                    #加入說明文字

                    cv2.putText(frame, "eye", (fx+ex, fy+ey-5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, eyecolor, 1)


                '''

                for (mx, my, mw, mh) in mouse_rect:

                    cv2.rectangle(frame, (fx+mx, fy+my), (fx+mx+mw, fy+my+mh), (255, 0, 0), 2)

                '''


        #顯示影像

        cv2.imshow(window_name, frame)


        #10 ms等待使用者的按鍵觸發,否則持續循環,如果輸入為q則停止

        if cv2.waitKey(10) & 0xFF == ord('q'):

            break

    #釋放鏡頭

    cap.release()

    #關閉視窗

    cv2.destroyAllWindows()


if __name__ == '__main__': 

     CatchVideo("Vedio") 

OpenCV官方範例

#!/usr/bin/env python


'''

face detection using haar cascades


USAGE:

    facedetect.py [--cascade <cascade_fn>] [--nested-cascade <cascade_fn>] [<video_source>]

'''


# Python 2/3 compatibility

from __future__ import print_function


import numpy as np

import cv2 as cv


# local modules

from video import create_capture

from common import clock, draw_str



def detect(img, cascade):

    rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30),

                                     flags=cv.CASCADE_SCALE_IMAGE)

    if len(rects) == 0:

        return []

    rects[:,2:] += rects[:,:2]

    return rects


def draw_rects(img, rects, color):

    for x1, y1, x2, y2 in rects:

        cv.rectangle(img, (x1, y1), (x2, y2), color, 2)


def main():

    import sys, getopt


    args, video_src = getopt.getopt(sys.argv[1:], '', ['cascade=', 'nested-cascade='])

    try:

        video_src = video_src[0]

    except:

        video_src = 0

    args = dict(args)

    cascade_fn = args.get('--cascade', "data/haarcascades/haarcascade_frontalface_alt.xml")

    nested_fn  = args.get('--nested-cascade', "data/haarcascades/haarcascade_eye.xml")


    cascade = cv.CascadeClassifier(cv.samples.findFile(cascade_fn))

    nested = cv.CascadeClassifier(cv.samples.findFile(nested_fn))


    cam = create_capture(video_src, fallback='synth:bg={}:noise=0.05'.format(cv.samples.findFile('samples/data/lena.jpg')))


    while True:

        _ret, img = cam.read()

        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

        gray = cv.equalizeHist(gray)


        t = clock()

        rects = detect(gray, cascade)

        vis = img.copy()

        draw_rects(vis, rects, (0, 255, 0))

        if not nested.empty():

            for x1, y1, x2, y2 in rects:

                roi = gray[y1:y2, x1:x2]

                vis_roi = vis[y1:y2, x1:x2]

                subrects = detect(roi.copy(), nested)

                draw_rects(vis_roi, subrects, (255, 0, 0))

        dt = clock() - t


        draw_str(vis, (20, 20), 'time: %.1f ms' % (dt*1000))

        cv.imshow('facedetect', vis)


        if cv.waitKey(5) == 27:

            break


    print('Done')



if __name__ == '__main__':

    print(__doc__)

    main()

    cv.destroyAllWindows()


相關連結

教學推薦:https://pyimagesearch.com/2021/04/12/opencv-haar-cascades/

官方文件:

OpenCV: Cascade Classifier 

https://www.geeksforgeeks.org/face-detection-using-cascade-classifier-using-opencv-python/

http://www.codebaoku.com/it-python/it-python-222465.html

metadatahttps://www.tensorflow.org/lite/convert/metadata


cv2.waitkey是OpenCV內置的函式,用途是在給定的時間內(單位毫秒)等待使用者的按鍵觸發,否則持續循環。

0xFF是十六進制常數,二進制值為11111111。這個寫法只留下原始的最後8位,和後面的ASCII碼對照——不必深入理解,此處是為了防止BUG。

ord(' ')可以將字符轉化為對應的整數(ASCII碼)。

如上面的判斷式——如果使用者没有按下q键,就會持續等待(循環),直到觸發後執行break跳出迴圈。