face.py 4.69 KB
import cv2
import os
import shutil

Img_dir = '../cacheUserImg'
Copy_dir = '../cacheUserImgCopy'
cv2.namedWindow("show", 0)
# 获取人脸识别训练数据
# face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_alt.xml')


def show(img, ms=0, reduce=3):
    """ 显示 """
    cv2.imshow('show', img)
    h, w = img.shape[:2]
    cv2.resizeWindow("show", w//reduce, h//reduce)
    cv2.waitKey(ms)


def rotate_img_bad(img, angle):
    """ 旋转 """
    # 原图的高、宽 以及通道数
    h, w = img.shape[:2]
    M = cv2.getRotationMatrix2D((w / 2, h / 2), angle, 1.0)
    rotated_img = cv2.warpAffine(img, M, (w, h))
    # show(rotated_img)
    cv2.imwrite(f'./test_{angle}.png', rotated_img)
    return rotated_img


def rotate_img(image, angle):
    # grab the dimensions of the image and then determine the
    # center
    (h, w) = image.shape[:2]
    (cX, cY) = (w // 2, h // 2)

    # grab the rotation matrix (applying the negative of the
    # angle to rotate clockwise), then grab the sine and cosine
    # (i.e., the rotation components of the matrix)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    # print(M, type(M))
    cos = abs(M[0, 0])
    sin = abs(M[0, 1])
    # print(f"cos {cos}, sin {sin}.\t h,w:{h},{w}\tangle:{angle} \t point:{cX},{cY}")

    # compute the new bounding dimensions of the image
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # adjust the rotation matrix to take into account translation
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # perform the actual rotation and return the image
    rotated_img = cv2.warpAffine(image, M, (nW, nH))
    # cv2.imwrite(f'./test_{angle}.png', rotated_img)
    return rotated_img


def check_face(img_gray, cascade):
    """ 检测人脸 """
    # 探测图片中的人脸
    faces = face_cascade.detectMultiScale(
        img_gray,
        scaleFactor=1.1,  # 每次缩减比例
        minNeighbors=5,  # 检测多次
        flags=cv2.CASCADE_SCALE_IMAGE,
        minSize=(100, 100)
    )

    print("检测到人脸区域:{}".format(faces))
    return faces


def mark_face(img, faces):
    """ 标记人脸 """
    print("mark face")
    iy, ix = img.shape[:2]
    for x, y, w, h in faces:
        # cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
        show(img, 100)

        # 裁剪图片
        print(ix, iy, x, y, w, h)
        length2 = min(ix, iy)
        
        length = int(w*2.5)
        length = min(length2, length)
        print(f"length: {length2} {length}")
        

        ow = length-w
        ow1 = ow//2
        oh = length-h
        oh1 = oh//2

        y1, y2 = y-oh1, y+h+oh1
        x1, x2 = x-ow1, x+w+ow1
        

        # 检测图片溢出
        print(y1, y2, x1, x2)
        if y1 < 0:
            print('裁剪:1 顶部溢出')
            y1 = 0
            y2 = length
        if y2 > iy:
            print('裁剪:2 底部溢出')
            y2 = iy
            y1 = iy-length
        if x1 < 0:
            print('裁剪:3 左侧溢出')
            x1 = 0
            x2 = length
        if x2 > ix:
            print('裁剪:4 右侧溢出')
            x2 = ix
            x1 = ix-length

        img2 = img[y1:y2, x1:x2]
        show(img2, 200)
        return img2


def run(img_name):
    # 读取图片,灰度转换
    img_bgr = cv2.imread(os.path.join(Img_dir, img_name))
    img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

    # 旋转图片
    find = False
    for angle in range(0, 360, 90):
        show(rotate_img(img_bgr, angle), 100)
        print(f"angle: {angle}")
        if angle > 0:
            img_bgr_r = rotate_img(img_bgr, angle)
            img_gray_r = rotate_img(img_gray, angle)
        else:
            img_bgr_r = img_bgr
            img_gray_r = img_gray

        faces = check_face(img_gray_r, face_cascade)

        if not isinstance(faces, tuple):
            print("find face")
            img_final = mark_face(img_bgr_r, faces)
            find = True
            break
            # show(img_bgr_r, 1000)
    print('end')
    if not find:
        print("未找到人脸,使用原图")
        img_final = img_bgr


    cv2.imwrite(os.path.join(Img_dir, img_name), img_final)
    


if __name__ == '__main__':
    file_list = os.listdir(Img_dir)
    for i in range(len(file_list)):
        file_name = file_list[i]
        print("处理图片{0}/{1}: {2}".format(i+1, len(file_list), file_name))
        if not os.path.exists(os.path.join(Copy_dir, file_name)):
            shutil.copy(f'{Img_dir}/{file_name}', f'{Copy_dir}/{file_name}')
        try:
            run(file_name)
        except Exception as _:
            pass

    cv2.destroyAllWindows()