OpenCV 头像训练与识别

识别效果图

依赖安装 opencv-python opencv-contrib-python tensorflow Pillow numpy 

pip3 install opencv-python==4.5.1.48 -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
pip3 install opencv-contrib-python==4.5.1.48  -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
pip3 install tensorflow==2.4.1  -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000
pip3 install -U pillow==8.1.2
pip3 install numpy==1.19.4  -i https://pypi.tuna.tsinghua.edu.cn/simple --default-timeout=10000

头像目标锁定资源文件 haarcascade_frontalface_default.xml  如果觉得慢,可以从 csdn 资源中下载 

项目结构

采集数据 collection.py  采集完成之后可以通过肉眼删除误差较大的数据

# 头像数据采集
import cv2 as cv
import uuid

# 数据集收集
def split_image(frame, set_path):
    # 图片转灰度
    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    # 加载人脸分类识别器
    face_detector = cv.CascadeClassifier(r'../data/haarcascade_frontalface_default.xml')
    faces = face_detector.detectMultiScale(frame_gray)
    for x, y, w, h in faces:
        # 头像标注
        # cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
        # 头像切割保存,分类型保存 frame_gray 为灰度图片 frame 为原始图片,选择灰度图片作为训练集
        cv.imwrite(set_path + str(uuid.uuid1()) + '.jpg', frame_gray[y:y + h, x:x + w])

if __name__ == '__main__':

    # 数据保存路径,不能有中文
    set_path = "C:/Users/Administrator/Desktop/data"
    label = 0  # 当前数据的标签
    stream_address = "../data/one.mp4"  # 读取视频文件
    # stream_address = 0;//获取摄像头
    stream = cv.VideoCapture(stream_address)  # 转化为流
    set_path = set_path + "/" + label
    while True:
        status, frame = stream.read()  # 读取帧图片数据
        if status:
            print("获取到图片数据,规格为:", frame.shape)
        else:
            print('没有检查到图像数据')
            break
        split_image(frame, set_path)  # 截取头部数据信息
    cv.destroyAllWindows()
    stream.release()

训练模型 train.py

# 训练模型
import numpy as np
from PIL import Image
import cv2 as cv
import os


# 加载训练数据
def get_train_data(data_path, image_width, image_high):
    train_data_array = []  # 训练集,灰度图片
    label_array = []  # 标签 必须是整数,数值型从0开始包括0,后续识别可以通过标签索引获取数组字典,数组从0开始
    listdir = os.listdir(data_path)
    for label in listdir:
        label_path = data_path + "/" + label
        files = os.listdir(label_path)
        for file_name in files:
            file_path = label_path + "/" + file_name
            img_numpy = np.array(Image.open(file_path).convert('L'), 'uint8')
            img_format = cv.resize(img_numpy, (image_width, image_high), interpolation=cv.INTER_CUBIC)  # 图片大小格式化
            train_data_array.append(img_format)
            label_array.append(int(label))
    return label_array, train_data_array


# 训练模型
def training():
    print("人脸训练中 ...")
    data_path = "C:/Users/Administrator/Desktop/data"  # 训练数据路径
    label_array, train_data_array = get_train_data(data_path, 128, 128) # 指定图片格式化大小
    # 创建LBPH识别器并开始训练,当然也可以选择Eigen或者Fisher识别器
    recognizer = cv.face.LBPHFaceRecognizer_create()
    # 传入训练集与标签
    recognizer.train(train_data_array, np.array(label_array))
    # 保存训练信息
    recognizer.write('../model/trainer.yml')
    print("{0} 训练分类数为2,已完成".format(len(np.unique(label_array))))


if __name__ == '__main__':
    training()

视频识别 distinguish.py

# 识别
import cv2 as cv


def distinguish():
    # 加载算法 创建LBPH识别器并开始识别,当然也可以选择Eigen或者Fisher识别器
    recognizer = cv.face.LBPHFaceRecognizer_create()
    # 加载模型
    recognizer.read('../model/trainer.yml')
    face_detector = cv.CascadeClassifier(r"../data/haarcascade_frontalface_default.xml")
    font = cv.FONT_HERSHEY_SIMPLEX
    # 特征值对应的姓名映射
    names = ['one', 'two']
    cap = cv.VideoCapture("../data/one.mp4")  # 加载视频文件数据
    # cap = cv.VideoCapture(0) # 加载摄像头数据
    while True:
        status, frame = cap.read()
        if status:
            print("获取到图片数据,规格为:", frame.shape)
        else:
            print('没有检查到图像数据')
            break
        # 图片转灰度
        frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        faces = face_detector.detectMultiScale(frame_gray)
        for x, y, w, h in faces:
            cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
            # 识别
            feature_id, value = recognizer.predict(frame_gray[y:y + h, x:x + w])
            print("当前识别分类为", feature_id, "得分为", value)
            if value > 100:
                feature_id = "unknown"
                reliability = "100%"
            else:
                feature_id = names[feature_id]  # 将识别的结果特征数值映射成姓名
                reliability = "{0}%".format(round(100 - value, 2))
            cv.putText(frame, str(feature_id), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
            cv.putText(frame, str(reliability), (x + 5, y + h - 5), font, 1, (0, 255, 0), 1)
        cv.imshow("distinguish", frame)
        if ord('q') == cv.waitKey(10):
            break
    cv.destroyAllWindows()
    cap.release()


if __name__ == '__main__':
    distinguish()

采集头像数据示例

训练完之后会在<project_home>mian/model目录下生成训练文件

校验模型的准确度 check.py

# 模型校验
import cv2 as cv
import os


# 数据结构
class CheckResult:
    accuracy = 0  # 正确数
    error = 0  # 正确数
    unknown = 0  # 未知数
    total = 0  # 总数
    accuracy_list = []  # 正确详细数据
    error_list = []  # 错误详细数据
    unknown_list = []  # 未知详细数据
    accuracy_rate = None  # 正确率
    error_rate = None  # 错误率
    unknown_rate = None  # 未知率
    accuracy_reliability = 0  # 正确平均可信度
    error_reliability = 0  # 错误平均可信度

    def msg(self):
        return "正确识别数:{0},正确率:{1},错误识别数:{2},错误率:{3},未知识别数:{4},未知率:{5},正确可信度:{6},错误可信度:{7}".format(
            self.accuracy,
            self.accuracy_rate,
            self.error,
            self.error_rate, self.unknown,
            self.unknown_rate,
            self.accuracy_reliability,
            self.error_reliability
        )


# 加载校验数据
def get_test_data(data_path):
    # 加载算法 创建LBPH识别器并开始校验,当然也可以选择Eigen或者Fisher识别器
    recognizer = cv.face.LBPHFaceRecognizer_create() 
    # 加载模型
    recognizer.read('../model/trainer.yml')
    face_detector = cv.CascadeClassifier(r"../data/haarcascade_frontalface_default.xml")
    test_data_array = []  # 校验集
    listdir = os.listdir(data_path)
    for label in listdir:
        label_path = data_path + "/" + label
        files = os.listdir(label_path)
        for file_name in files:
            file_path = label_path + "/" + file_name
            frame = cv.imread(file_path, 3)
            # 图片转灰度
            frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
            faces = face_detector.detectMultiScale(frame_gray)
            for x, y, w, h in faces:
                cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=1)
                # 识别
                feature_id, value = recognizer.predict(frame_gray[y:y + h, x:x + w])
                if value > 100:
                    feature_id = "unknown"
                    reliability = 1
                else:
                    reliability = 100 - value
                test_data_array.append(
                    {"path": file_path, "feature": feature_id, "reliability": reliability, "label": int(label)})
    return test_data_array


# 校验模型
def calc_result(test_data_array):
    result = CheckResult()

    for x in test_data_array:
        if x["feature"] == x["label"]:
            result.accuracy += 1
            result.accuracy_list.append(x)
            result.accuracy_reliability += x["reliability"]
        elif x["feature"] == 'unknown':
            result.unknown += 1
            result.unknown_list.append(x)
        else:
            result.error += 1
            result.error_list.append(x)
            result.error_reliability += x["reliability"]
    result.total = len(test_data_array)
    if result.total == 0:
        result.accuracy_rate = "0.00%"
        result.error_rate = "0.00%"
        result.unknown_rate = "0.00%"
    else:
        result.accuracy_rate = str(round(result.accuracy * 100 / result.total, 2)) + "%"
        result.error_rate = str(round(result.error * 100 / result.total, 2)) + "%"
        result.unknown_rate = str(round(result.unknown * 100 / result.total, 2)) + "%"
        result.accuracy_reliability = str(round(result.accuracy_reliability / result.total, 2)) + "%"
        result.error_reliability = str(round(result.error_reliability / result.total, 2)) + "%"
    return result


def checking():
    print("模型校验中 ...")
    data_path = "C:/Users/Administrator/Desktop/data"  # 校验数据路径
    test_data_array = get_test_data(data_path)
    result = calc_result(test_data_array)
    print(result.msg())


# 校验模型准确度
if __name__ == '__main__':
    checking()

校验结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小钻风巡山

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值