OpenCV笔记4:级联分类器实现嘴部检测

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

人脸原图

lyf.png

嘴部检测效果图

image.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饭碗、碗碗香

感谢壮士的慷概解囊!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值