Always keep a |

园龄:粉丝:关注:

2024-03-24 21:40阅读: 27评论: 0推荐: 0

人脸识别学习

基于人脸识别及反作弊技术的在线评测系统

基于Detect and recognize the faces from camera / 调用摄像头进行人脸识别,支持多张人脸同时识别的学习

opencv调用摄像头

Python调用摄像头是通过调用摄像头设备来实现的。具体来说,可以使用Python的OpenCV库来打开摄像头设备,并使用摄像头进行图像捕捉和处理。

Python调用摄像头示例代码

import cv2

# 打开摄像头设备
# 0 表示默认摄像头
cap = cv2.VideoCapture(0)
# 用cap读取视频文件
# cap = cv2.VideoCapture(path)
# path为想要捕获的视频文件路径

while True:
    # 读取摄像头图像
    # cap.read()方法中的ret表示是否成功读取图像,frame表示读取到的图像
    # 如果读取成功,ret为True,frame为图像数据
    # 如果读取失败,ret为False,frame为None
    ret, frame = cap.read()
    
    # 在图像上显示图像
    if ret == True:
        cv2.imshow('Camera', frame)
    else:
        print("Error [reason: frame read failed]")


    # 按下q键退出循环
    # waitkey()方法用于等待用户按下键盘按键
    # 1表示等待1毫秒,如果用户没有按下按键,则继续等待
    # ord()方法用于获取按键的ASCII码值
    # ord('q')表示按下q键
    # 0xFF表示按下键盘上的任意键
    if cv2.waitKey(1) == ord('q'):
        break       
    
# 释放摄像头设备
cap.release()

# 关闭图像窗口
cv2.destroyAllWindows()

Dlib库人脸检测

Dlib是一个用于机器学习、图像处理和模式识别的开源C++库。它包含机器学习、图像处理和模式识别的算法,并且可以与Python、Ruby、Matlab和Java等语言进行交互。

Dlib库人脸检测

Dlib库调用摄像头是通过调用Dlib库中的相关函数来实现的。具体来说,可以使用Dlib库中的函数来打开摄像头设备,并使用摄像头进行图像捕捉和处理。

Dlib库调用摄像头示例代码

import dlib
import cv2

# 创建一个detector对象,用于人脸检测 
# 正面的人脸检测器 
detector = dlib.get_frontal_face_detector()

# 打开摄像头设备
cap = cv2.VideoCapture(0)

while True:
    # 读取摄像头图像    
    ret, frame = cap.read()

    # 将图像转换为灰度图像
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)   
    # 问题一:为什么需要将图像转换为灰度图像?

    # 使用detector对象进行人脸检测
    faces = detector(gray)

    # 在图像上绘制人脸矩形框
    for face in faces:  
        x, y, w, h = face.left(), face.top(), face.width(), face.height()  
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

    # 在图像上显示图像
    cv2.imshow('Camera', frame)
    
    # 按下q键退出循环
    if cv2.waitKey(1) == ord('q'):
        break
    
# 释放摄像头设备
cap.release()   

# 关闭图像窗口
cv2.destroyAllWindows()                         

为什么需要将图像转换为灰度图像?

gpt给出的解释:

  1. 简化计算:灰度图像只有一个通道(亮度),而彩色图像通常有三个通道(红、绿、蓝)。处理单个通道的图像比处理三个通道的图像要快得多,并且需要的内存也更少。
  2. 减少噪声:彩色图像中的颜色信息有时会引入额外的噪声,这些噪声对于某些类型的图像分析(如边缘检测、形态学操作等)是不必要的。转换为灰度图像可以减少这些噪声的影响。
  3. 统一处理:对于一些算法来说,颜色信息并不是关键因素,或者在不同的光照和颜色条件下需要一致的处理结果。灰度图像可以消除颜色变化带来的影响,使得算法更加鲁棒。
  4. 历史原因:早期的图像处理算法和硬件大多只能处理灰度图像,因此很多传统方法和理论都是基于灰度图像开发的。
  5. 特定应用需求:有些应用领域,如某些类型的生物特征识别(指纹识别)、文档分析等,主要关注图像的纹理和形状信息,这些信息在灰度图像中更容易提取。

暂不关心4、5两条

[1. 简化计算]:黑白图像只需要关心像素的明亮程度

需要知道:

  1. 图像以数字矩阵的形式存储在计算机中,其中这些数字称为像素值。
  2. 这些像素值代表每个像素的强度。
  3. 0代表黑色,255代表白色。
  4. 数字矩阵称为通道,对于灰度图像,我们只有一个通道。

那么彩色图片是如何在计算机中存储的呢?

  • 图像由许多颜色组成,几乎所有颜色都可以从三种原色(红色,绿色和蓝色)生成。我们可以说每个彩色图像都是由这三种颜色或3个通道(红色,绿色和蓝色)。

所以使用三个数字矩阵分别从红、绿、蓝记录图片的像素值
对于一个N×M的彩色图像,需要存储N×M×3个数字矩阵

总结:黑白图像只有一个通道,而彩色图像有三个通道。灰度图处理起来快很多。

将一张彩色图片,处理为三张不同的色度图:

from PIL import Image

# 打开图像文件

images = []
for i in range(3):
    # 为什么要加载3次图片
    # Image.open返回的是对该图片的引用
    imagecsp = Image.open(r"learn\pic\1.jpg")
    images.append(imagecsp)
    # 对imagecsp为什么不会被销毁的思考
    # 因为新建出来的imagecsp的引用被append到images中,实际上,images依然存在对该内存空间的引用,“局部变量”不会被销毁
    # 循环结束,该地址空间依然存在
    # 感觉还是有点问题???
image= Image.open(r"learn\pic\1.jpg")
# 检查图像是否正确打开
if image is None:
    print("图像加载失败")
    exit()

# 获取图像的宽度、高度和通道数
width, height, channels = image.size[0], image.size[1], image.mode

# 遍历图像的每个像素
for y in range(height):
    for x in range(width):
        # 获取像素值
        blue, green, red = image.getpixel((x, y))
        rgb = [(red, 0, 0), (0, green, 0), (0, 0, blue)]
        csp=0
        for i in range(3):
            images[i].putpixel((x, y), rgb[i])
for i in range(3):
    name = "learn/pic/" + str(i) + "x.jpg"
    print("picture has been saved to " + name)
    images[i].save(name)

用c++写了个相似逻辑的东西,没搞明白

学艺不精

搞不懂了

#include <bits/stdc++.h>

using namespace std;

int main() {
    stringstream ss;
    string address_str;
    if (1 == 1) {
        int x = 10;
        cout << (&x) << " " << x << '\n';
        ss << (&x);
        address_str = ss.str();
    }

    // 将字符串转换为uintptr_t类型
    uintptr_t address;
    char* end; // 用于strtoull的指针
    address = strtoull(address_str.c_str(), &end, 16); // 将字符串转换为无符号长整型

    // 将uintptr_t类型转换为int*指针
    int* addr = reinterpret_cast<int*>(address);

    // 现在 addr 指向了 address_str 所表示的地址
    // 注意:这里我们没有检查 addr 是否指向有效的内存区域
    // 在实际应用中,你需要确保 addr 指向的内存是有效的,并且你有权访问

    // 示例:假设我们知道该地址指向了一个int类型的变量
    // int value = *addr; // 这行代码可能会访问非法内存,导致程序崩溃

    // 输出转换后的地址
    std::cout << addr << " " << *addr << std::endl;
}

[2. 减少噪声]: 在图像处理中,噪声是指图像中不希望出现的随机变化,它可能是由于图像采集、传输或处理过程中的多种原因造成的。

opencv调用摄像头,并将捕获的图片存储到指定路径

实现功能如下:

  1. 按下“n”新建用户文件夹,用来存储人脸图片
  2. 按下“s”捕获人脸图片,并存储到指定路径
  3. 按下“o”框出人脸
  4. 按下“q”退出程序

实现代码:

import dlib
import cv2
import logging
import os

path="learn/"
class FaceDetector():
    def __init__(self):
        self.detector = dlib.get_frontal_face_detector() # 创建一个detector对象,用于人脸检测     
        self.person_num = 0                              # 已录入的人脸数量
        self.person_numX_id = 0                          # 当录入x的人脸时,对录入图片数量进行标记
        self.save_path = path+"pic/"                     # 图片保存路径
        self.person_numX_dir = ""                        # 用于保存当前录入的人脸图片
        self.face_retangle_status = False                # 用于标记是否显示人脸框 默认关闭
        self.face_register_status = False                # 用于标记是否进行人脸录入 默认关闭
    
    # 新建用户文件夹
    def person_num_addX_dir(self):
        self.person_num += 1
        self.person_numX_id = 0
        print("录入第{}个人脸".format(self.person_num))
        # 新建一个以person_num命名的文件夹,用于保存该人的图片
        if not os.path.exists(self.save_path  + "P"+str(self.person_num)):
            os.makedirs(self.save_path + "P"+str(self.person_num))
        self.person_numX_dir = self.save_path + "P"+str(self.person_num)
        print("新的文件夹路径为:{}".format(self.person_numX_dir))
        self.face_register_status = True
    
    # 录入人脸图片
    def person_num_addX_pic(self, frame):
        if os.path.exists(self.person_numX_dir):
            self.person_numX_id += 1
            # 保存图片
            cv2.imwrite(self.person_numX_dir + "/P"+str(self.person_num)+"_"+str(self.person_numX_id)+".jpg", frame)
            print("已保存第{}张图片".format(self.person_numX_id))
        else:
            print("文件夹不存在,请先创建文件夹")
    
    # 检测已存在的person数量
    def check_exiting_person_num(self):
        if os.listdir(self.save_path):
            personlist = os.listdir(self.save_path)             # personlist为所有已录入的人脸文件夹名
            personlist_num = []
            for person in personlist:
                personlist_num.append(int(person.split('P')[-1]))
            self.person_num = max(personlist_num)               # 最大的人数编号
        else:
            self.person_num = 0

    # 在图像上绘制人脸矩形框
    def draw_rectangle(self, frame, faces):
        for face in faces:  
            x, y, w, h = face.left(), face.top(), face.width(), face.height()  
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            
    def FaceDetector(self):
        # 打开摄像头设备
        cap = cv2.VideoCapture(0)
        self.check_exiting_person_num()
        while True:
            key_press = cv2.waitKey(1)
            if ord('A') <= key_press <= ord('Z'):
                key_press = key_press + 32
            # 读取摄像头图像    
            ret, frame = cap.read()

            # 当按下q键时,退出程序
            if key_press == ord('q') :
                break

            # 当按下n键时,新建一个文件夹用来存储人脸图片
            if key_press == ord('n') :
                self.person_num_addX_dir()

            # 当按下s键时,保存图像到指定路径
            if key_press == ord('s') :
                if self.face_register_status == False:
                    print("请先新建用户")
                else:
                    self.person_num_addX_pic(frame)

            # 按下o键,显示人脸框图
            if key_press == ord('o') :
                self.face_retangle_status =  self.face_retangle_status ^ True

            if self.face_retangle_status == True:
                # 将图像转换为灰度图像
                gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  
                # 使用detector对象进行人脸检测
                faces = self.detector(gray)
                self.draw_rectangle(frame, faces)
            
            # 在图像上显示图像
            if ret == True:
                cv2.imshow('Camera', frame)
            else:
                print("无法从摄像头读取图像")
            
        # 释放摄像头设备
        cap.release()   
        # 关闭图像窗口
        cv2.destroyAllWindows()    

def main():
    logging.basicConfig(level=logging.INFO)
    FaceDetector_cur = FaceDetector()
    FaceDetector_cur.FaceDetector()

if __name__ == '__main__':
    main()

图片处理

dlib库68特征点标记

# this file is to test the dlib face detection and landmarking

import cv2
import dlib
import logging


path="learn/dlib/"
class FaceMarker:
    def __init__(self):
        self.detector = dlib.get_frontal_face_detector() # dlib face detector                   # 默认人脸检测器,正向裁剪人脸图像
        self.predictor = dlib.shape_predictor(path+"shape_predictor_68_face_landmarks.dat")     # dlib人脸landmark关键点检测器

    def get_landmarks(self, image):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        rects = self.detector(gray, 1) 
        # 检测人脸
        for (i, rect) in enumerate(rects):
            shape = self.predictor(gray, rect)
            # 检测关键点
            for i in range(68):
                cv2.circle(image, (shape.part(i).x, shape.part(i).y), 2, (0, 255, 0), -1)
                # 画出关键点
        return image

    def run(self):
        cap = cv2.VideoCapture(0)
        while True:
            ret, frame = cap.read()
            if ret == False:
                print("无法打开摄像头")
                break
            


def Main():
    logging.basicConfig(level=logging.INFO)
    FaceMarker = FaceMarker()
    FaceMarker.run()

if __name__ == '__main__':
    Main()

提取特征128维的特征值

import dlib
import os
import logging
import csv
import numpy as np
import cv2

class Face_feature:
    def __init__(self):
        self.detector = dlib.get_frontal_face_detector() # 正向人脸检测器
        self.predictor = dlib.shape_predictor("learn/dlib/shape_predictor_68_face_landmarks.dat") # 68个特征点检测器
        self.face_reco_model = dlib.face_recognition_model_v1("learn/dlib/dlib_face_recognition_resnet_model_v1.dat") # 128D特征提取器
        self.path_features_csv = "learn/data/" # 将csv文件也放入这个文件夹下
        self.path_img_floder = "learn/data/pic/" # 图片文件夹
    
    # 计算单张的图像的128D特征
    def return_128D_feature_single(self, path_picture_personX):
        img = cv2.imread(path_picture_personX)
        # 检测人脸
        faces = self.detector(img)
        logging.info("检测到人脸图片{0:40}".format(path_picture_personX))

        # 用检测到人脸的原图片去计算128D特征
        if len(faces):
            # 获得人脸特征点
            shape = self.predictor(img, faces[0])
            # 获得人脸128D特征
            face_descriptor = self.face_reco_model.compute_face_descriptor(img, shape)
        else:
            face_descriptor = 0
            logging.warning("录入失败,未检测到人脸")
        return  face_descriptor
    # def tansform_pic_to_csv(self):
    # 获得person的128D特征 - 平均特征
    def return_128D_features_ave(self, path_personX):
        features_128D_Of_PersonX = []
        faces = os.listdir(path_personX)
        if faces:
            for face in faces:
                logging.info("正在读取{0:40}下的图片:{1:20}".format(path_personX, face))
                # 计算该图片的128D特征
                face_feature_128D = self.return_128D_feature_single(path_personX+"/"+face)
                # 跳过识别失败的图片
                if face_feature_128D == 0:
                    continue
                else:
                    features_128D_Of_PersonX.append(face_feature_128D)

        else:
            logging.warning("文件夹{0:40}为空".format(path_personX))
        
        if features_128D_Of_PersonX:
            features_128D_Of_PersonX_ave = np.array(features_128D_Of_PersonX, dtype=object).mean(axis=0)
        else:
            features_128D_Of_PersonX_ave = np.zeros(128, dtype=object, order='C')
        return features_128D_Of_PersonX_ave

        
    def process(self):
        self.__init__()
        
        # 获取已录入的最后一个人脸序号
        person_list = os.listdir(self.path_img_floder)
        person_list.sort()

        with open(self.path_features_csv+"features_all.csv", "w", newline="") as csvfile:
            writer = csv.writer(csvfile)
            for person in person_list:
                logging.info("正在处理{0:40}{1:20}".format(self.path_img_floder, person))
                features_128D_Of_PersonX = self.return_128D_features_ave(self.path_img_floder+person)
                #获得person的128D特征
                features_128D_Of_PersonX = np.insert(features_128D_Of_PersonX, 0, person, axis=0)
                writer.writerow(features_128D_Of_PersonX)
                logging.info("{0:40}{1:20}处理完毕".format(self.path_img_floder, person))
            logging.info("全部处理完毕, 全部人脸数据存入{0:40}".format(self.path_img_floder+"features_all.csv"))


def main():
    logging.basicConfig(level=logging.INFO)
    face_feature = Face_feature()
    face_feature.process()

if __name__ ==  '__main__':
    main()

参考文献

图像如何存储在计算机中?

本文作者:rufu

本文链接:https://www.cnblogs.com/rufu/p/18093124

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   迷糊的Rufu  阅读(27)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起