基于OpenCV实现简单人脸面具、眼镜、胡须、鼻子特效(详细步骤 + 源码)

2022-04-06 20:47:53 浏览数 (1)

导读

本文给大家分享一个基于OpenCV实现简单人脸面具、眼镜、胡须、鼻子特效的实例,并附实现步骤和源码。

背景介绍

OpenCV传统人脸检测是使用Haar特征的级联分类器实现的。Harr级联是一个基于Haar特征的级联分类器。级联分类器是什么?它是一个把弱分类器串联成强分类器的过程。弱分类器和强分类器分别是什么呢?弱分类器是性能受限的分类器,它们没法正确地区分所有事物。如果你的问题很简单,它的输出结果会在一个可以接受的范围内。强分类器可以正确地对数据进行分类。下图展示了它们是如何组合在一起的。Haar级联的另一个重要部分是Haar特征,这些特征简单地总结了不同的长方形区域的区别,如下图所示:

计算ABCD区域的Haar特征,只需要计算这个区域白色像素和有色像素的区别。在上面四张图表中使用了不同的图案创建Haar 特征,同时其他图案也被使用了。这些图案使用了多重尺度法以确保系统的拉伸是不变的。多重尺度法指把图像缩小再次计算同样的特征。这样可以在给出对象大小有差异的时候候,获得一个可靠的结果。

OpenCV安装目录中提供了多个已经训练好的Haar分类器模型文件,包含:人脸检测、人眼检测、鼻子检测和身体检测等,如下图所示:

比如使用haarcascade_frontalface_alt.xml,我们可以很快实现一个人脸检测功能:

代码语言:javascript复制
import sys
import numpy as np
import cv2

#加载xml分类器文件
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')

font = cv2.FONT_HERSHEY_SIMPLEX

def face_detect(img):
  strText=""
  cv2.imshow('原图', img)
  gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转为灰度图
  #gray = cv2.equalizeHist(gray)#直方图均衡化

  #人脸检测
  faces = face_cascade.detectMultiScale(gray,1.1,2,0|cv2.CASCADE_SCALE_IMAGE,(30,30))#OpenCV3.x
  
  for (x,y,w,h) in faces: #遍历检测结果
    cv2.rectangle(img,(x,y),(x w,y h),(0,255,0),2)#框出人脸区域
    #cv2.circle(img,(int(x w/2),int(y h/2)),int(w/2),(0,255,0),3)

  face_num = len(faces) 
  if face_num==0:
    print ("There is no face!")
    strText="There is no face!"
  elif face_num==1:
    print ("There is 1 face!")
    strText="There is 1 face!"
  else:
    print ("There are %s faces!"�ce_num)
    strText="There are %s faces!"�ce_num
  cv2.putText(img, strText, (20,30), font, 1, (0,0,255), 2)
   
  cv2.imshow('结果图',img)
  print ('Finished')
  cv2.waitKey(0)
  cv2.destroyAllWindows()

if __name__ == '__main__':
  img = cv2.imread('./pics/5.jpg')
  face_detect(img)

实现步骤

【1】准备面具图片并处理成透明背景

【2】人脸检测并确定人脸ROI

【3】将面具图片缩放到人脸ROI大小,并对Alpha通道阈值提取分离面具部分

代码语言:javascript复制
Mat faceMask = imread("./mask/mask2.png", -1);
if (faceMask.empty())
{
  cerr << "Error loading mask image. Exiting!" << endl;
  return -1;
}
Mat alpha, channels[4];
split(faceMask, channels);
alpha = channels[3];
threshold(alpha, alpha, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("thresMask", alpha);
cout << alpha.channels() << endl;
vector<Mat>bgrImg;
bgrImg.push_back(channels[0]);
bgrImg.push_back(channels[1]);
bgrImg.push_back(channels[2]);
merge(bgrImg, faceMask);
waitKey();

【4】用Mat的copyTo方法将面具贴到人脸部分

代码语言:javascript复制
faceMaskResized.copyTo(faceROI, grayMaskResized)

【5】扩展到眼镜、胡须和鼻子特效:

haarcascade_frontalface_alt.xml---人脸检测

haarcascade_smile.xml---嘴唇检测

haarcascade_mcs_nose.xml---鼻子检测

haarcascade_eye.xml---眼睛检测

实现效果:

0 人点赞