实现效果:写一个图形界面,实现输入一个视频,对视频中的人脸进行捕捉并输出。
本文技术基础将分为三个部分介绍:
库 | 用途 |
---|---|
opencv | 视频处理模块 |
face_recognition | 人脸识别模块 |
tkinter | 窗口视窗设计模块 |
face_recognition是一个强大、简单、易上手的人脸识别开源项目,输入一张图像就可以确定人脸的位置。关于face_recognition的更多内容可以了解https://github.com/ageitgey/face_recognition。
以下是我亲自尝试过的face_recognition库下载方法,都成功安装了:
sudo wget https://cmake.org/files/v3.9/cmake-3.9.0-rc5.tar.gz -O cmake.tar.gz
sudo tar -xvf cmake.tar.gz
cd cmake-3.9.0-rc5/
sudo chmod +x bootstrap
sudo ./bootstrap
sudo make
sudo make install
安装好cmake后,输入
cmake -version
查看cmake版本是否安装成功。然后安装git来手动安装dlib
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build
cd build
cmake ..
最后安装face_recognition。
Python的cv2库是一个在计算机视觉领域应用非常广泛的库,Python对于视频的读取、处理很多使用cv2库实现。
了解、安装cv2库可以参考Py之cv2:cv2库(OpenCV,opencv-python)的简介、安装、使用方法(常见函数、方法等)最强详细攻略。在处理图像方面,cv2和其他几种常见的库例如PIL的用法很不一样,可以查看我的另一篇文章可以上Python PIL、cv2、Dataloader、plt读取/显示图像数据集对比实例。
v2使用有一些坑,例如三个通道的顺序是BGR而不是RGB,有时会报奇怪的错误其实就是图像路径没写对,等等。
我们可以用GUI 实现很多直观的功能,比如想开发一个计算器,如果只是一个程序输入,输出窗口的话,是没用用户体验的。所有开发一个图像化的小窗口,就是必要的。
Tkinter 就是使用 python 进行窗口视窗设计的模块。Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口。
作为 python 特定的GUI界面,是一个图像的窗口,tkinter是python 自带的,不需要另外下载。
参考:Python GUI之tkinter窗口视窗教程大集合(看这篇就够了)
以下给出本文的主要代码,完整代码见我的Github: GUI for video_face_recognition
这一部分主要使用cv2库实现。
读取视频:
self.cap = cv2.VideoCapture(self.filename)
读取fps每秒传输帧数、视频时长(帧总数)
self.fps = self.cap.get(cv2.CAP_PROP_FPS)
self.total = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
设定从视频的第几帧开始读取
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.start)
如果视频是竖着拍的,在cv2读取进去以后仍然是横向的,所以在人脸识别之前,需要旋转一下。(当然喵酱这些视频都是横着拍的就不用旋转了)
旋转图像代码:
##旋转图像
def rotate_bound(image,angle):
#获取图像的尺寸
#旋转中心
(h,w) = image.shape[:2]
(cx,cy) = (w/2,h/2)
#设置旋转矩阵
M = cv2.getRotationMatrix2D((cx,cy),-angle,1.0)
cos = np.abs(M[0,0])
sin = np.abs(M[0,1])
# 计算图像旋转后的新边界
nW = int((h*sin)+(w*cos))
nH = int((h*cos)+(w*sin))
# 调整旋转矩阵的移动距离(t_{x}, t_{y})
M[0,2] += (nW/2) - cx
M[1,2] += (nH/2) - cy
return cv2.warpAffine(image,M,(nW,nH))
读取视频的每一帧图像:
ret, frame = self.cap.read()#frame(720, 1280, 3)BGR
if not ret:##视频读取结束,退出
break
## 旋转图片,否则是横过来的
if self.rotate == 1:
frame = rotate_bound(frame,90)
由于喵酱的视频尺寸比较大,需要缩小尺寸。
然后转成RGB通道。在显示之前还要再转回BGR去。
## 缩放
frame = cv2.resize(frame, (1200, 800))
## BGR到RGB
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
然后是辅助功能:在图像上显示当前帧在整个视频上的时间进展
#计算当前时间进度
now_seconds=int(self.cnt/self.fps%60)
now_minutes=int(self.cnt/self.fps/60)
total_second=int(self.total /self.fps%60)
total_minutes=int(self.total/self.fps/60)
# { <参数序号> : <填充> <对齐)> <宽度> <,> <.精度> <类型>}.
time_now_vs_total="Time:{:>3}:{:>02}|{:>3}:{:0>2}".format(now_minutes,now_seconds,total_minutes,total_second)
# 输出到画面上
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(img, time_now_vs_total, (10, 50), font, 1.0, (255, 255, 255), 1)
对于视频场景的人脸识别代码在github上是开源的https://github.com/ageitgey/face_recognition/blob/master/examples/facerec_from_webcam_faster.py,所以选择性的copy就可以了。
首先,对于一帧图像,找到脸的位置
face_locations = face_recognition.face_locations(frame)
然后用蓝色框标记出来就ok了
for (top,right,bottom,left) in face_locations:
frame = cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
GUI功能:
使用:
我们的窗口设计如下:
图形大小、标题
root = Tk()
root.geometry('250x150+200+200')
root.title('视频人脸识别 1.0')
Label:
Label(root,text = '当前播放:').grid(row = 0,sticky = W)
Label(root,text = '按q退出当前视频').grid(row = 6,column = 0,sticky = W)
Label(root,text = '按空格暂停').grid(row = 6,column = 1,sticky = W)
两个文本框:
Label(root,text = '保存帧间隔').grid(row = 3,column = 0)
skip_entry = Entry(root)
skip_entry['width'] = 10
skip_entry.insert(0,10) ##每10次保存一张图像
skip_entry.grid(row = 3,column = 1)
Label(root,text = '从第几帧读取').grid(row = 4,column = 0)
start_entry = Entry(root)
start_entry['width'] = 10
start_entry.insert(0,1) ##每10次保存一张图像
start_entry.grid(row = 4,column = 1)
两个Checkbutton:
v = IntVar()
v.set(1)
Checkbutton(root,text = '翻转',variable = v,onvalue=1,offvalue=0).grid(row = 5,column = 0)
v2 = IntVar()
v2.set(1)
Checkbutton(root,text = '需要缩放尺寸',variable = v2,onvalue=1,offvalue=0).grid(row = 5,column = 1)
三个Button
Button(root,text = '选择视频文件',command = selectpath).grid(row = 2,column = 0,sticky = W)
Button(root,text = '帮助',background = 'yellow',command = helpful).grid(row = 2,column = 1,sticky = E)
Button(root,text = '播放',background = 'red',command = thread).grid(row = 2,column = 1,sticky = W)
初次了解tkinter,欢迎各位指教。
参考:
https://www.cnblogs.com/mengd/p/7287119.html
Python Tkinter模块详解(后续持续补充)
【Python-opencv3.4】视频基本操作(帧率,总视频帧数、从第N帧开始播放、播放进度显示、按键控制视频)