OpenCV
嘴部检测
"""
嘴部区域检测
1. 静态图像检测嘴部区域
创建分类器
加载特征文件
检测图像
绘制嘴部区域
显示
2. 切换为摄像头
"""
import cv2
import numpy as np
class FaceDetect:
def __init__(self):
# 级联分类器
# 创建级联分类器,当前用于检测人脸
classifier_face = cv2.CascadeClassifier()
classifier_mouth = cv2.CascadeClassifier()
# 加载 特征文件
classifier_face.load('./haarcascade_frontalface_alt.xml')
classifier_mouth.load('./haarcascade_mcs_mouth.xml')
self.classifier_face = classifier_face
self.classifier_mouth = classifier_mouth
# 初始化logo
self.logo = cv2.imread('./fans.jpg')
pass
def capVideo(self):
cap = cv2.VideoCapture(0)
while cap.isOpened():
# 读取一帧一帧的图像
retval, frame = cap.read()
if not retval:
print('can not read frame')
break
# imshow 会默认创建一个窗口
self.detect(frame)
cv2.imshow('frame', frame)
key = cv2.waitKey(25)
if key == ord('z'):
break
cap.release()
pass
def detect(self, face_img):
# 级联分类器检测人脸
face_rects = self.classifier_face.detectMultiScale(face_img)
# 绘制人脸区域
for face_rect in face_rects:
x, y, w, h = face_rect
cv2.rectangle(face_img, (x, y), (x + w, y + h), color=(0, 0, 255), thickness=2)
# self.drawLogo(face_rect, face_img)
# self.drawLogo2(face_rect, face_img)
self.detectMouth(face_rect, face_img)
def detectMouth(self, face_rect, face_img):
# 检测嘴巴
mouth_rects = self.classifier_mouth.detectMultiScale(face_img)
face_min_x, face_min_y, face_w, face_h = face_rect
# 方式1
# for mouth_rect in mouth_rects:
# x, y, w, h = mouth_rect
# # 排除人脸左右区域
# # if x < face_min_x or x > face_min_x + face_w:
# # continue
# # # 排除人脸上下区域
# # if y < face_min_y or y > face_min_y + face_h:
# # continue
# # 排除人脸中部上面的区域
# if y < face_min_y + face_h * 0.6:
# continue
# cv2.rectangle(face_img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)
# 方式2
# is_right_mouth = mouth_rects[:, 0] > face_min_x
# is_down_mouth = mouth_rects[:, 1] > face_min_y
# is_lower_mouth = mouth_rects[:, 1] > (face_min_y + face_h * 0.6)
# is_mouth = is_right_mouth & is_down_mouth & is_lower_mouth
# mouth_rect = mouth_rects[is_mouth]
idx = mouth_rects[:, 1] > (face_min_y + face_h * 0.6)
mouth_rect = mouth_rects[idx]
for rect in mouth_rect:
x, y, w, h = rect
cv2.rectangle(face_img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)
def drawLogo(self, face_rect, face_img):
x, y, w, h = face_rect
logo = self.logo
ratio = min(logo.shape[:2]) / max(logo.shape[:2])
scale_logo = cv2.resize(logo, dsize=(w, round(w * ratio)))
scale_logo_h, scale_logo_w, _ = scale_logo.shape
# 方式1:循环
# for row in range(scale_logo_h):
# for col in range(scale_logo_w):
# face_img[y - scale_logo_h + row, x + col] = scale_logo[row, col]
# pass
# 方式2:切片
face_img[y - scale_logo_h:y, x:x + scale_logo_w] = scale_logo
def drawLogo2(self, face_rect, face_img):
"""
1. 找轮廓
- 原图:三通道彩色图
- 灰度图(0-255)
- 黑白二值图(0/255)
2. 绘制轮廓
- 绘制在背景是白色的图
:param face_rect:
:param face_img:
:return:
"""
# 参数1 被转换的图像
# 参数2 原图转为灰度图
logo_gray = cv2.cvtColor(self.logo, cv2.COLOR_BGR2GRAY)
# 转为二值图
# 参数1 灰度图
# 参数2 阈值 小于阈值为0
# 参数3 大于阈值为maxval
# 参数4 类型 cv2.THRESH_BINARY cv2.THRESH_OTSU 会自适应阈值
# retval, logo_binary = cv2.threshold(logo_gray, 100, 255, cv2.THRESH_BINARY)
retval, logo_binary = cv2.threshold(logo_gray, 100, 255, cv2.THRESH_OTSU)
# 查找轮廓
# 参数1 被查找的二值图
# 参数2 轮廓存放的层级关系
# 参数3 存放轮廓的方式 cv2.CHAIN_APPROX_SIMPLE 存放轮廓的拐角点
contours, hierarchy = cv2.findContours(logo_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 创建一个黑色的背景图
mask = np.zeros_like(self.logo)
cv2.drawContours(mask, contours, 1, color=(255, 255, 255), thickness=-1)
x, y, w, h = face_rect
logo = self.logo
ratio = min(logo.shape[:2]) / max(logo.shape[:2])
scale_logo = cv2.resize(logo, dsize=(w, round(w * ratio)))
scale_mask = cv2.resize(mask, dsize=(w, round(w * ratio)))
scale_logo_h, scale_logo_w, _ = scale_logo.shape
# 方式1:循环
# for row in range(scale_logo_h):
# for col in range(scale_logo_w):
# if np.all(scale_mask[row, col] == 255):
# face_img[y - scale_logo_h + row, x + col] = scale_logo[row, col]
# 方式2:切片
idx = scale_mask == 255
after_mask_logo = scale_logo[idx]
face_img[y - scale_logo_h:y, x:x + scale_logo_w][idx] = after_mask_logo
pass
if __name__ == '__main__':
face_img = cv2.imread('./lyf.png')
face_detect = FaceDetect()
# face_detect.capVideo()
face_detect.detect(face_img)
cv2.imshow('frame', face_img)
cv2.waitKey(0)
cv2.destroyAllWindows()