imutils

imutils 是一个 基于 opencv 的 图像处理 工具包,对 opencv 进行了再次封装,简化了 opencv 的应用,这里不多赘述;

此外,imutils 专门配套 dlib 提供了处理 人脸的工具 face_utils;

dlib 获取人脸数据后,用特征点来描述五官,每个部位的 特征点 是固定的,想要进一步操作就需要处理这些 特征点,face_utils 就用于 快速处理这些 特征点

 

dlib 特征点索引

dlib  生成特征点对应下图,如 mouth:index 从 48 到 68,需要看这张图 才知道 哪些点对应嘴

face_utils 可直接获取

face_utils.FACIAL_LANDMARKS_IDXS
OrderedDict([('mouth', (48, 68)), ('inner_mouth', (60, 68)), ('right_eyebrow', (17, 22)), ('left_eyebrow', (22, 27)), ('right_eye', (36, 42)), ('left_eye', (42, 48)), ('nose', (27, 36)), ('jaw', (0, 17))])

 

dlib 特征点 存储

dlib 提取人脸的 68 个特征点后,用自身的 dlib.full_object_detection 格式保存他们的坐标信息,需要逐一通过 (shape.part(n).x, shape.part(n).y) 来获取

shape = predictor(img, d)        # 关键点检测
print(shape)        # <_dlib_pybind11.full_object_detection object at 0x0000013F450FCB20>
print(shape.part(0), shape.part(1), shape.part(2), shape.part(67))    # (322, 217) (319, 238) (319, 260) (386, 321)

 

face_utils 可直接转换

def shape_to_np(shape, dtype="int"):
    # initialize the list of (x, y)-coordinates
    coords = np.zeros((shape.num_parts, 2), dtype=dtype)

    # loop over all facial landmarks and convert them
    # to a 2-tuple of (x, y)-coordinates
    for i in range(0, shape.num_parts):
        coords[i] = (shape.part(i).x, shape.part(i).y)

    # return the list of (x, y)-coordinates
    return coords

当然,其实没做什么大事,只是把 坐标 放到 (68,2)的矩阵中

 

标记人脸部位

获取人脸部位后,face_utils 可直接对 这些部位进行标记

def visualize_facial_landmarks(image, shape, colors=None, alpha=0.75):
    # create two copies of the input image -- one for the
    # overlay and one for the final output image
    overlay = image.copy()
    output = image.copy()

    # if the colors list is None, initialize it with a unique
    # color for each facial landmark region
    if colors is None:
        colors = [(19, 199, 109), (79, 76, 240), (230, 159, 23),
            (168, 100, 168), (158, 163, 32),
            (163, 38, 32), (180, 42, 220)]

    # loop over the facial landmark regions individually
    for (i, name) in enumerate(FACIAL_LANDMARKS_IDXS.keys()):
        # grab the (x, y)-coordinates associated with the
        # face landmark
        (j, k) = FACIAL_LANDMARKS_IDXS[name]
        pts = shape[j:k]

        # check if are supposed to draw the jawline
        if name == "jaw":
            # since the jawline is a non-enclosed facial region,
            # just draw lines between the (x, y)-coordinates
            for l in range(1, len(pts)):
                ptA = tuple(pts[l - 1])
                ptB = tuple(pts[l])
                cv2.line(overlay, ptA, ptB, colors[i], 2)

        # otherwise, compute the convex hull of the facial
        # landmark coordinates points and display it
        else:
            hull = cv2.convexHull(pts)
            cv2.drawContours(overlay, [hull], -1, colors[i], -1)

    # apply the transparent overlay
    cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0, output)

    # return the output image
    return output

示例代码

import cv2
import dlib
from imutils import face_utils

detector = dlib.get_frontal_face_detector()
predictor_path = 'shape_predictor_68_face_landmarks.dat'
predictor = dlib.shape_predictor(predictor_path)

img = cv2.imread('img/cl.jpg')
det = detector(img, 1)
shape = predictor(img, det[0])
print(shape)

shape = face_utils.shape_to_np(shape)
img = face_utils.visualize_facial_landmarks(img, shape)
cv2.imshow('img', img)
cv2.waitKey(0)

输出

 

虹膜检测

检测流程:

执行面部关键点检测。

使用相应的关键点为两只眼睛创建蒙版。

阈值-。这一步取决于对象的虹膜色调。例如,如果你试图检测蓝眼睛人的虹膜,则应使用图像的红色或绿色通道来增加与白色背景的对比度。

找到二值化虹膜图像的质心。

找到二值化虹膜图像的轮廓。

找到所有虹膜轮廓的最小封闭圆。

比较步骤4中获得的质心与所有轮廓的最小封闭圆质心之间的距离。

选择到质心距离最小的圆。

使用步骤8中获得的圆创建蒙版和反向蒙版。

对整个图像应用颜色变换,并将该图像与虹膜蒙版相乘。

将原始图像乘以反向蒙版。

将步骤10和11的结果图像添加到一起。

 

import cv2
import dlib
import numpy as np
from imutils import face_utils

im = cv2.imread("img/cl.jpg")

# 检测脸部关键点
PREDICTOR_PATH = "shape_predictor_68_face_landmarks.dat"
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(PREDICTOR_PATH)
det = detector(im, 1)
shape = predictor(im, det[0])
shape = face_utils.shape_to_np(shape)

def createEyeMask(eyeLandmarks, im):
    leftEyePoints = eyeLandmarks
    eyeMask = np.zeros_like(im)
    cv2.fillConvexPoly(eyeMask, np.int32(leftEyePoints), (255, 255, 255))
    eyeMask = np.uint8(eyeMask)
    return eyeMask

def findIris(eyeMask, im, thresh):
    r = im[:, :, 2]
    _, binaryIm = cv2.threshold(r, thresh, 255, cv2.THRESH_BINARY_INV)
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (4, 4))
    morph = cv2.dilate(binaryIm, kernel, 1)
    morph = cv2.merge((morph, morph, morph))
    morph = morph.astype(float) / 255
    eyeMask = eyeMask.astype(float) / 255
    iris = cv2.multiply(eyeMask, morph)
    return iris

def findCentroid(iris):
    M = cv2.moments(iris[:, :, 0])
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])
    centroid = (cX, cY)
    return centroid

def createIrisMask(iris, centroid):
    cnts, _ = cv2.findContours(np.uint8(iris[:, :, 0]), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    flag = 10000
    final_cnt = None
    for cnt in cnts:
        (x, y), radius = cv2.minEnclosingCircle(cnt)
        distance = abs(centroid[0] - x) + abs(centroid[1] - y)
        if distance < flag:
            flag = distance
            final_cnt = cnt
        else:
            continue
    (x, y), radius = cv2.minEnclosingCircle(final_cnt)
    center = (int(x), int(y))
    radius = int(radius) - 2

    irisMask = np.zeros_like(iris)
    inverseIrisMask = np.ones_like(iris) * 255
    cv2.circle(irisMask, center, radius, (255, 255, 255), -1)
    cv2.circle(inverseIrisMask, center, radius, (0, 0, 0), -1)
    irisMask = cv2.GaussianBlur(irisMask, (5, 5), cv2.BORDER_DEFAULT)
    inverseIrisMask = cv2.GaussianBlur(inverseIrisMask, (5, 5), cv2.BORDER_DEFAULT)

    return irisMask, inverseIrisMask

def changeEyeColor(im, irisMask, inverseIrisMask):
    imCopy = cv2.applyColorMap(im, cv2.COLORMAP_TWILIGHT_SHIFTED)
    imCopy = imCopy.astype(float) / 255
    irisMask = irisMask.astype(float) / 255
    inverseIrisMask = inverseIrisMask.astype(float) / 255
    im = im.astype(float) / 255
    faceWithoutEye = cv2.multiply(inverseIrisMask, im)
    newIris = cv2.multiply(irisMask, imCopy)
    result = faceWithoutEye + newIris
    return result

def float642Uint8(im):
    im2Convert = im.astype(np.float64) / np.amax(im)
    im2Convert = 255 * im2Convert
    convertedIm = im2Convert.astype(np.uint8)
    return convertedIm

# 创建眼睛蒙版
leftEyeMask = createEyeMask(shape[36:42], im)
rightEyeMask = createEyeMask(shape[43:49], im)

# 设定阈值来找到虹膜
leftIris = findIris(leftEyeMask, im, 40)
rightIris = findIris(rightEyeMask, im, 50)

# 寻找质心
leftIrisCentroid = findCentroid(leftIris)
rightIrisCentroid = findCentroid(rightIris)

# 生成虹膜蒙版及其反蒙版
leftIrisMask, leftInverseIrisMask = createIrisMask(leftIris, leftIrisCentroid)
rightIrisMask, rightInverseIrisMask = createIrisMask(rightIris, rightIrisCentroid)

# 改变眼睛的颜色,并合并到原始图像
coloredEyesLady = changeEyeColor(im, rightIrisMask, rightInverseIrisMask)
coloredEyesLady = float642Uint8(coloredEyesLady)
coloredEyesLady = changeEyeColor(coloredEyesLady, leftIrisMask, leftInverseIrisMask)

# 现在的结果
cv2.imshow("", coloredEyesLady)
cv2.waitKey(0)

输出

 

眼睛检测

眨眼检测

疲劳检测

思路都大致相同,检测到特征点,然后提取某个部位,进行后续操作和计算,具体见参考资料,有些代码跑不通,懒得调了

 

滤镜

创建一个应用滤镜“戴口罩”

  1. 人脸识别,识别嘴巴区域。
  2. 使用蒙版技术获取医用口罩的真实面积。
  3. 将口罩放到指定的口腔区域

 

 

 

 

参考资料:

https://steven-cloud.blog.csdn.net/article/details/107105690?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ETopBlog-1-107105690-blog-114839030.topblog&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ETopBlog-1-107105690-blog-114839030.topblog&utm_relevant_index=1  imutils库源码解析,看它如何调用opencv(二)- 面部工具

https://blog.csdn.net/woshicver/article/details/121987470    使用OpenCV+Dlib检测虹膜并改变其颜色

https://blog.csdn.net/qq_38641985/article/details/115755417   基于dlib的眼睛检测

 

https://www.it610.com/article/1303927614737518592.htm  Dlib模型之驾驶员疲劳检测一(眨眼)

https://zhuanlan.zhihu.com/p/498712772          人脸检测实战高级:使用 OpenCV、Python 和 dlib 完成眨眼检测

https://www.cnblogs.com/gmhappy/p/11864119.html     dlib 基于摄像流检测眨眼次数

https://blog.csdn.net/wanlong_peng/article/details/115841226  openCV和python基于dlib库实现眨眼/睁闭眼检测--亲测高效

 

https://mp.weixin.qq.com/s/sVzm6AleDv1D6f3mIXfbLg  使用 OpenCV 创建一个有趣的应用程序滤镜,如 Facebook