前置安裝
我的樹莓派是3b,就1G內存,系統為stretch版本,自帶的python為3.5版本
強烈建議在燒寫樹莓派系統時就直接用buster版本,自帶的python版本在3.7及以上
Windows下直接使用PyCharm安裝python-opencv,python-opencv-contrib,pyqt5,pyqt5-tools
樹莓派下編譯安裝OpenCV:十分困難,可能要編譯4-5小時
樹莓派上python3已經可以直接使用pip包管理來直接安裝OpenCV
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libhdf5-dev libhdf5-serial-dev
sudo apt-get install libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5
sudo apt-get install libatlas-base-dev
sudo apt-get install libjasper-dev
sudo pip3 install --no-cache-dir opencv-contrib-python==3.4.3.18
檢測是否安裝成功:
python3 test.py
import cv2
print(cv2.__version__)
這里我們直接在Windows使用PyCharm寫代碼,然后通過FileZilla傳輸到樹莓派運行
靜態圖片檢測
灰度化
度化處理就是將一幅彩色圖像轉化為灰度圖像的過程
當R=G=B=255時,灰度值達到最高,顯示為白色,反之則顯示為黑色。
圖像灰度化的目的是為了簡化矩陣
彩色圖像中的每個像素顏色由R、G、B三個分量來決定,而每個分量的取值范圍都在0-255之間,這樣對計算機來說,彩色圖像的一個像素點就會有16777216種顏色的變化范圍
而灰度圖像是R、G、B分量相同的一種特殊彩色圖像,對計算機來說,一個像素點的變化范圍只有0-255這256種
使用到的特征分類器
Haar特征分類器,其實就是一個XML文件,用於描述人體各個部位的Haar特征值(眼睛,嘴唇等)
引用一個博客的說法:(42條消息) 機器學習 之 Haar特征_蘇的專欄-CSDN博客
Haar特征是一種反映圖像的灰度變化的,像素分模塊求差值的一種特征。它分為三類:邊緣特征、線性特征、中心特征和對角線特征。用黑白兩種矩形框組合成特征模板,在特征模板內用 黑色矩形像素和 減去 白色矩形像素和來表示這個模版的特征值。例如:臉部的一些特征能由矩形模塊差值特征簡單的描述,如:眼睛要比臉頰顏色要深,鼻梁兩側比鼻梁顏色要深,嘴巴比周圍顏色要深等。但矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述在特定方向(水平、垂直、對角)上有明顯像素模塊梯度變化的圖像結構。
在安裝目錄可以找到分類器文件,從文件名就能大致看出其功能
#detectMultiScale函數可以檢測處圖片中的所有人臉 ( 識別圖像中的人臉,返回所有人臉的矩形框向量組 )
#且可以使用向量(vector)將所有人臉的坐標大小(矩形表示)保存
# scaleFactor 為了檢測到不同大小的目標,通過scalefactor參數把圖像長寬同時按照一定比例(默認1.1)逐步縮小,
# 然后檢測,這個參數設置的越大,計算速度越快,但可能會錯過了某個大小的人臉。
# minNeighbors 構成檢測目標的相鄰矩形的最小個數,默認值是3
faces = haar_face_cascade.detectMultiScale(gray_img, scaleFactor=1.1,minNeighbors=3)
cv2.rectangle(image, start_point, end_point, color, thickness)
image:它是要在其上繪制矩形的圖像。
start_point:它是矩形的起始坐標。坐標表示為兩個值的元組,即(X坐標值,Y坐標值)。
end_point:它是矩形的結束坐標。坐標表示為兩個值的元組,即(X坐標值ÿ坐標值)。
color:它是要繪制的矩形的邊界線的顏色。對於BGR,我們通過一個元組。例如:(255,0,0)為藍色。
thickness:它是矩形邊框線的粗細像素。厚度-1像素將以指定的顏色填充矩形形狀
靜態檢測代碼
import cv2
import numpy as np
def dection(imagepath):
image = cv2.imread(imagepath,cv2.IMREAD_COLOR) #讀取圖片
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)#圖像灰度化,用於簡化矩陣運算
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') # xml來源於資源文件。
faces = face_cascade.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=1)
for (x , y, w, h) in faces:
image = cv2.rectangle(image, (x, y) , (x+w , y+h) , (0,0,255) , 2)
cv2.namedWindow('face')
cv2.imshow('face',image)
cv2.waitKey(0) #等待退出鍵
cv2.destroyAllWindows()
dection('img2.jpg')
用攝像頭做檢測(此時仍然是簡單的檢測,並非識別,大抵上只是將圖像源換為了攝像頭的圖像幀)
.pgm格式
Portable Gray Map
灰度圖像格式中一種最簡單的格式標准。另外兩種與之相近的圖片格式是PBM和PPM。它們分別相應着黑白圖像和彩色圖像
camera.read()函數
read()函數返回一個bool類型,表示幀的讀取的正確與否(可以用來檢查視頻文件是否到達結尾)
(read之前可以使用isOpened()來檢測是否成功初始化攝像頭
)
如果初始化false,則使用open()
read():
參數ret 為True 或者False,代表有沒有讀取到圖片 第二個參數frame表示截取到一幀的圖片
用一個死循環一直讀取攝像頭幀,每讀到一幀就檢測一次
import cv2
import numpy as np
def det(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
face_detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
faces = face_detector.detectMultiScale(gray, 1.2, 6)
for x, y, w, h in faces:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.imshow("result", image)
#視頻檢測人臉
def video_detc():
camera = cv2.VideoCapture(1)#打開攝像頭(插入usb攝像頭后,0為筆記本攝像頭,1為usb攝像頭)
while(True):
ret, frame = camera.read()
frame = cv2.flip(frame, 1)#設置個鏡像(好看一點)
det(frame)
c = cv2.waitKey(10)
if c == 27: # ESC
break
video_detc()
人臉識別數據集的錄入
使用pgm格式存儲
讓用戶自己輸入id(用於修改文件名,區分不同人的數據集)
例如某一個人錄入的pgm文件名全為:User_1.pam
,1即為用戶輸入的id
#一個id(一個人)錄入50-100張圖片,這里選了100張(可能在檢測的時候精度更高)
#並且保存為pgm格式
#需要去手動設置你的人臉id值
import cv2
import os
def input_face_data():
camera = cv2.VideoCapture(1)
#使用默認大小
face_detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
id = input("請輸入id,並回車:")
print("請正視攝像頭,多做幾個表情")
pic_count = 0 #記錄有多少pgm文件
while(True):
ret,frame = camera.read()
frame = cv2.flip(frame, 1) # 設置個鏡像(好看一點)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(gray, 1.2, 6)
for (x,y,w,h) in faces:
pic_count+=1
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
cv2.imwrite("D:\\py_study\\facedetection\\dataset\\User_"+str(id)+"_"+str(pic_count)+".pgm",gray[y:y+h,x:x+w])
cv2.imshow('image', frame)
print("錄入第"+str(pic_count)+"張結束")
k = cv2.waitKey(100) & 0xff # Press 'ESC' for exiting video
c = cv2.waitKey(10)
if c == 27: # ESC
break
elif pic_count>=100:
print("結束錄入數據集")
break
input_face_data()