Giter VIP home page Giter VIP logo

intelligentmonitor's Introduction

IntelligentMonitor

TOC

  1. 介绍
  2. 目的
  3. 演示
  4. 提供的API功能介绍
  5. 快速使用
  6. 如何编译
  7. 注意
  8. TODO
  9. 题外话

介绍

本项目是基于darknet yolov3 - AlexeyAB version进行的二次开发。 主要实现的是智能视频监控模块开发(动态链接库dll开发), 方便视频监控系统客户端进行智能化升级。

目的

传统的视频监控往往会记录着许多冗余数据, 这对于回看视频监控的操作人员来说, 将是一件枯燥而且艰难的工作。研究表明, 操作人员盯着电视墙超过10分钟, 就将漏掉90%的视频信息, 所以本课题旨在利用深度学习框架YOLO进行视频监控智能模块开发, 实现提取视频监控有效片段、人员计数等功能的DLL(动态链接库), 并提供相应调用的API接口, 从而使视频监控系统中的摄像机成为人的眼睛, 拓展视频监控系统的作用和能力, 实现非智能到智能地升级, 以此大幅度减少人力、物力、财力的投入。

演示

计数图片上有多少人

使用detect_something_appear_times

// names_file 是yolo能识别的所有目标名, 比如coco.names
// cfg_file 是yolo的cfg文件, 比如yolov3-tiny.cfg
// weights 是yolo的weights权重文件, 比如yolov3-tiny.weights
IntelligentMonitor monitor = IntelligentMonitor(
                                names_file, 
                                cfg_file, 
                                weights_file
                            );
std::string pic_file = "test_data/people_test.jpg"
std::cout << "person: " <<
       monitor.detect_something_appear(pic_file.c_str(), "person", true, "test_save_file/predict_people.jpg")
       << std::endl;

原图:

结果:

原图上实际有19个人, 检测到18个人, 正确率还是杠杠的 (使用yolov3.weights - YOLOv3-416)

计数视频中所有能检测对象出现的次数

演示detect_all_appear_times API, 用于检测视频画面上所有能检测到的对象出现的次数

左上角会标注出出现的次数。 可以通过设置

  • bool draw_box来控制是否要显示框住的对象的框
  • bool show_times来控制左上角是否显示检测到对象出现的次数

(使用yolov3.weights - YOLOv3-416)

提取视频有效片段

原视频路径: https://vd1.bdstatic.com/mda-hhfrc6w2sh38kh1s/sc/mda-hhfrc6w2sh38kh1s.mp4?auth_key=1553656663-0-0-ed14309fc809c2c477396b1d5ee95ff3&bcevod_channel=searchbox_feed&pd=bjh&abtest=all

原视频共有54秒, 通过extract提取有人出现的画面得到43秒视频, 实际有人出现的时间约为45秒。 其中设置了disappear_thresh为5, 表示视频中检测的人消失了5秒, 认定不再出现, 再出现就在新的片段中。

检测的片段:

// 本演示调用时, 设置的参数
// 设置了检测对象为"person"
// disappear_thresh为5, 表示视频中检测的对象消失了5秒, 认定不再出现, 再出现就在新的片段中
// draw_box设为了true
INTELLIGENT_API bool extract(
    cv::VideoCapture& cap,
    std::vector<char *>& obj_to_extract,
    const char* save_path = "./",
    const char * prefix = NULL,
    int disappear_thresh = DISAPPEAR_THREASH,
    bool draw_box = false,
    float thresh = DEFAULT_THREASH,
    double* progress_rate = NULL
);

其他API的使用参看IntelligentMonitor_console_demo.sln

或见API参数详细介绍

提供的API功能介绍

// 提取视频有效片段, 有2个重载函数
// 支持输入视频文件或cv::VideoCapture对象
// 可设置要提取的目标对象
// 可设置目标最大消失阈值, 即目标在画面消息了多少秒分一个片段
// 可选择是否要绘制框住对象的框
// 多线程可获取进度
// 可设置导出视频的路径、命名前缀
// 可设置置信度阈值下限(即分类时若大于该值, 才认定对象属于该分类)
// 可设置每检测一帧, 跳过几帧, 加快提取速度
INTELLIGENT_API extract(...);       

// 检测目标是否出现, 有4个重载函数
// 支持单个目标检测, 或一组目标检测
// 可框住检测到的目标
// 可设置处理后的图片的保存
// 可设置置信度阈值下限(即分类时若大于该值, 才认定对象属于该分类)
INTELLIGENT_API bool detect_something_appear(...);

// 检测目标出现次数, 有4个重载函数
// 支持单个目标检测, 或一组目标检测
// 可框住检测到的目标
// 可左上角显示各目标出现次数
// 可设置处理后的图片的保存
// 可设置置信度阈值下限(即分类时若大于该值, 才认定对象属于该分类)
INTELLIGENT_API int detect_something_appear_times(...);

// 检测画面所有目标出现次数, 有2个重载函数
// 可框住检测到的目标
// 可左上角显示各目标出现次数
// 可设置处理后的图片的保存
// 可设置置信度阈值下限(即分类时若大于该值, 才认定对象属于该分类)
INTELLIGENT_API void detect_all_appear_times(...);

API的用途

extract

可应用的场景:

  1. 传统的视频监控系统保存着很多录像记录, 这些录像记录中存在着许多冗余片段, 可使用这个API来剔除冗余视频内容, 减少操作员回看负担

detect_something_appear

返回值是布尔值

可应用的场景:

  1. 视频监控系统可使用该API来判断何时需要进行录像, 以此剔除冗余视频内容, 使有效存储周期提升(因为存储空间有限, 监控摄像头一般满了就会覆盖存储, 而剔除了冗余的内容, 就有更多的空间来保存有效视频内容, 而且还减少了回看操作员的负担)
  2. 视频监控系统可使用该API来设置看护区域, 即某些看护区域在某段时间内不允许有人出入, 就可以使用该API来实现该功能, 且还能利用这个来判断当有人出现在看护区域时, 进行响铃报警或者短信通知主人(地铁高速公路等禁止进入的区域和场所; 晚上睡觉, 想把大门口设置为看护区域; 银行押运钱时, 设置某区域为看护区域;幼儿园午觉, 用来看护哪些调皮蛋偷偷跑出来)

detect_somthing_appear_times detect_all_appear_times

detect_somthing_appear_timesdetect_all_appear_times功能相似

可应用的场景:

  1. 视频监控可以使用该API来实现计数, 比如路口车辆通过数, 或者统计路口行人密度, 或者统计公交车上拥挤程度, 或者为以进行人流量的统计, 为商业网点、大型超市等提供依据, 方便业务分析
  2. 视频监控可以使用该API来实现人员聚集检测, 对指定区域内出现的人员非法集中、群体性事件进行报警, 可以广泛用于广场、政府机关等场所, 避免非法游行集会等恶性事件发生。

更多的扩展: 因为只要更换cfg文件weights权重文件(前提是使用数据训练好), 就可以实现更多目标检测, 比如视频监控对违禁物品的监控等

快速使用

前提是部署好所需的环境

C++程序使用

  1. include目录包含到你的Visual Studio项目中
  2. IntelligentMonitor.lib文件附加到你的项目中
  3. 在你的代码中, 使用#include "intelligent_monitoring.h", 并加上#pragma comment(lib, "IntelligentMonitor.lib")
  4. 之后就可以使用IntelligentMonitor 这个类, 比如
#include "intelligent_monitoring.h"
#include <opencv2/opencv.hpp>          // C++
#include "opencv2/highgui/highgui.hpp"  
#include <string>
#include <vector>
#include <map>

#pragma comment(lib, "opencv_world343.lib")
#pragma comment(lib, "IntelligentMonitor.lib")

// names_file 是yolo能识别的所有目标名, 比如coco.names
// cfg_file 是yolo的cfg文件, 比如yolov3-tiny.cfg
// weights 是yolo的weights权重文件, 比如yolov3-tiny.weights
IntelligentMonitor monitor = IntelligentMonitor(
                                names_file, 
                                cfg_file, 
                                weights_file
                            );

std::vector<char *> obj_to_detect;
obj_to_detect.push_back("person");
obj_to_detect.push_back("car");

// 提取视频"test.mp4"中有出现person、car画面的视频片段
// 保存到当前目录的./test_file中
// 并且命名以"pre"做前缀
// 5代表person、car出现的画面, 这些检测目标最大消失时间, 超过5秒则提取为一个片段
// true 表示绘制框框框住检测到的对象
monitor.extract("test.mp4", obj_to_detect, "./test_file", "pre", 5, true)

// 判断"dog.jpg"中是否有dog出现, 并框住检测到的dog, 保存到save_file/predict_dog.jpg下, 返回bool
monitor.detect_something_appear("dog.jpg", "dog", true, "save_file/predict_dog.jpg");

// 计数"dog.jpg"中dog出现的次数, 并框住检测到的dog, 保存到save_file/predict_dog.jpg下, 返回int
monitor.detect_something_appear_times("dog.jpg", "dog", true, "save_file/predict_dog.jpg");

// 统计视频中所有能检测到的目标出现的次数, 并框住检测到的对象, 以及左上角显示计数
cv::VideoCapture capture;
std::map<std::string, int> in_map;

capture.open(test_file);
if (!capture.isOpened())
    printf("文件打开失败");

while (true)
{
    capture >> frame;
    if (frame.empty()) break;
    monitor.detect_all_appear_times(frame, in_map, true, true);
    for (auto &j : in_map)
        std::cout << j.first << " appear: " << j.second << std::endl;
    cv::imshow("window name1", frame);
    cv::waitKey(1);
}

如何编译

这里主要说明如何编译出IntelligentMonitor.dll

环境

参照这篇文章进行配置CUDAcuDNN: https://vonsdite.cn/posts/c6b151e6.html

或者参照官网进行配置CUDAcuDNN: https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html#installwindows

变量设置

  • 设置系统变量OpenCV_ROOT_DIR = opencv 3.4.3 Release版本的build目录
  • 设置系统变量CUDNN = CUDNN所在的目录
  • 检查CUDA_PATHCUDA_PATH V10 0这两个变量是否存在
  • 添加环境变量, 如图(一是CUDA的路径、一是opencv的路径)

进行编译

  1. Visual Studio 2015打开IntelligentMonitor.sln
  2. 修改项目工程为Release x64
  3. 添加CUDA Toolkit Custom Dir目录(根据自己的情况来设置)
  4. 可将C/C++ - 高级 - 编译为 修改为编译为 C++ 代码 (/TP)
  5. 点击生成 - 重新生成IntelligentMonitor (E), 即可生成IntelligentMonitor.dll

成功编译, 真的恭喜你, 我走过太多的坑了! If you finish all the above, then you are good to go.

API参数详细介绍

extract

用于提取视频中出现某些目标对象的片段

函数声明
/*
参数:
    cv::VideoCapture& cap:                      视频捕获对象(请不要传摄像头的)
    std::vector<char *>& obj_to_extract:        需要提取的视频中所包含的目标组
    const char* save_path="./":                 提取出来的视频保存的路径
    const char * prefix=NULL:                   提取出来的视频命名的前缀
    int disappear_thresh=DISAPPEAR_THREASH:     所检测的目标最大消失的阈值, 秒为单位;
                                                比如设置为5,表示5秒内目标没出现, 则分一个片段
    bool draw_box=false:                        是否需要绘制框住目标的框框
    float thresh=DEFAULT_THREASH:               置信度的下限(即分类时若大于该值, 才认定对象属于该分类)
    double* progress_rate=NULL:                 提取的进度率, 多线程的时候可以拿这个来显示进度
    int interval_frame = 0:                     设置每检测一帧后跳过几帧, 加快检测速度

返回值:
    bool:                                       表明提取是否成功
*/
INTELLIGENT_API bool extract(
    cv::VideoCapture& cap,
    std::vector<char *>& obj_to_extract,
    const char* save_path = "./",
    const char * prefix = NULL,
    int disappear_thresh = DISAPPEAR_THREASH,
    bool draw_box = false,
    float thresh = DEFAULT_THREASH,
    double* progress_rate = NULL,
    int interval_frame = 0
);

/*
参数:
    const char* video_file:                     视频文件的路径
    std::vector<char *>& obj_to_extract:        需要提取的视频中所包含的目标组
    const char* save_path="./":                 提取出来的视频保存的路径
    const char * prefix=NULL:                   提取出来的视频命名的前缀
    int disappear_thresh=DISAPPEAR_THREASH:     所检测的目标最大消失的阈值, 秒为单位;
                                                比如设置为5,表示5秒内目标没出现, 则分一个片段
    bool draw_box=false:                        是否需要绘制框住目标的框框
    float thresh=DEFAULT_THREASH:               置信度的下限(即分类时若大于该值, 才认定对象属于该分类)
    double* progress_rate=NULL:                 提取的进度率, 多线程的时候可以拿这个来显示进度
    int interval_frame = 0:                     设置每检测一帧后跳过几帧, 加快检测速度

返回值:
    bool:                                       表明提取是否成功
*/
INTELLIGENT_API bool extract(
    const char* video_file,
    std::vector<char *>& obj_to_extract,
    const char* save_path = "./",
    const char * prefix = NULL,
    int disappear_thresh = DISAPPEAR_THREASH,
    bool draw_box = false,
    float thresh = DEFAULT_THREASH,
    double* progress_rate = NULL,
    int interval_frame = 0
);

detect_all_appear_times

检测画面上所有对象出现的次数

函数声明
/*
参数:
    cv::Mat& mat:                       图片或者视频某帧的矩阵
    std::map<std::string, int>& in_map: 保存检测的对象出现次数的映射表
    bool draw_box=false:                是否绘制框住对象的框
    bool show_times=false:              是否显示检测对象的出现次数
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    无返回值, 次数保存在in_map中
*/
INTELLIGENT_API void detect_all_appear_times(
    cv::Mat& mat,
    std::map<std::string, int>& in_map,
    bool draw_box = false,
    bool show_times = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    const char* image_filename:         图片名
    std::map<std::string, int>& in_map: 保存检测的对象出现次数的映射表
    bool draw_box=false:                是否绘制框住对象的框
    bool show_times=false:              是否显示检测对象的出现次数
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    无返回值, 次数保存在in_map中
*/
INTELLIGENT_API void detect_all_appear_times(
    const char* image_filename,
    std::map<std::string, int>& in_map,
    bool draw_box = false,
    bool show_times = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

detect_somthing_appear_times

检测某物出现的次数, 返回值是int

函数声明
/*
参数:
    cv::Mat& mat:                       图片或者视频某帧的矩阵
    const char* something:              检测的对象
    bool draw_box=false:                是否绘制框住对象的框
    bool show_times=false:              是否显示检测对象的出现次数
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    int:                                表明检测对象出现的次数
*/
INTELLIGENT_API int detect_something_appear_times(
    cv::Mat& mat,
    const char* something,
    bool draw_box = false,
    bool show_times = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    const char* image_filename:         图片名
    const char* something:              检测的对象
    bool draw_box=false:                是否绘制框住对象的框
    bool show_times=false:              是否显示检测对象的出现次数
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    int:                                表明检测对象出现的次数
*/
INTELLIGENT_API int detect_something_appear_times(
    const char* image_filename,
    const char* something,
    bool draw_box = false,
    bool show_times = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    cv::Mat& mat:                       图片或者视频某帧的矩阵
    std::vector<char*>& something:      检测的一组对象
    std::map<std::string, int>& in_map: 记录检测对象出现的次数
    bool draw_box=false:                是否绘制框住对象的框
    bool show_times=false:              是否显示检测对象的出现次数
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    无返回值, 次数保存在in_map中
*/
INTELLIGENT_API void detect_something_appear_times(
    cv::Mat& mat,
    std::vector<char*>& something,
    std::map<std::string, int>& in_map,
    bool draw_box = false,
    bool show_times = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    const char* image_filename:             图片名
    std::vector<char*>& something:          检测的一组对象
    std::map<std::string, int>& in_map:     记录检测对象出现的次数
    bool draw_box=false:                    是否绘制框住对象的框
    bool show_times=false:                  是否显示检测对象的出现次数
    const char* save_file_name=NULL:        保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:           置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    无返回值, 次数保存在in_map中
*/
INTELLIGENT_API void detect_something_appear_times(
    const char* image_filename,
    std::vector<char*>& something,
    std::map<std::string, int>& in_map,
    bool draw_box = false,
    bool show_times = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

detect_something_appear

检测某物是否出现, 返回值是bool

函数声明
/*
参数:
    cv::Mat& mat:                       图片或者视频某帧的矩阵
    const char* something:              检测的对象
    bool draw_box=false:                是否绘制框住对象的框
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    bool:                               表明检测对象是否出现
*/
INTELLIGENT_API bool detect_something_appear(
    cv::Mat& mat,
    const char* something,
    bool draw_box = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    const char* image_filename:         图片名
    const char* something:              检测的对象
    bool draw_box=false:                是否绘制框住对象的框
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    bool:                               表明检测对象是否出现
*/
INTELLIGENT_API bool detect_something_appear(
    const char* image_filename,
    const char* something,
    bool draw_box = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    cv::Mat& mat:                       图片或者视频某帧的矩阵
    std::vector<char*>& something:      检测的一组对象
    bool draw_box=false:                是否绘制框住对象的框
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    bool:                               只要对象组中一个对象出现, 就返回true, 全没出现, 返回false
*/
INTELLIGENT_API bool detect_something_appear(
    cv::Mat& mat,
    std::vector<char*>& something,
    bool draw_box = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

/*
参数:
    const char* image_filename:         图片名
    std::vector<char*>& something:      检测的一组对象
    bool draw_box=false:                是否绘制框住对象的框
    const char* save_file_name=NULL:    保存处理后的图片名, NULL表示不保存
    float thresh=DEFAULT_THREASH:       置信度的下限(即分类时若大于该值, 才认定对象属于该分类)

返回值:
    bool:                               只要对象组中一个对象出现, 就返回true, 全没出现, 返回false
*/
INTELLIGENT_API bool detect_something_appear(
    const char* image_filename,
    std::vector<char*>& something,
    bool draw_box = false,
    const char* save_file_name = NULL,
    float thresh = DEFAULT_THREASH
);

关于dont_show

该API的调用, 需要有以下文件支持:

  • names_file -> 训练yolo权重时, 记录所有分类名的文件, 例如coco.names
  • cfg_file -> 训练yolo权重时, 所使用的cfg文件, 例如yolov3-tiny.cfg
  • weights_file -> 训练yolo权重, 最后得到的权重文件, 例如yolov3-tiny.weights

使用dont_show, 可以提高权重文件利用率 为了灵活使用训练好的权重文件, 可以在names_file中的分类对象前加入dont_show来表示不检测该物体, 以此来减少干扰 比如, 只想检测行人, 就可以在names_file加入dont_show来实现该功能

上图就是只检测人的结果

注意

  • 目录ProgressDiary/保存本项目的进度历程
  • 目录IntelligentMonitor_console_demo_src目录存放的是IntelligentMonitor_console_demo.sln命令行示例程序代码
  • 目录src保存的是本项目IntelligentMonitor.sln的源代码, include3rdparty也是
  • 目录x64是本项目编译生成文件的目录, 还保存着yolo所需的cfgdata目录, yolo权重文件需要到https://pjreddie.com/darknet/yolo/下载

TODO

  • 接下来将进行的事:
    • 成功编译 darknet.exe
    • 修复darknet.exe, 使其成功支持图像识别视频识别摄像头识别(因为我编译出来总是崩溃或出错)
    • 修复视频/摄像头识别结果保存问题
    • 完成智能模块DLL开发
    • 制作MFC演示程序, 做一个好看的界面
    • 获取数据, 训练一个新的权重模型进行检测

题外话

darknet yolov3 - AlexeyAB version提了多个Issue, 帮助作者Bug fixed

Cite

@misc{darknet13,
  author =   {Joseph Redmon},
  title =    {Darknet: Open Source Neural Networks in C},
  howpublished = {\url{http://pjreddie.com/darknet/}},
  year = {2013--2016}
}

intelligentmonitor's People

Contributors

vonsdite avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

intelligentmonitor's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.