如何使用openCV和HAAR级联来模糊人脸?

10

我想知道是否有一种方法可以模糊由haarcascade人脸分类器自动识别出的脸部。

使用下面的代码,我能够检测到脸部,剪裁围绕这个脸的图像或在其上绘制一个矩形。

image = cv2.imread(imagepath)

# Specify the trained cascade classifier
face_cascade_name = "./haarcascade_frontalface_alt.xml"

# Create a cascade classifier
face_cascade = cv2.CascadeClassifier()

# Load the specified classifier
face_cascade.load(face_cascade_name)

#Preprocess the image
grayimg = cv2.cvtColor(image, cv2.cv.CV_BGR2GRAY)
grayimg = cv2.equalizeHist(grayimg)

#Run the classifiers
faces = face_cascade.detectMultiScale(grayimg, 1.1, 2, 0|cv2.cv.CV_HAAR_SCALE_IMAGE, (30, 30))

print "Faces detected"

if len(faces) != 0:            # If there are faces in the images
    for f in faces:         # For each face in the image

        # Get the origin co-ordinates and the length and width till where the face extends
        x, y, w, h = [ v for v in f ]

        # Draw rectangles around all the faces
        cv2.rectangle(image, (x,y), (x+w,y+h), (255,255,255))
        sub_face = image[y:y+h, x:x+w]
        for i in xrange(1,31,2):
            cv2.blur(sub_face, (i,i))
        face_file_name = "./face_" + str(y) + ".jpg"
        cv2.imwrite(face_file_name, sub_face)

但我希望模糊人们的面部,以便他们无法被识别。

你有什么想法如何实现吗?

感谢您的帮助。

Arnaud


1
使用其中一个函数,并传入包含人脸的图像子区域。请参考这里 - Hammer
嗨,Hammer,我考虑过这个问题,但我不知道如何只模糊检测到人脸的部分图像。谢谢。 - Arnaud Geotribu
我终于成功做到了我想要的事情。 为了做到这一点,我按照你建议的方法应用了高斯模糊: sub_face = cv2.GaussianBlur(sub_face,(23, 23), 30)然后我将这个模糊图像与一个新图像重叠: result_image[y:y+sub_face.shape[0], x:x+sub_face.shape[1]] = sub_face - Arnaud Geotribu
抱歉,我应该更明确一些。很高兴你解决了它 :) - Hammer
@ArnaudGeotribu,请将您的解决方案放入答案并接受它,以便寻找相同问题的人可以使用它。 - w-m
3个回答

20

我终于成功做到了我想要的事情。像Hammer建议的那样,应用高斯模糊。 代码如下:

image = cv2.imread(imagepath)
result_image = image.copy()

# Specify the trained cascade classifier
face_cascade_name = "./haarcascade_frontalface_alt.xml"

# Create a cascade classifier
face_cascade = cv2.CascadeClassifier()

# Load the specified classifier
face_cascade.load(face_cascade_name)

#Preprocess the image
grayimg = cv2.cvtColor(image, cv2.cv.CV_BGR2GRAY)
grayimg = cv2.equalizeHist(grayimg)

#Run the classifiers
faces = face_cascade.detectMultiScale(grayimg, 1.1, 2, 0|cv2.cv.CV_HAAR_SCALE_IMAGE, (30, 30))

print "Faces detected"

if len(faces) != 0:         # If there are faces in the images
    for f in faces:         # For each face in the image

        # Get the origin co-ordinates and the length and width till where the face extends
        x, y, w, h = [ v for v in f ]

        # get the rectangle img around all the faces
        cv2.rectangle(image, (x,y), (x+w,y+h), (255,255,0), 5)
        sub_face = image[y:y+h, x:x+w]
        # apply a gaussian blur on this new recangle image
        sub_face = cv2.GaussianBlur(sub_face,(23, 23), 30)
        # merge this blurry rectangle to our final image
        result_image[y:y+sub_face.shape[0], x:x+sub_face.shape[1]] = sub_face
        face_file_name = "./face_" + str(y) + ".jpg"
        cv2.imwrite(face_file_name, sub_face)

# cv2.imshow("Detected face", result_image)
cv2.imwrite("./result.png", result_image)

Arnaud

->

Arnaud


你不需要 if len(faces) != 0,因为for循环不会遍历一个空列表。也就是说,在每个for循环的顶部实际上有一个内置的if语句。 - Kurt
1
x,y,w,h = f 更符合 Python 风格。 - Kurt
嗨,Arnaud,我遇到了一个错误,你能帮忙吗?谢谢。顺便说一句,cv2.cv.CV_BGR2GRAY 应该替换为 cv2.COLOR_BGR2HSV。 - ah bon

11
你的整个代码末尾可以被以下内容替换:
img[startX:endX, startY:endY] = cv2.blur(img[startX:endX, startY:endY], (23, 23))

改为:

    # Get the origin co-ordinates and the length and width till where the face extends
    x, y, w, h = [ v for v in f ]

    # get the rectangle img around all the faces
    cv2.rectangle(image, (x,y), (x+w,y+h), (255,255,0), 5)
    sub_face = image[y:y+h, x:x+w]
    # apply a gaussian blur on this new recangle image
    sub_face = cv2.GaussianBlur(sub_face,(23, 23), 30)
    # merge this blurry rectangle to our final image
    result_image[y:y+sub_face.shape[0], x:x+sub_face.shape[1]] = sub_face

特别是因为您没有要求圆形遮罩,对我来说更容易阅读。

PS:抱歉没有评论,声望不够。即使帖子已经有5年了,我认为这可能仍然有价值,因为我找到了与此特定问题相关的信息...


0
注意:神经网络(例如Resnet)现在比HAAR级联更准确地检测面部,它们也已经集成在OpenCV中。这可能比使用此问题中提到的解决方案更好。
然而,模糊/像素化面部的代码仍然适用。

您还可以通过添加包含面部区域中区域RGB值平均值的正方形来对面部区域进行像素化处理。

执行此操作的函数可能如下所示:

def pixelate_image(image: np.ndarray, nb_blocks=5, in_place=False) -> np.ndarray:
    """Return a pixelated version of a picture (need to be fed with a face to pixelate)"""
    # To pixelate, we will split into a given number of blocks
    # For each block, we will compute the average of RGB values of the block
    # And then we can just replace with a rectangle of this color
    # divide the input image into NxN blocks
    if not in_place:
        image = np.copy(image)
    h, w = image.shape[:2]
    blocks = tuple(
        np.linspace(0, d, nb_blocks + 1, dtype="int") for d in (w, h)
    )

    for i, j in product(*[range(1, len(s)) for s in blocks]):
        # compute the starting and ending (x, y)-coordinates
        # for the current block
        start = blocks[0][i - 1], blocks[1][j - 1]
        end = blocks[0][i], blocks[1][j]
        # extract the ROI using NumPy array slicing, compute the
        # mean of the ROI, and then draw a rectangle with the
        # mean RGB values over the ROI in the original image
        roi = image[start[1]:end[1], start[0]:end[0]]
        bgr = [int(x) for x in cv2.mean(roi)[:3]]
        cv2.rectangle(image, start, end, bgr, -1)

    return image

然后你只需要在函数中像这样使用它(更新为Python 3,使用pathlib和类型提示):

from pathlib import Path
from typing import Union

import cv2
import numpy as np

PathLike = Union[Path, str]

face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")

def pixelate_faces_haar(img_path: PathLike, dest: Path):
    """Pixelate faces of people with OpenCV and save to a destination file"""
    img = cv2.imread(str(img_path))
    # To use cascade, we need to use Grayscale images
    # We can then detect faces
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.1, 4)

    for (x, y, width, height) in faces:
        roi = img[y:y+height, x:x+width]
        pixelate_image(roi, 15, in_place=True)

    dest.parent.mkdir(parents=True, exist_ok=True)
    cv2.imwrite(str(dest), img)
    print(f"Saved pixelated version of {img_path} to {dest}")```

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接