基于opencv使用python实现人脸识别与视频生成
概述
OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。
OpenCV由一系列C函数和少量C++类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法,主要倾向于实时视觉应用。
基础用法
- **cv2.imread()**:读入图像。第一个参数为图像路径,第二个参数指定读入图像的颜色,例如cv2.IMREAD_COLOR表示读入彩色图像,cv2.IMREAD_GRAYSCALE表示读入灰度图像。
- **cv2.imshow()**:显示图像。第一个参数是窗口的名字,第二个参数是要显示的图像。
- **cv2.VideoCapture()**:获取摄像头视频或者读取视频文件。参数可以是设备的索引号,也可以是视频文件的路径。
- **cv2.imwrite()**:保存图像。第一个参数是文件名,包括文件路径和文件扩展名,第二个参数是要保存的图像。
- **cv2.cvtColor()**:转换图像颜色空间。例如将彩色图像转换为灰度图像。
实际案例
图像转视频
图像尺寸统一化
1 |
|
上述代码讲不同尺寸图像转换为统一目标尺寸,过小用黑边填充,过大进行缩放。
图像转为视频
1 |
|
上述代码从list中读取图像,使用
width = image.shape[1]
获取图像宽度或高度;使用fourcc = cv2.VideoWriter.fourcc(*'MJPG') # 创建VideoWriter对象 video_name = video_out_path + id_generate_time() + "test.mp4" video = cv2.VideoWriter(video_name, fourcc, int(output_video_fps), (width, height))
创建videowriter对象,其中output_video_fps规定了视频输出帧率,(width, height)规定了视频输出宽高度;后边使用image = cv2.imread(os.path.join(images_input_path, image_path))
读取传入图片对象;使用resized_image = cv2.resize(image, (width, height))
再次调整图片大小至合适尺寸;最后使用video.write(resized_image)
写入图像到视频中。写入完成后,使用video.release()
释放对象。
人脸特征检测
分类器下载与使用
- 下载地址
1
https://github.com/opencv/opencv/tree/master/data/haarcascades。
- 读取与使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def get_data_file(filename):
"""
获取数据文件的路径,无论是直接运行还是通过 PyInstaller 打包
:param filename
:return
"""
if getattr(sys, 'frozen', False):
# 如果程序是“冷冻的”,即打包后的 exe
basedir = sys._MEIPASS
else:
# 如果程序是直接运行的,即没有打包
basedir = os.path.dirname(__file__)
return os.path.join(basedir, filename)
def main():
face_xml_path = get_data_file("xml_data/haarcascade_frontalface_default.xml")
eye_xml_path = get_data_file('xml_data/haarcascade_eye.xml')
# 加载分类器
face_cascade = cv2.CascadeClassifier(face_xml_path)
eye_cascade = cv2.CascadeClassifier(eye_xml_path)
实际案例
- 图像读取与人脸特征分割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def face_detect(path, image_path):
"""
使用OpenCV进行人脸和眼睛检测。
:param path:
:param image_path: 图像文件的路径。
:return: None
"""
file_path, file_name = os.path.split(image_path)
folder_name = find_img_result(image_path)
if folder_name is None:
folder_name = 'unknown_name'
logger.warning('folder_name is None, default use unknown_name.')
base_path = os.path.join(path, "face_detect_result")
base_path = os.path.join(base_path, folder_name)
img_file_path = os.path.join(base_path, "split_face")
img_file_path_line = os.path.join(base_path, "red_line")
img_file_name = os.path.join(img_file_path, file_name)
img_file_name_line = os.path.join(img_file_path_line, file_name)
if not os.path.exists(img_file_path):
os.makedirs(img_file_path)
logger.warning("face detect split_face dir not exists, create it.")
if not os.path.exists(img_file_path_line):
os.makedirs(img_file_path_line)
logger.warning(f"face detect red_line dir not exists, create it: {img_file_path}.")
# 只生成没有的
if os.path.exists(img_file_name) or os.path.exists(img_file_name_line):
logger.warning(f"{img_file_name} already exists, will skip!")
return False
try:
face_xml_path = get_data_file("xml_data/haarcascade_frontalface_default.xml")
eye_xml_path = get_data_file('xml_data/haarcascade_eye.xml')
# 加载分类器
face_cascade = cv2.CascadeClassifier(face_xml_path)
eye_cascade = cv2.CascadeClassifier(eye_xml_path)
# 读取图像
img = cv2.imread(image_path)
if img is None:
logger.error(f"Error: Unable to load image at {image_path}")
return False
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = face_cascade.detectMultiScale(gray, 1.1, 5)
# eye_cascade.detectMultiScale(gray, 1.1, 5)
if len(faces) == 0:
# logger.warning(f"No faces detected:{image_path}")
return False
else:
save_face(img_file_name, img_file_name_line, img, faces, gray, eye_cascade)
# 显示结果
cv2.waitKey(0)
cv2.destroyAllWindows()
except Exception as e:
logger.error(f"An error occurred: {e}")
return False - 识别结果保存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def save_face(img_file_name, img_file_name_line, img, faces, gray, eye_cascade):
"""
:param eye_cascade:
:param gray:
:param img_file_name_line:
:param img_file_name:
:param img:
:param faces:
:return:
"""
target_size = (200, 200)
# Calculate the dimensions of the faces_image based on the number of faces and target size
num_faces = len(faces)
faces_image_height = num_faces * target_size[0]
faces_image_width = target_size[1] # Assuming we want to fit only one face horizontally for simplicity
try:
# Create a blank image to hold the resized faces
faces_image = np.zeros((faces_image_height, faces_image_width, 3), dtype=np.uint8)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
roi_gray = gray[y:y + h, x:x + w]
roi_color = img[y:y + h, x:x + w]
# 在人脸区域内检测眼睛
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
# 将绘制了眼睛矩形框的人脸区域放回原图的正确位置
img[y:y + h, x:x + w] = roi_color
# Iterate over the detected faces
for i, (x, y, w, h) in enumerate(faces):
# Resize the face to the target size
face_resized = cv2.resize(img[y:y + h, x:x + w], target_size)
row = i
col = 0
# Place the resized face in the faces_image array
faces_image[row * target_size[0]:(row + 1) * target_size[0],
col * target_size[1]:(col + 1) * target_size[1]] = face_resized
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite(img_file_name, faces_image)
cv2.imwrite(img_file_name_line, img)
except Exception as e:
logger.error(f"unknown error, detail: {e}, name: {img_file_name[-27:]}")
return False
logger.success(f"save success, name: {img_file_name[-27:]}")
return True上述代码,在人脸中检测了眼睛、脸部特征点,并使用对应颜色框框选出来,最终保存至目标路径。