1. 级联分类器: OpenCV提供的级联分类器有Harr、HOG、LBP这3种,这些分类器以XML文件保存,这里主要演示Harr检测人脸(OpenCV提供的分类器不仅限于检测人脸,还包括下表特征检测,当然OpenCV还支持训练自己的级联分类器,这里不做说明。。。)。
2. 函数介绍:
object = cv2.CascadeClassifier(filename) 加载分类器
object= faceCascade.detectMultiScale(img,scaleFactor,minNeighbors,minSize,maxSize) 检测对象
上代码:检测图片中的人脸
import cv2
# 1 原始图像处理
image = cv2.imread('model1.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 2 加载分类器
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 3 人脸检测
faces = faceCascade.detectMultiScale(
gray,
scaleFactor = 1.01,
minNeighbors = 15,
minSize = (8,8))
# 4 打印输出的实现
print("发现{0}张人脸!".format(len(faces)))
print("其位置分别是:")
print(faces)
# 5 遍历检测对象
for(x,y,w,h) in faces:
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2) # 绘制矩形(x、y、w、h)
cv2.imshow("result",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
# 1 加载分类器
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 2 处理摄像头视频
# 初始化摄像头
cap=cv2.VideoCapture(0,cv2.CAP_DSHOW)
# 处理每一帧
while True:
# 读取一帧
ret,image=cap.read()
image=cv2.flip(image,1)
# 没有读到,直接退出
if ret is None:
break
# 灰度化(彩色BGR-->灰度Gray)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 人脸检测
faces = faceCascade.detectMultiScale(gray,
scaleFactor = 1.1,
minNeighbors = 5,
minSize = (5,5))
# 处理每个人脸
for(x,y,w,h) in faces:
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
# 提取人脸所在区域,单通道形式
roi=gray[y:y+h,x:x+w] #image[起点,终点]
# 显示结果
cv2.imshow("dect",image)
cv2.imshow("roi",cutFace)
key=cv2.waitKey(25)
if key==27:
break
cap.release()
cv2.destroyAllWindows()
运行:
3. dlib库检测人脸: 免费的开源库,虽然测试速度不及前面的Harr级联分类器,但是准确率非常高。
上代码:
import cv2
import dlib
# dlib初始化
detector=dlib.get_frontal_face_detector()
# 读取原始图像
img=cv2.imread("imgs/3.jpg")
# 使用人脸检测器返回检测到的人脸框
faces=detector(img,1)
# 遍历人脸集合
for face in faces:
# 获取人脸框的坐标
x1=face.left()
y1=face.top()
x2=face.right()
y2=face.bottom()
# 绘制人脸框
cv2.rectangle(img,(x1,y1),(x2,y2),(0,255,0),2)
# 显示捕获到的各个人脸框
cv2.imshow("result",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行:
上代码:
import numpy as np
import cv2
import dlib
# 读取图像
srcImg = cv2.imread("model.jpg")
img=srcImg.copy()
# Step 1:构造人脸检测器(dlib初始化)
detector = dlib.get_frontal_face_detector()
# Step 2:检测人脸框(使用人脸检测器返回检测到的人脸框)
faces = detector(img, 1)
# Step 3:载入模型(加载预测器)
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
index=0
# Step 4:获取每一张脸的关键点(实现检测)
for face in faces:
index+=1
# 检测当前人脸的关键点
shape=predictor(img, face)
# 下面对这句代码进行了分解
# landmarks = np.matrix([[p.x, p.y] for p in shape.parts()])
# 通过shape.parts()方法遍历关键点
for i, p in enumerate(shape.parts()):
print('face:'+str(index)+' predictor:'+str(i)+' x:'+str(p.x)+' y:'+str(p.y))
# 将关键点的x,y放入一个2列68行的矩阵中,需要知道的是,人脸的每个特征对应的关键点索引是固定的,比如36-42描述的右眼。
landmarks = np.matrix([[p.x, p.y]])
# Step 5:绘制每一张脸的关键点(绘制shape中的每个点)
for idx, point in enumerate(landmarks):
# 当前关键的坐标:[0,1]表示第0行第1个元素
pos = (point[0, 0], point[0, 1])
# 针对当前关键点,绘制一个实心圆
cv2.circle(img, pos, 2, color=(0, 255, 0), thickness=-1)
# 字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 利用cv2.putText输出1-68,索引序号加1,显示时从1开始。
cv2.putText(img, str(i + 1), pos, font, 0.4, (255, 255, 255), 1, cv2.LINE_AA)
# 绘制结果
cv2.imshow("img", img)
cv2.imshow("src", srcImg)
cv2.waitKey()
cv2.destroyAllWindows()
脸部轮廓、眉毛这种起点和终点分开的区域,首先找到轮廓所在的关键点,然后使用点到点之间绘制直线的方式绘制边缘。
脸部眼睛、嘴巴这种起点和终点最终汇聚在一起的区域,首先找到轮廓所在的关键点,然后将这一组关键点坐标作为轮廓数组传入convexHull()函数进行凸包绘制。
凸包:找到图形最外侧的端点,然后将其连接起来。
凸包示例代码:
import cv2
img = cv2.imread("shape2.png") # 读取原始图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转为灰度图像
ret, binary = cv2.threshold(gray, 127, 225, cv2.THRESH_BINARY) # 二值化阈值处理
# 检测图像中出现的所有轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0]) # 获取轮廓的凸包
cv2.drawContours(img, [hull], -1, (0, 255, 0), 2)
cv2.imshow("img", img) # 显示图像
cv2.waitKey() # 按下任何键盘按键后
cv2.destroyAllWindows() # 释放所有窗体
勾勒五官轮廓代码:
import numpy as np
import dlib
import cv2
# 模型初始化
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# 自定义函数drawLine,将指定的点连接起来
def drawLine(start,end):
# 获取点集
pts = shape[start:end]
# 遍历点集,将各个点用直线连接起来
for l in range(1, len(pts)):
ptA = tuple(pts[l - 1])
ptB = tuple(pts[l])
cv2.line(image, ptA, ptB, (0, 255, 0), 2)
# 自定义函数,将指定的点构成一个凸包、绘制其轮廓
def drawConvexHull(start,end):
# 注意,凸包用来绘制眼睛、嘴
# 眼睛、嘴也可以用drawLine通过直线绘制
# 但是,使用凸包绘制轮廓,更方便进行颜色填充等设置
# 获取某个特定五官的点集
Facial = shape[start:end]
# 针对该五官构造凸包
mouthHull = cv2.convexHull(Facial)
# 把凸包轮廓绘制出来
cv2.drawContours(image, [mouthHull], -1, (0, 255, 0), 2)
# 读取图像
srcImg=cv2.imread("model2.jpg")
image=srcImg.copy()
# 色彩空间转换彩色(BGR)-->灰度(Gray)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 获取人脸
faces = detector(gray, 3)
# 对检测到的rects,逐个遍历
for face in faces:
# 针对脸部的关键点进行处理,构成坐标(x,y)形式
shape = np.matrix([[p.x, p.y] for p in predictor(gray, face).parts()])
# ============使用函数drawConexHull绘制嘴、眼睛=========================
#获取嘴部的关键点集(在整个脸部索引中,其索引范围为[48,60],不包含61)
drawConvexHull(48,59)
# 嘴内部
drawConvexHull(60,68)
# 左眼
drawConvexHull(42,48)
# 右眼
drawConvexHull(36,42)
# ============使用函数drawLine绘制脸颊、眉毛、鼻子=========================
# 将shape转换为np.array
shape=np.array(shape)
# 绘制脸颊,把脸颊的各个关键点(索引0-16,不含17)用线条连接起来
drawLine(0,17)
# 绘制左眉毛,通过将关键点连接实现(索引18-21)
drawLine(17,22)
# 绘制右眉毛(索引23-26)
drawLine(22,27)
# 鼻子(索引27-36)
drawLine(27,36)
cv2.imshow("Frame", image)
cv2.imshow("Src",srcImg)
cv2.waitKey()
cv2.destroyAllWindows()
运行:
以上,如有错误,欢迎指正批评!