人脸识别学习
基于人脸识别及反作弊技术的在线评测系统
基于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给出的解释:
- 简化计算:灰度图像只有一个通道(亮度),而彩色图像通常有三个通道(红、绿、蓝)。处理单个通道的图像比处理三个通道的图像要快得多,并且需要的内存也更少。
- 减少噪声:彩色图像中的颜色信息有时会引入额外的噪声,这些噪声对于某些类型的图像分析(如边缘检测、形态学操作等)是不必要的。转换为灰度图像可以减少这些噪声的影响。
- 统一处理:对于一些算法来说,颜色信息并不是关键因素,或者在不同的光照和颜色条件下需要一致的处理结果。灰度图像可以消除颜色变化带来的影响,使得算法更加鲁棒。
- 历史原因:早期的图像处理算法和硬件大多只能处理灰度图像,因此很多传统方法和理论都是基于灰度图像开发的。
- 特定应用需求:有些应用领域,如某些类型的生物特征识别(指纹识别)、文档分析等,主要关注图像的纹理和形状信息,这些信息在灰度图像中更容易提取。
暂不关心4、5两条
[1. 简化计算]:黑白图像只需要关心像素的明亮程度
需要知道:
- 图像以数字矩阵的形式存储在计算机中,其中这些数字称为像素值。
- 这些像素值代表每个像素的强度。
- 0代表黑色,255代表白色。
- 数字矩阵称为通道,对于灰度图像,我们只有一个通道。
那么彩色图片是如何在计算机中存储的呢?
- 图像由许多颜色组成,几乎所有颜色都可以从三种原色(红色,绿色和蓝色)生成。我们可以说每个彩色图像都是由这三种颜色或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调用摄像头,并将捕获的图片存储到指定路径
实现功能如下:
- 按下“n”新建用户文件夹,用来存储人脸图片
- 按下“s”捕获人脸图片,并存储到指定路径
- 按下“o”框出人脸
- 按下“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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步