使用GluonCV+OpenCV+YoloV3调用摄像头实现实时人脸检测

1.写在前面

最近组里有个项目与目标识别有关,去网上找了一下,发现目前SOTA的目标识别算法基本都是one-stage的,比如SSD、DSSD、RetinaNet、YOLO等,但是速度上YOLO是最快的。而且看了下YOLO主页,作者的风格我很喜欢。所以仔细研究了一下。本文的内容基于GluonCV、OpenCV和YoloV3,运行平台为Ubuntu16.04版本。ps:因为组里采购的服务器还没到,目前只能在我自己笔记本的虚拟机上跑,而虚拟机的显卡是模拟出来的,无法安装CUDA和CUDNN(这个坑也是我安装CUDA遇到了各种坑后发现的),各位有条件的还是使用CUDA+CUDNN环境,速度会快不少。

2.环境搭建

2.1 GluonCV

GuonCV是一个计算机视觉深度学习的工具箱,功能非常强大,包含了图像分类,目标识别,语义分割,实例分割等。GluonCV的安装在他们主页上面有介绍,安装很简单,python2和python3都可以,但是你的pip版本要大于9.0,同时还要安装一个mxnet框架。同时他们主页还提供了一些简单的demo教你使用,还可以查询API的源代码。

2.2 OpenCV

OpenCV是一个用于图像处理、分析、机器视觉方面的开源函数库. 无论你是做科学研究,还是商业应用,OpenCV都可以作为你理想的工具库,因为,对于这两者,它完全是免费的。该库采用C及C++语言编写,可以在windows, linux, mac OSX系统上面运行。该库的所有代码都经过优化,计算效率很高,因为,它更专注于设计成为一种用于实时系统的开源库。opencv采用C语言进行优化,而且,在多核机器上面,其运行速度会更快。它的一个目标是提供友好的机器视觉接口函数,从而使得复杂的机器视觉产品可以加速面世。该库包含了横跨工业产品检测、医学图像处理、安防、用户界面、摄像头标定、三维成像、机器视觉等领域的超过500个接口函数。

OpenCV安装很简单,直接pip install opencv-python即可。你也可以使用源代码安装,官网的下载速度很痛苦,我给个OpenCV3.4.7版本的链接,需要的朋友可以自取:
https://pan.baidu.com/s/1Zts9WR7VtH-2L0e9fIaNHw
提取码:498k
源码的安装教程网上很多,我贴一个别人https://jingyan.baidu.com/article/a3761b2be162951576f9aace.html,需要安装cmake工具,没有安装的直接apt install cmake就可以了。

2.3 YoloV3

YoloV3在他们主页有很详细的教程(基于darknet),有兴趣可以去看下他们的论文,写的很有趣,传统的识别方法是当做一个分类问题,而作者当做一个回归问题来处理,同时并不像传统算法那样需要很多滑动窗口,他是end to end直接输出结果,这也是他们的名字YOLO(you only look once)的由来。同时推荐新手使用darknet,他是一个很轻量级的框架,但是内容很多,且易于上手。

3.代码

代码主要分为三个模块,utils模块,detection模块和main模块。

3.1 utils模块

utils模块包括data_preset.py,yolov3.py,bbox.py等文件
[图片上传失败...(image-4f99d3-1569487002238)]

3.2 detection模块

detection模块包括model,mobilefacedetnet.py等文件
[图片上传失败...(image-7077ae-1569487002238)]

3.3 main模块

main模块包括cap.py函数,其实就是执行函数。使用python3 cap.py执行就行。ps:我设置了一些命令行参数,比如--video选择本地视频,--camera选择摄像头,--gpu选择是否使用GPU。大家可以使用python3 cap.py -h查看使用方法,比如
[图片上传失败...(image-4ec4d7-1569487002238)]
cap.py代码如下:

from mxnet import nd
import gluoncv as gcv
from mxnet.gluon.nn import BatchNorm
from gluoncv.data.transforms import presets
from matplotlib import pyplot as plt
sys.path.append(os.path.abspath(os.path.dirname(__file__)) + os.sep + '../MobileFace_Detection/utils/')
from data_presets import data_trans
sys.path.append(os.path.abspath(os.path.dirname(__file__)) + os.sep + '../MobileFace_Detection/')
from mobilefacedetnet import mobilefacedetnet_v2
sys.path.append(os.path.abspath(os.path.dirname(__file__)) + os.sep + '../MobileFace_Tracking/')
from mobileface_sort_v1 import Sort


def parse_args():
    parser = argparse.ArgumentParser(description='Test with YOLO networks.')
    parser.add_argument('--model', type=str, 
                        default='../MobileFace_Detection/model/mobilefacedet_v2_gluoncv.params',
                        help='Pretrained model path.')
    parser.add_argument('--video', type=str, default='friends1.mp4',
                        help='Test video path.')
    parser.add_argument('--camera', type=int, default=None,
                        help='Camera select')
    parser.add_argument('--gpus', type=str, default='',
                        help='Default is cpu , you can specify 1,3 for example with GPUs.')
    parser.add_argument('--pretrained', type=str, default='True',
                        help='Load weights from previously saved parameters.')
    parser.add_argument('--thresh', type=float, default=0.5,
                        help='Threshold of object score when visualize the bboxes.')
    parser.add_argument('--sort_max_age', type=int, default=10,
                        help='Threshold of object score when visualize the bboxes.')
    parser.add_argument('--sort_min_hits', type=int, default=3,
                        help='Threshold of object score when visualize the bboxes.')
    parser.add_argument('--output', type=str, 
                        default='./tracking_result/result_friends1_tracking.avi',
                        help='Output video path and name.')
    args = parser.parse_args()
    return args

def main():
    args = parse_args()
    # context list
    ctx = [mx.gpu(int(i)) for i in args.gpus.split(',') if i.strip()]
    ctx = [mx.cpu()] if not ctx else ctx

    net = mobilefacedetnet_v2(args.model)
    net.set_nms(0.45, 200)
    net.collect_params().reset_ctx(ctx = ctx)

    mot_tracker = Sort(args.sort_max_age, args.sort_min_hits) 

    img_short = 256   
    colors = np.random.rand(32, 3) * 255

    winName = 'MobileFace for face detection and tracking'
    cv2.namedWindow(winName, cv2.WINDOW_NORMAL)
    if args.camera == None:
        cap = cv2.VideoCapture(args.video)
    else:
        cap = cv2.VideoCapture(args.camera)
    output_video = args.output
    # video_writer = cv2.VideoWriter(output_video, cv2.VideoWriter_fourcc('M','J','P','G'), 30, (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))))
    video_writer = cv2.VideoWriter(output_video, cv2.VideoWriter_fourcc('M','J','P','G'), 30, (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))))
    # while(cap.isOpened()):
    while cv2.waitKey(1) < 0:
        ret, frame = cap.read()
        if not ret:
            print("Done processing !!!")
            print("Output file is stored as ", output_video)
            cv2.waitKey(3000)
            break
        
        dets = []
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        frame_nd = nd.array(frame_rgb)
        x, img = data_trans(frame_nd, short=img_short)
        x = x.as_in_context(ctx[0])
        # ids, scores, bboxes = [xx[0].asnumpy() for xx in net(x)]
        tic = time.time()
        result = net(x)
        toc = time.time() - tic
        #print('Detection inference time:%fms' % (toc*1000))
        ids, scores, bboxes = [xx[0].asnumpy() for xx in result]

        h, w, c = frame.shape
        scale = float(img_short) / float(min(h, w))
        for i, bbox in enumerate(bboxes):
            if scores[i]< args.thresh:
                continue
            xmin, ymin, xmax, ymax = [int(x/scale) for x in bbox]
            # result = [xmin, ymin, xmax, ymax, ids[i], scores[i]]
            result = [xmin, ymin, xmax, ymax, ids[i]]
            dets.append(result)

        dets = np.array(dets)    
        tic = time.time()
        trackers = mot_tracker.update(dets)
        toc = time.time() - tic
        #print('Tracking time:%fms' % (toc*1000))

        for d in trackers:
            color = (int(colors[int(d[4]) % 32, 0]), int(colors[int(d[4]) % 32,1]), int(colors[int(d[4]) % 32, 2]))
            cv2.rectangle(frame, (int(d[0]), int(d[1])), (int(d[2]), int(d[3])), color, 3)
            # cv2.putText(frame, str('%s%0.2f' % (net.classes[int(d[4])], d[5])), 
            #            (d[0], d[1] - 5), cv2.FONT_HERSHEY_COMPLEX , 0.8, color, 2)
            cv2.putText(frame, str('%s%d' % ('face', d[4])), 
                       (int(d[0]), int(d[1]) - 5), cv2.FONT_HERSHEY_COMPLEX , 0.8, color, 2)

        video_writer.write(frame.astype(np.uint8))  
        cv2.imshow(winName, frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    warnings.filterwarnings("ignore")
    main()

4.后续

项目我会放到我的GitHub上,更新了会告诉大家,如果有想要的可以联系我maplect@sina.com,我看到会发给你。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 一瞥(You Only Look Once, YOLO),是检测Pascal VOC2012数据集内对象/目标的系...
    Aspirinrin阅读 52,333评论 28 64
  • 木里藏族自治县位于四川省西南边缘,境内山峦重叠,河流环绕。县域内的景色由森林、河流、湖泊、山涧瀑布、雪山组成,属于...
    霜叶shuangye阅读 1,772评论 5 2
  • 今天带着小车宝宝出去玩,我们刚下楼的时候还没有下雨,宝宝玩的很高兴,可一会儿下雨了,宝宝还没玩够,和宝宝说下雨了,...
    贾秀秀阅读 349评论 0 0
  • 世界上每个人都是独立的个体,每个人都是一个“我”,所以每个人多少都会有点自私,因为他们是“我”。有什么想不明白的,...
    小可愛哇阅读 156评论 0 1
  • 姓名:陈芬 公司:宁波慈星股份有限公司 宁波盛和塾《六项精进》224期学员,利他二组学员 【日精进打卡第161天】...
    龙芬浩阅读 116评论 0 0