https://m.toutiao.com/is/89vUHRb/?=AI視覺
有需要的可以使用 cv2.VideoCapture(0) 捕獲電腦攝像頭。本節(jié)就用視頻進(jìn)行人臉識(shí)別。
# 安裝opencvpip install opencv-contrib-python# 安裝mediapipepip install mediapipe# pip install mediapipe --user #有user報(bào)錯(cuò)的話試試這個(gè) # 安裝之后導(dǎo)入各個(gè)包import cv2 #opencvimport mediapipe as mpimport time
人臉檢測(cè)的相關(guān)說明見官方文檔:Face Detection - mediapipe
MediaPipe 人臉檢測(cè)是一種識(shí)別速度超快的方法,具有 6 個(gè)特征點(diǎn)和多面支持。它基于BlazeFcae一個(gè)輕量級(jí)且性能良好的面部檢測(cè)器,專為移動(dòng)GPU推理量身定制。該探測(cè)器的超實(shí)時(shí)性能使其能夠應(yīng)用于任何需要精確感興趣面部區(qū)域作為其他任務(wù)特定模型輸入的實(shí)時(shí)取景器體驗(yàn),例如3D面部關(guān)鍵點(diǎn)或幾何估計(jì)(例如 MediaPipe Face Mesh)面部特征或表情分類以及面部區(qū)域分割。
從mediapipe中導(dǎo)入檢測(cè)方法,今天我們使用人臉檢測(cè)
mediapipe.solutions.face_detection。
mediapipe.solutions.hands # 手部關(guān)鍵點(diǎn)檢測(cè)mediapipe.solutions.pose # 人體姿態(tài)檢測(cè)mediapipe.solutions.face_mesh # 人臉網(wǎng)狀檢測(cè)mediapipe.solutions.face_detection # 人臉識(shí)別....................
(1)
mediapipe.solutions.face_detection.FaceDetection() 人臉檢測(cè)函數(shù)
參數(shù):
min_detection_confidence: 默認(rèn)為 0.5。人臉檢測(cè)模型的最小置信值 (0-1之間),高于該置信度則將檢測(cè)視為成功。
返回值:
detections:檢測(cè)到的人臉的集合,其中每個(gè)人臉都表示為一個(gè)檢測(cè)原始消息,其中包含 人臉的概率、1 個(gè)邊界框、6 個(gè)關(guān)鍵點(diǎn)(右眼、左眼、鼻尖、嘴巴中心、右耳、左耳)。邊界框由 xmin 和 width (由圖像寬度歸一化為 [0, 1])以及 ymin 和 height (由圖像高度歸一化為 [0, 1])組成。每個(gè)關(guān)鍵點(diǎn)由 x 和 y 組成,分別通過圖像寬度和高度歸一化為 [0, 1]。
返回值.score: 獲取圖像是人臉的概率
返回值.location_data: 獲取識(shí)別框的 x, y, w, h 和 6個(gè)關(guān)鍵點(diǎn)的 x, y
返回值
.location_data.relative_bounding_box: 獲取識(shí)別框的 x, y, w, h
返回值
.location_data.relative_keypoints: 6個(gè)關(guān)鍵點(diǎn)的 x, y 組成的列表
(2)
mediapipe.solutions.drawing_utils.draw_landmarks() 繪制手部關(guān)鍵點(diǎn)的連線
參數(shù):
image: 需要畫圖的原始圖片
landmark_list: 檢測(cè)到的手部關(guān)鍵點(diǎn)坐標(biāo)
connections: 連接線,需要把那些坐標(biāo)連接起來
landmark_drawing_spec: 坐標(biāo)的顏色,粗細(xì)
connection_drawing_spec: 連接線的粗細(xì),顏色等
使用 cv2.VideoCapture() 讀取視頻文件時(shí),文件路徑最好不要出現(xiàn)中文,防止報(bào)錯(cuò)。
變量.read() 每次執(zhí)行就從視頻中提取一幀圖片,需要循環(huán)來不斷提取。用success來接收是否能打開,返回True表示可以打開。img保存返回的的每一幀圖像。
由于讀入視頻圖像通道一般為RGB,而opencv中圖像通道的格式為BGR,因此需要 cv2.cvtColor() 函數(shù)將opencv讀入的視頻圖像轉(zhuǎn)為RGB格式 cv2.COLOR_BGR2RGB。
import cv2import mediapipe as mpimport time # 導(dǎo)入人臉識(shí)別模塊mpFace = mp.solutions.face_detection# 導(dǎo)入繪圖模塊mpDraw = mp.solutions.drawing_utils# 自定義人臉識(shí)別方法,最小的人臉檢測(cè)置信度0.5faceDetection = mpFace.FaceDetection(min_detection_confidence=0.5) #(1)導(dǎo)入視頻filepath = 'C:\\GameDownload\\Deep Learning\\face.mp4'cap = cv2.VideoCapture(filepath) pTime = 0 # 記錄每幀圖像處理的起始時(shí)間 #(2)處理每一幀圖像while True: # 每次取出一幀圖像,返回是否讀取成功(True/False),以及讀取的圖像數(shù)據(jù) success, img = cap.read() # 將opencv導(dǎo)入的BGR圖像轉(zhuǎn)為RGB圖像 imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 將每一幀圖像傳給人臉識(shí)別模塊 results = faceDetection.process(imgRGB) # 如果檢測(cè)不到人臉那就返回None if results.detections: # 返回人臉關(guān)鍵點(diǎn)索引index,和關(guān)鍵點(diǎn)的坐標(biāo)信息 for index, detection in enumerate(results.detections): # 遍歷每一幀圖像并打印結(jié)果 print(index, detection) # 每幀圖像返回一次是人臉的幾率,以及識(shí)別框的xywh,后續(xù)返回關(guān)鍵點(diǎn)的xy坐標(biāo) # print(detection.score) # 是人臉的的可能性 # print(detection.location_data.relative_bounding_box) # 識(shí)別框的xywh # 繪制關(guān)鍵點(diǎn)信息及邊界框 mpDraw.draw_detection(img, detection) # 記錄每幀圖像處理所花的時(shí)間 cTime = time.time() fps = 1/(cTime-pTime) #計(jì)算fps值 pTime = cTime # 更新每張圖像處理的初始時(shí)間 # 把fps值顯示在圖像上,img畫板;fps變成字符串;顯示的位置;設(shè)置字體;字體大小;字體顏色;線條粗細(xì) cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_PLAIN, 3, (0,255,0), 3) # 顯示圖像,輸入窗口名及圖像數(shù)據(jù) cv2.imshow('image', img) if cv2.waitKey(50) & 0xFF==27: #每幀滯留50毫秒后消失,ESC鍵退出 break # 釋放視頻資源cap.release()cv2.destroyAllWindows()
結(jié)果如下圖所示,準(zhǔn)確找到了人臉位置,并繪制識(shí)別框。右側(cè)打印識(shí)別框和關(guān)鍵點(diǎn)信息。
在這里我更加關(guān)注識(shí)別框的位置位置,不太關(guān)心關(guān)鍵點(diǎn)的坐標(biāo)信息,因此接下來我們單獨(dú)繪制識(shí)別框,并把每一幀圖像的人臉概率顯示出來。如果有同學(xué)更關(guān)注人臉關(guān)鍵點(diǎn),可以使用mediapipe的人臉網(wǎng)狀檢測(cè),能得到的關(guān)鍵點(diǎn)非常多,這個(gè)我在后續(xù)章節(jié)也會(huì)寫。
因此,接下來我們?cè)谏厦娲a的基礎(chǔ)上繼續(xù)補(bǔ)充。
detection.location_data.relative_bounding_box 獲取檢測(cè)框的左上角坐標(biāo)和檢測(cè)框的寬高,保保存在bbox中。如下我們可以看到識(shí)別框的信息都是歸一化之后的,需要將其轉(zhuǎn)換為像素坐標(biāo)。
IN[21]: detection.location_data.relative_bounding_boxOut[21]: xmin: 0.6636191606521606ymin: 0.16451001167297363width: 0.1620280146598816height: 0.28804928064346313
轉(zhuǎn)換方法也很簡(jiǎn)單,只需要將比例長(zhǎng)度x和w乘以實(shí)際圖像寬度即可得到像素長(zhǎng)度下的x和w,同理y和h。注意,像素長(zhǎng)度一定是整數(shù),如[200,200],比例長(zhǎng)度是小數(shù),如[0.5, 0.5]
使用自定義矩形繪制函數(shù)cv2.rectangle(),現(xiàn)在有了像素坐標(biāo)下的左上坐標(biāo)xy,框的寬w和高h(yuǎn)。就可以在原圖像img上把框繪制出來。
detection.score 獲取檢測(cè)框的人臉概率值,返回只有一個(gè)元素的列表。detection.score[0] 提取這個(gè)元素,返回浮點(diǎn)型數(shù)值。
# 導(dǎo)入人臉識(shí)別模塊mpFace = mp.solutions.face_detection# 導(dǎo)入繪圖模塊mpDraw = mp.solutions.drawing_utils# 自定義人臉識(shí)別方法,最小的人臉檢測(cè)置信度0.5faceDetection = mpFace.FaceDetection(min_detection_confidence=0.5) #(1)導(dǎo)入視頻filepath = 'C:\\GameDownload\\Deep Learning\\face.mp4'cap = cv2.VideoCapture(filepath) pTime = 0 # 記錄每幀圖像處理的起始時(shí)間 boxlist = [] # 保存每幀圖像每個(gè)框的信息 #(2)處理每一幀圖像while True: # 每次取出一幀圖像,返回是否讀取成功(True/False),以及讀取的圖像數(shù)據(jù) success, img = cap.read() # 將opencv導(dǎo)入的BGR圖像轉(zhuǎn)為RGB圖像 imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 將每一幀圖像傳給人臉識(shí)別模塊 results = faceDetection.process(imgRGB) # 如果檢測(cè)不到人臉那就返回None if results.detections: # 返回人臉?biāo)饕齣ndex(第幾張臉),和關(guān)鍵點(diǎn)的坐標(biāo)信息 for index, detection in enumerate(results.detections): # 遍歷每一幀圖像并打印結(jié)果 # print(index, detection) # 每幀圖像返回一次是人臉的幾率,以及識(shí)別框的xywh,后續(xù)返回關(guān)鍵點(diǎn)的xy坐標(biāo) print(detection.score) # 是人臉的的可能性 print(detection.location_data.relative_bounding_box) # 識(shí)別框的xywh # 設(shè)置一個(gè)邊界框,接收所有的框的xywh及關(guān)鍵點(diǎn)信息 bboxC = detection.location_data.relative_bounding_box # 接收每一幀圖像的寬、高、通道數(shù) ih, iw, ic = img.shape # 將邊界框的坐標(biāo)點(diǎn)從比例坐標(biāo)轉(zhuǎn)換成像素坐標(biāo) # 將邊界框的寬和高從比例長(zhǎng)度轉(zhuǎn)換為像素長(zhǎng)度 bbox = (int(bboxC.xmin * iw), int(bboxC.ymin * ih), int(bboxC.width * iw), int(bboxC.height * ih)) # 有了識(shí)別框的xywh就可以在每一幀圖像上把框畫出來 cv2.rectangle(img, bbox, (255,0,0), 5) # 自定義繪制函數(shù),不適用官方的mpDraw.draw_detection # 把人臉的概率顯示在檢測(cè)框上,img畫板,概率值*100保留兩位小數(shù)變成百分?jǐn)?shù),再變成字符串 cv2.putText(img, f'{str(round(detection.score[0] * 100, 2))}%', (bbox[0], bbox[1]-20), # 文本顯示的位置,-20是為了不和框重合 cv2.FONT_HERSHEY_PLAIN, # 文本字體類型 2, (0,0,255), 2) # 字體大小; 字體顏色; 線條粗細(xì) # 保存索引,人臉概率,識(shí)別框的x/y/w/h boxlist.append([index, detection.score, bbox]) # 記錄每幀圖像處理所花的時(shí)間 cTime = time.time() fps = 1/(cTime-pTime) #計(jì)算fps值 pTime = cTime # 更新每張圖像處理的初始時(shí)間 # 把fps值顯示在圖像上,img畫板;fps變成字符串;顯示的位置;設(shè)置字體;字體大小;字體顏色;線條粗細(xì) cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_PLAIN, 3, (0,255,0), 3) # 顯示圖像,輸入窗口名及圖像數(shù)據(jù) cv2.imshow('image', img) if cv2.waitKey(50) & 0xFF==27: #每幀滯留50毫秒后消失,ESC鍵退出 break # 釋放視頻資源cap.release()cv2.destroyAllWindows()
結(jié)果如下圖所示,右側(cè)輸出每幀圖像的每個(gè)識(shí)別框的概率和框坐標(biāo)
接下來把識(shí)別框做的好看一些,只需要修改矩形框樣式即可,我們接著上面的代碼編輯。把識(shí)別框?qū)挾日{(diào)細(xì)一些,在四個(gè)角上添加粗線段。
# 導(dǎo)入人臉識(shí)別模塊mpFace = mp.solutions.face_detection# 導(dǎo)入繪圖模塊mpDraw = mp.solutions.drawing_utils# 自定義人臉識(shí)別方法,最小的人臉檢測(cè)置信度0.5faceDetection = mpFace.FaceDetection(min_detection_confidence=0.5) #(1)導(dǎo)入視頻filepath = 'C:\\GameDownload\\Deep Learning\\face.mp4'cap = cv2.VideoCapture(filepath) pTime = 0 # 記錄每幀圖像處理的起始時(shí)間 boxlist = [] # 保存每幀圖像每個(gè)框的信息 #(2)處理每一幀圖像while True: # 每次取出一幀圖像,返回是否讀取成功(True/False),以及讀取的圖像數(shù)據(jù) success, img = cap.read() # 將opencv導(dǎo)入的BGR圖像轉(zhuǎn)為RGB圖像 imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 將每一幀圖像傳給人臉識(shí)別模塊 results = faceDetection.process(imgRGB) # 如果檢測(cè)不到人臉那就返回None if results.detections: # 返回人臉?biāo)饕齣ndex(第幾張臉),和關(guān)鍵點(diǎn)的坐標(biāo)信息 for index, detection in enumerate(results.detections): # 遍歷每一幀圖像并打印結(jié)果 # print(index, detection) # 每幀圖像返回一次是人臉的幾率,以及識(shí)別框的xywh,后續(xù)返回關(guān)鍵點(diǎn)的xy坐標(biāo) print(detection.score) # 是人臉的的可能性 print(detection.location_data.relative_bounding_box) # 識(shí)別框的xywh # 設(shè)置一個(gè)邊界框,接收所有的框的xywh及關(guān)鍵點(diǎn)信息 bboxC = detection.location_data.relative_bounding_box # 接收每一幀圖像的寬、高、通道數(shù) ih, iw, ic = img.shape # 將邊界框的坐標(biāo)點(diǎn)從比例坐標(biāo)轉(zhuǎn)換成像素坐標(biāo) # 將邊界框的寬和高從比例長(zhǎng)度轉(zhuǎn)換為像素長(zhǎng)度 bbox = (int(bboxC.xmin * iw), int(bboxC.ymin * ih), int(bboxC.width * iw), int(bboxC.height * ih)) # 有了識(shí)別框的xywh就可以在每一幀圖像上把框畫出來 # cv2.rectangle(img, bbox, (255,0,0), 5) # 自定義繪制函數(shù),不適用官方的mpDraw.draw_detection # 把人臉的概率顯示在檢測(cè)框上,img畫板,概率值*100保留兩位小數(shù)變成百分?jǐn)?shù),再變成字符串 cv2.putText(img, f'{str(round(detection.score[0] * 100, 2))}%', (bbox[0], bbox[1]-20), # 文本顯示的位置,-20是為了不和框重合 cv2.FONT_HERSHEY_PLAIN, # 文本字體類型 2, (0,0,255), 2) # 字體大小; 字體顏色; 線條粗細(xì) # 保存索引,人臉概率,識(shí)別框的x/y/w/h boxlist.append([index, detection.score, bbox]) #(3)修改識(shí)別框樣式 x, y, w, h = bbox # 獲取識(shí)別框的信息,xy為左上角坐標(biāo)點(diǎn) x1, y1 = x+w, y+h # 右下角坐標(biāo)點(diǎn) # 繪制比矩形框粗的線段,img畫板,線段起始點(diǎn)坐標(biāo),線段顏色,線寬為8 cv2.line(img, (x,y), (x+20,y), (255,0,255), 4) cv2.line(img, (x,y), (x,y+20), (255,0,255), 4) cv2.line(img, (x1,y1), (x1-20,y1), (255,0,255), 4) cv2.line(img, (x1,y1), (x1,y1-20), (255,0,255), 4) cv2.line(img, (x1,y), (x1-20,y), (255,0,255), 4) cv2.line(img, (x1, y), (x1, y+20), (255, 0, 255), 4) cv2.line(img, (x,y1), (x+20,y1), (255,0,255), 4) cv2.line(img, (x,y1), (x,y1-20), (255,0,255), 4) # 在每一幀圖像上繪制矩形框 cv2.rectangle(img, bbox, (255,0,255), 1) # 自定義繪制函數(shù) # 記錄每幀圖像處理所花的時(shí)間 cTime = time.time() fps = 1/(cTime-pTime) #計(jì)算fps值 pTime = cTime # 更新每張圖像處理的初始時(shí)間 # 把fps值顯示在圖像上,img畫板;fps變成字符串;顯示的位置;設(shè)置字體;字體大小;字體顏色;線條粗細(xì) cv2.putText(img, f'FPS: {str(int(fps))}', (10,50), cv2.FONT_HERSHEY_PLAIN, 3, (0,255,0), 3) # 顯示圖像,輸入窗口名及圖像數(shù)據(jù) cv2.imshow('image', img) if cv2.waitKey(50) & 0xFF==27: #每幀滯留50毫秒后消失,ESC鍵退出 break # 釋放視頻資源cap.release()cv2.destroyAllWindows()
修改后的檢測(cè)框效果如下
我們將坐標(biāo)信息存放在了boxlist中,boxlist.append([index, detection.score, bbox]) 存放人臉?biāo)饕?、評(píng)分、檢測(cè)框信息,把它打印出來看一下,比如某幀圖像所在的視頻有3張臉,每一幀都會(huì)輸出0、1、2三個(gè)識(shí)別框的概率,左上角坐標(biāo)xy,框的寬高wh
。。。。。。。。。。。。。。。。。。。。。。。。。 [0, [0.9619430303573608], (98, 100, 96, 96)], [1, [0.9173532128334045], (457, 65, 118, 118)], [2, [0.8985080122947693], (268, 52, 123, 123)], [0, [0.9615015983581543], (98, 100, 97, 97)], [1, [0.9164762496948242], (457, 65, 118, 118)], [2, [0.9118367433547974], (269, 53, 123, 123)], [0, [0.9616674780845642], (97, 100, 97, 97)], [1, [0.9218802452087402], (272, 53, 122, 122)], [2, [0.9176990389823914], (456, 65, 118, 118)], [0, [0.9638006091117859], (97, 101, 97, 97)], [1, [0.9180505275726318], (276, 56, 119, 119)], [2, [0.9177079796791077], (456, 64, 118, 118)], 。。。。。。。。。。。。。。。。。。。。。。。。。。
聯(lián)系客服