这几天在看OpenCV相关的书,结合书上的源码自己拼合出了这个功能,于是写下来作为入门OpenCV的一个记录。
要完成这个功能,需要两步操作,一是打开摄像头采集图像,二是将采集到的图像送入图像检测模块。
类VideoCapture是OpencCV中最基本的视频输入输出接口,可以读取视频文件或打开摄像头,提取视频帧,并提供多个函数获取视频的属性信息。如用open函数可以打开一个视频文件或打开一个捕获视频的设备;用release函数实现关闭视频文件或摄像头;用get函数则可以获取视频中如帧率、格式等信息。
从视频文件中读取视频创建VideoCapture对象格式为:
VideoCapture(filename) --> <VideoCapture object> filename为文件名
从摄像机中读取视频创建VideoCapture对象格式为:
VideoCapture(device) --> <VideoCapture object> device为视频捕获设备的ID
如果在计算机中插入一个摄像头,那么open的第一个参数通常是700。可以尝试运行下面这段代码,应该就能看到笔记本摄像头被调用后开启视频的画面。此时相当于一帧一帧地从摄像头中读取画面,并一帧一帧地播放,间隔时间很短,给人的感觉就像是在看视频。
import cv2 as cv
#打开摄像头 默认为700
cap = cv.VideoCapture(700)
# 设置宽度和高度
cap.set(cv.CAP_PROP_FRAME_WIDTH,320)
cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)
while True:
#每次读取一帧摄像头或者视频
ret,frame = cap.read()
#将一帧frame显示出来,第一个参数为窗口名
cv.imshow('frame',frame)
#每次等待1ms 当esc按键被按下时退出显示
#ESC按键对应的键值为27
if(cv.waitKey(1)&0xff) == 27:
break
#常规操作 释放资源
cap.release()
cv.destroyAllWindows()
从提取特征开始实现人脸检测比较费时,作为初学者,我们可以直接使用OpenCV的级联分类器(CascadedClassifier)加载预训练模型进行直观感受,这些模型可以在cv2的data文件夹中直接找到。这些预训练模型的模型采用了AdaBoost(Adaptive Boosting,自适应增强)算法,将多个弱分类器组合成强分类器,具有较小的误别率和较快的运行速度。
应该指出的是,为了提高人脸检测的速度和精度,最终的分类器其实往往是由几个强分类器级联得到的。在一个级联分类系统中,对于每一个输入图像,将顺序通过每个强分类器。其中,前面的强分类器相对简单,包含的弱分类器相对较少,后面的强分类器逐级复杂,只有通过前面的强分类器,才能进一步送入下一个强分类器,这样的过滤方式在保证精度的同时提高了效率。只有最终通过了所有强分类器的图像区域,才是有效的人脸区域。
import cv2
# 采用电脑前置摄像头
capture = cv2.VideoCapture(700)
# 获取 capture 的一些属性
frame_width = capture.get(cv2.CAP_PROP_FRAME_WIDTH)
frame_height = capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
print('The width is %.1f . \n The height is %.1f'%(frame_width, frame_height))
if capture.isOpened() is False:
print('Error openning the camera')
# 人脸检测函数
def detectface(image):
# 读取文件
model1 = 'haarcascade_eye.xml'
model1 = cv2.CascadeClassifier(model1) # 加载模型
# 人眼检测
eyes = model1.detectMultiScale(image)
for (x, y, w, h) in eyes:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), thickness=2) # 红色画出人眼矩形框
# 读取文件
model2 = 'haarcascade_frontalface_default.xml'
model2 = cv2.CascadeClassifier(model2) # 加载模型
# 人脸检测
faces = model2.detectMultiScale(image)
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), thickness=2) # 绿色画出人脸矩形框
# 显示图片
cv2.imshow('detect_result', image)
return image
# 直接识别lena图片,用作测试
image = cv2.imread('lena.png')
detectface(image)
cv2.waitKey(3000) # 展示个3秒
# 视频流识别
frame_index = 0
while capture.isOpened():
ret, frame = capture.read()
if ret:
# 显示摄像头捕获的帧
cv2.imshow('Input frame from the camera', frame)
# 识别捕捉到的帧
detect_frame = detectface(frame)
# cv2.waitKey()这个函数是在一个给定的时间内(单位ms)等待用户按键触发
# 按下'q'键退出
if (cv2.waitKey(10) & 0xFF) == ord('q'):
break
# 按下'c'键保存
if (cv2.waitKey(10) & 0xFF) == ord('c'):
frame_name = f'camera_frame_{frame_index}.png'
detect_frame_name = f'dectect_camera_frame_{frame_index}.png'
cv2.imwrite(frame_name, frame)
cv2.imwrite(detect_frame_name, detect_frame)
frame_index += 1
else:
break
# 关闭退出
capture.release()
cv2.destroyAllWindows()
运行上述代码,一开始应该先看到一幅lena的测试图,悬停3秒后会正常进入摄像头捕捉的人脸实时检测。看得出来对于静态图片的识别效果还是很好的。
接下来应该看得到两个视频捕捉的显示窗口,按下“q”键退出,按下“c”键保存图像,下面是某次捕捉的保存结果。(可以尝试低下头一些,不然容易将鼻孔区域误标记成眼睛,场景中的一些黑格都有一定概率容易被误识