OpenCV——通过摄像头捕获实时视频并探测人脸、准备人脸数据

转载自

作者:种子_fe
链接:https://www.imooc.com/article/67961
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

本地视频读取

OpenCV中是通过创建一个VideoCapture对象来捕获视频,这里先以读取和播放本地视频为例:

import cv2

cap = cv2.VideoCapture('clementi sonatina in f major, op. 36 no. 4.mp4') # 注意这里视频放在当前工作目录下,VideoCapture的参数就是视频文件名

while(cap.isOpened()): # isOpened方法判断视频是否成功打开
    ret, frame = cap.read() # read方法返回一个表示视频是否正确读取的布尔值和一帧图像
    
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 这里用cvtColor(cvt就是convert的缩写)方法进行色彩空间的转换,这里是从BGR空间转换到灰度空间
    
    cv2.imshow('frame', gray) # 通过imshow显示一帧图像
    if cv2.waitKey(1) & 0xFF == ord('q'): # 一帧显示一毫秒,通过上面的while循环不断地显示下一帧,从而形成动态的视频;按q键退出循环,关闭视频。
        break
    
cap.release()
cv2.destroyAllWindows()

通过笔记本摄像头捕获实时视频流

通过上面读取本地视频的代码,可以理解OpenCV中显示视频的原理就是通过循环不断显示下一帧图像从而得到动态的视频,下面,只需改变VideoCapture的参数就可以捕获笔记本电脑摄像头的实时视频流:

import cv2    #引入cv2,也就是引入opencv的一些包和处理类,不然下面的一些操作都无法完成

#打开摄像头的方法,window_name为显示窗口名,video_id为你设备摄像头的id,默认为0-1,如果引用usb可能会改变为1,等
def openvideo(window_name ,video_id):
    cv2.namedWindow(window_name) # 创建一个窗口

    cap=cv2.VideoCapture(video_id) # 获取摄像头
    while cap.isOpened():
        ok,frame=cap.read() # ok表示摄像头读取状态,frame表示摄像头读取的图像
        if not ok :
            break

        cv2.imshow(window_name,frame) # 将图像矩阵显示在一个窗口中
        c=cv2.waitKey(10) # 等待10ms,10ms内没有按键操作就进入下一次while循环,从而得到10ms一帧的效果,waitKey返回在键盘上按的键
        if c & 0xFF==ord('q'): # 按键q后break
            break

    # 释放资源
    cap.release()
    cv2.destroyWindow(window_name)
    print("cam closed")

# 主程序调用方法运行
if __name__ == '__main__': # __name__ 是当前模块名,当模块被直接运行时模块名为 __main__ 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。
    print ('open camera...')
    openvideo('mycam' ,0)
    

从实时视频流中探测人脸

如果你跟着上面的代码成功运行到了这一步,应该已经可以在打开的摄像头窗口里看到自己的脸了,下面要做的就是从里面探测到你的脸了:

import  cv2

def facedetect(windowname,camera_id):
#命名和打开摄像头
    cv2.namedWindow(windowname) # 创建一个已windowname为名字的窗口

    cap=cv2.VideoCapture(camera_id) # camera_id为设备摄像头的id,默认是0,如果有usb摄像头可能会变为1
    # Face Detection using Haar Cascades http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_objdetect/py_face_detection/py_face_detection.html?highlight=cascadeclassifier
    classfier=cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml') # 加载分类器,分类器位置可以自行更改,注意这里用opencv库文件夹下的绝对路径也不行,在库文件夹里找到这个文件复制到这个程序的同目录下,参考:https://blog.csdn.net/GAN_player/article/details/77993872

    color=(0,225,0)#人脸框的颜色,采用rgb模型,这里表示g取255,为绿色框

    while cap.isOpened():
        ok,frame=cap.read() # 读取一帧数据,ok表示摄像头读取状态,frame表示摄像头读取的图像矩阵mat类型
        if not ok:
            break
        # 灰度化在后面检测时可以降低计算量,cvtColor changing colorspace
        gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)#图像灰度化,cv2.cvtColor(input_image, flag) where flag determines the type of conversion.

这一部分代码在前面捕获实时视频流的基础上加载了OpenCV所提供的用于对象检测的分类器,注意分类器文件haarcascade_frontalface_alt2.xml可以在OpenCV包文件夹下找到,要放到当前工作目录下才能使用,这个分类器就是用来探测人脸的,在探测到人脸后,我们要在视频窗口中把人脸部分框出来,color变量就用来指定框的颜色,接着我们就来看看得到人脸框的代码:

 # detectMultiScale完成人脸探测工作,returns the positions of detected faces as Rect(x,y,w,h),x、y是左上角起始坐标,h、w是高和宽
        # grey是要识别的图像数据,scaleFactor图像缩放比例,可以理解为同一个物体与相机距离不同,其大小亦不同,必须将其缩放到一定大小才方便识别,该参数指定每次缩放的比例
        faceRects=classfier.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=3,minSize=(32,32)) # 利用分类器检测灰度图像中的人脸矩阵数,1.23分别为图片缩放比例和需要检测的有效点数

        if len(faceRects)>0:#大于0则检测到人脸     
            for faceRect in faceRects:# 可能检测到多个人脸,用for循环单独框出每一张人脸
                x,y,w,h=faceRect#获取框的左上的坐标,框的长宽
                # cv2.rectangle()完成画框的工作,这里外扩了10个像素以框出比人脸稍大一点的区域,从而得到相对完整一点的人脸图像;cv2.rectangle()函数的最后两个参数一个用于指定矩形边框的颜色,一个用于指定矩形边框线条的粗细程度。
                cv2.rectangle(frame,(x-10,y-10),(x+w-10,y+h-10),color,2)

        cv2.imshow(windowname,frame) # 显示图像

        c=cv2.waitKey(10)
        if c&0xFF==ord('q'): # 退出条件
            break

    cap.release()#释放摄像头并销毁所有窗口
    cv2.destroyAllWindows()


if __name__ == '__main__':#主程序
    print ('face detecting... ')
    facedetect('facedetect',0)

现在,运行上面的程序,应该就能在视频窗口里看到你的脸被绿色的框框起来了,下一步我们要把框出来的人脸保存下来。
在这里插入图片描述

保存人脸图像数据

上面的程序里我们已经得到了人脸区域的起始坐标和宽高,只需访问图片特定像素和区域的方法把这一区域单独拿出来存成图片就行了,这里的关键代码是:

image = frame[y:y+h, x:x+w] # 将当前帧含人脸部分保存为图片,注意这里存的还是彩色图片,前面检测时灰度化是为了降低计算量;这里访问的是从y位开始到y+h-1位
cv2.imwrite(image_name, image)

完整代码

import cv2

def getTrainingData(window_name, camera_id, path_name, max_num): # path_name是图片存储目录,max_num是需要捕捉的图片数量
    cv2.namedWindow(window_name) # 创建窗口
    cap = cv2.VideoCapture(camera_id) # 打开摄像头
    classifier = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml') # 加载分类器
    color = (0,255,0) # 人脸矩形框的颜色
    num = 0 # 记录存储的图片数量
    
    while cap.isOpened():
        ok, frame = cap.read()
        if not ok:
            break
        
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 灰度化
        faceRects=classifier.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=3,minSize=(32,32))
        
        if len(faceRects) > 0:
            for faceRect in faceRects:
                x,y,w,h = faceRect
                # 捕捉到的图片的名字,这里用到了格式化字符串的输出
                image_name = '%s%d.jpg' % (path_name, num) # 注意这里图片名一定要加上扩展名,否则后面imwrite的时候会报错:could not find a writer for the specified extension in function cv::imwrite_ 参考:https://stackoverflow.com/questions/9868963/cvimwrite-could-not-find-a-writer-for-the-specified-extension
                image = frame[y:y+h, x:x+w] # 将当前帧含人脸部分保存为图片,注意这里存的还是彩色图片,前面检测时灰度化是为了降低计算量;这里访问的是从y位开始到y+h-1位
                cv2.imwrite(image_name, image)
                
                num += 1
                # 超过指定最大保存数量则退出循环
                if num > max_num:
                    break
                
                cv2.rectangle(frame, (x,y), (x+w,y+h), color, 2) # 画出矩形框
                font = cv2.FONT_HERSHEY_SIMPLEX # 获取内置字体
                cv2.putText(frame, ('%d'%num), (x+30, y+30), font, 1, (255,0,255), 4) # 调用函数,对人脸坐标位置,添加一个(x+30,y+30)的矩形框用于显示当前捕捉到了多少人脸图片
        if num > max_num:
            break
        cv2.imshow(window_name, frame)
        c = cv2.waitKey(10)
        if c & 0xFF == ord('q'):
            break

    cap.release()#释放摄像头并销毁所有窗口
    cv2.destroyAllWindows()
    print('Finished.')
#主函数
if __name__ =='__main__':
    print ('catching your face and writting into disk...')
    getTrainingData('getTrainData',0,'training_data_me/',100) # 注意这里的training_data_xx 文件夹就在程序工作目录下

  • 8
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值