1. 级联分类器: OpenCV提供的级联分类器有Harr、HOG、LBP这3种,这些分类器以XML文件保存,这里主要演示Harr检测人脸(OpenCV提供的分类器不仅限于检测人脸,还包括下表特征检测,当然OpenCV还支持训练自己的级联分类器,这里不做说明。。。)。
在这里插入图片描述

2. 函数介绍:

object = cv2.CascadeClassifier(filename) 加载分类器

  • object:分类器对象。
  • filename:分类器xml路径+文件名。

object= faceCascade.detectMultiScale(img,scaleFactor,minNeighbors,minSize,maxSize) 检测对象

  • object:返回值(目标对象的x、y、w、h信息)。
  • scaleFactor:缩放比例。
  • minNeighbors:检测目标的相邻矩形的最小个数。默认为3,表示满足3个以上的检测标记才会认为是人脸。该值越大越准确,但是会导致一些人脸检测不到。
  • minSize:目标最小尺寸,小于会被忽略。

上代码:检测图片中的人脸

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级联分类器,但是准确率非常高。

  • 检测人脸:
    detector=dlib.get_frontal_face_detector() 构造dlib检测器
    faces=detector(img,n) 检测人脸
    faces:人脸集合。
    n:上采样次数,图像会变大,但是准确率会提高,这个参数对速度影响极大。

上代码:

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()

运行:
在这里插入图片描述

  • 检测关键点:
    detector=dlib.get_frontal_face_detector() 构造dlib检测器
    faces=detector(img,n) 检测人脸
    predictor = dlib.shape_predictor(dat) 加载预测
    dat:模型文件
    predictor:预测器对象,返回68个脸部关键点。

上代码:

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()

运行:
在这里插入图片描述


以上,如有错误,欢迎指正批评!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐