DVG-Utils工具,帮你快速构建图像和视频处理管道

磐创AI

    dvg-utils是一组工具,可以帮助你使用OpenCV快速构建图像和视频处理管道。
    在不同的平台和设备上进行计算机视觉和深度学习的实验带来了许多挑战,尤其是当你希望与团队共同维护一个代码库而不需要做重复的工作。从不同设备设置视频流的步骤基本上是一样的,该过程我们需要记录日志,读取配置文件,绘制带有标签的框,保存结果,收集一些指标等,为什么不将这些工作放在一起呢?这就是本文向你介绍dvg-utils的意义。目录dvg-utils简介设置命令行工具捕获视频捕获图像例子指标概要资源dvg-utils简介自从我写了第一篇关于为图像和视频处理创建一个模块化而且简单的管道的文章以来,差不多过去一年了,从那以后我也一直在学习,学到了很多东西。在这段时间里,我做了许多不同的项目,它们总是需要相同的步骤。每个计算机视觉管道都需要以下代码块:设置日志读取配置文件捕获图像或视频流处理数据可视化结果显示结果保存结果收集指标这些代码块中的大多数都是在每个项目中会反复出现的模板代码。为了更轻松,更快速地设置计算机视觉项目,我在S?awomirGilewski的帮助下创建了dvg-utils Python软件包。dvg-utils:https://github.com/jagin/dvg-utilsS?awomirGilewski:https://medium.com/u/1ddaceb8aa71设置在开始之前,我建议使用Python虚拟环境。虚拟环境允许你在系统上运行独立的Python环境,更多请看一下RealPython上的这篇文章。https://realpython.com/python-virtual-environments-a-primer/我假设你正在使用具有Linux或MacOs系统的台式机/笔记本电脑(我没有机会在Windows平台上对其进行测试,但它应该可以运行)。如果你想从Jetson设备运行一些示例,Jetpack的SDK已经安装了OpenCV,你可以跳过pip install opencv-contrib-python这一步骤。对于树莓派用户,请在此文章的帮助下安装OpenCV 。https://www.pyimagesearch.com/2019/09/16/install-opencv-4-on-raspberry-pi-4-and-raspbian-buster/为了浏览库和用法示例,让我们克隆它并安装所需的软件包:$ git clone https://github.com/jagin/dvg-utils.git
    $ cd ./dvg-utils
    $ pip install tqdm pyyaml numpy
    $ pip install opencv-contrib-python
    $ pip install dvg-utils
    命令行工具安装dvg-utils后,你可以访问dvg-utils工具命令:将视频文件转换为一组图像$ dvg-utils v2i -i assets/videos/faces.mp4 -o output --display
    将一组帧图像转换为视频文件$ dvg-utils i2v -i output -o output/my_new_file.avi --display
    绘制指标(我将在本故事的后面部分对此进行详细介绍)对于参数描述,请运行以下命令之一:$ dvg-utils v2i -h
    $ dvg-utils i2v -h
    $ dvg-utils pm -h
    如果可以分别处理每一帧,则将视频转换为图像并返回,你可以并行处理这些帧,然后将它们组合回带有可视注释的视频文件中。捕获视频dvg-utils的强大功能来自于从OpenCV cv2.VideoCapture和树莓派相机支持的所有源捕获视频流,使用单线:video_capture = VideoCapture(conf["videoCapture"]).open()
    技巧是使用conf["videoCapture"],其中包含我们的视频捕获配置的字典,该字典从YAML配置文件中读取,参考:https://medium.com/swlh/python-yaml-configuration-with-environment-variables-parsing-77930f4273ac (向Maria Karanasou致谢,她使用环境变量parsing进行了Python YAML配置)videoCapture:
      capture: file
      file:
        src: assets/videos/cars_driving.mp4
        # You can select the frame range for a video file
        # start_frame: 100
        # end_frame: 500
      camera:
        src: 0
        fourcc: MJPG
        resolution: [640, 480]
        fps: 30
      piCamera:
        src: 0
        resolution: [640, 480]
        framerate: 30
        settings:
          rotation: 180
      stream:
        # Jetson Nano camera stream
        src: >-
          nvarguscamerasrc sensor-id=0 sensor_mode=3 !
          video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12, framerate=(fraction)30/1 !
          nvvidconv flip-method=2 !
          video/x-raw, width=(int)640, height=(int)480, format=(string)BGRx !
          videoconvert !
          video/x-raw, format=(string)BGR !
          appsink
        api_preference: CAP_GSTREAMER
    我们可以定义不同的来源(file,camera,piCamera,stream),但我们想要选择的属性在videoCapture.capture里面(在上面的例子中是assets/videos/cars_driving.mp4文件)。让我们运行./examples/capture_video.py示例以查看实际效果:$ python ./examples/capture_video.py
    INFO: Load configuration from config/capture_video.yml
    INFO: Capturing file: assets/videos/cars_driving.mp4
    INFO: Codec: avc1
    INFO: Resolution: 1280x720
    INFO: FPS: 50.0
    INFO: Capturing...
    INFO: 3000 it, 13.106 s, 0.004 s/it, 228.89 it/s
    3000it [00:13, 228.88it/s]
    
    这个简单的例子是你学习视频处理管道的一个很好的起点。它已经包括:配置文件 config/capture_video.yml,它规定可在不同平台上使用的不同的视频源记录器来显示可用信息:记录器选项在 logger.yml 文件中定义,我们通过 setup_logger() 从 dvgutil 包中调用函数来进行设置,显示带有处理后的帧数和预测的FPS结果:dvgutils.vis带有helper函数的程序包可以很好地放置一些文本,绘制覆盖矩形或调整图像大小,并保留长宽比或填充,保存带注释的输出视频选项:包中有SaveVideo和SaveImage类,dvgutils.modules可轻松保存视频和图像,用于保存有关管道性能的指标选项:通过包中的Metrics类,dvgutils.modules可以收集指标(如迭代时间,每秒迭代次数,每次迭代的秒数),你可以使用dvg-utils pm命令进行绘制。这是完整的选项列表:$ python ./examples/capture_video.py -h
    usage: capture_video.py [-h] [-cf CONF]
                            [-cfo CONF_OVERWRITES [CONF_OVERWRITES ...]]
                            [-o OUTPUT] [--no-display] [--no-progress]
                            [--pipeline] [--metrics METRICS] [--fps FPS]
    optional arguments:
      -h, --help            show this help message and exit
      -cf CONF, --conf CONF
                            Path to the input configuration file (default:
                            config/capture_video.yml)
      -cfo CONF_OVERWRITES [CONF_OVERWRITES ...], --conf-overwrites CONF_OVERWRITES [CONF_OVERWRITES ...]
      -o OUTPUT, --output OUTPUT
                            output video file name
      --no-display          hide display window
      --no-progress         don't display progress
      --pipeline            run as pipeline
      --metrics METRICS     metrics file name
      --fps FPS             output video fps
    之前我提到过,我们可以使用其他输入源来运行管道。如何实现呢?有两种方法:在config/capture_video.yml部分设置capture属性videoCapture到选定的源(file,camera,piCamera,stream)使用选项-cfo videoCapture.capture=<selected_source>执行管道,该选项将覆盖YAML配置中的设置。要使用网络摄像头执行示例,请运行:$ python ./examples/capture_video.py -cfo videoCapture.capture=camera
    如果你在树莓派上运行示例,则需要在树莓派上运行pip install picamera。你可以通过在显示屏上按ESC(只是将其关闭或在终端中按Ctrl + C)来中断该处理,所有这些操作都在dvgutils.modules的ShowImage类中处理。capture_video.py示例包含两个不同的实现方式,用于说明目的。第一个是一个简单的while循环,其中我们使用dvg-utils包中的通用类处理视频帧:# Setup processing modules
    video_capture = VideoCapture(conf["videoCapture"]).open()
    save_video = SaveVideo(args["output"])
    show_image = ShowImage("Video")
    metrics = Metrics().start()
    progress = Progress(disable=not args["progress"])
    while True:
        # Grab the frame
        frame = video_capture.read()
        if frame is None:
            break
        ... # Do some processing and visualization
        save_video(frame)
        show = show_image(frame)
        if not show:
            break
        metrics.update()
        progress.update()
        idx += 1
    第二个基于流水线的概念,在流水线的概念中,我们定义了处理块,并借助Python生成器将数据推送到该流(CaptureVideoPipe是一个生成器,生成的帧数据通过管道步骤进行映射)。# Setup pipeline steps
    capture_video_pipe = CaptureVideoPipe(conf["videoCapture"])
    save_video_pipe = SaveVideoPipe("vis_image", args["output"])
    show_image_pipe = ShowImagePipe("vis_image", "Video")
    metrics_pipe = MetricsPipe()
    progress_pipe = ProgressPipe(disable=not args["progress"])
    # Create pipeline
    pipeline = Pipeline(capture_video_pipe)
    pipeline.map(...)  # Do some processing and visualization
    pipeline.map(save_video_pipe)
    pipeline.map(show_image_pipe)
    pipeline.map(metrics_pipe)
    pipeline.map(progress_pipe)
    # Process pipeline
    pipeline.run()
    创建模块化管道可以使我们有机会在不同项目中重用通用块。捕获图像使用dvg-utils,你可以几乎以与视频帧相同的方式来处理图像。examples/capture_image.py是一个很好的示例。使用以下配置(config/capture_image.yml):imageCapture:
      path: assets/images/friends
      valid_ext: jpg
      #contains: some_string
      # Transform image
      transform:
        resize:
          width: 320
        flip: 1  # 0 - vertical, 1 - horizontal, -1 - vertical and horizontal
    你可以从assets/images/friends目录中读取所有JPG文件,甚至在它们运行你的处理代码之前对其进行转换:$ python ./examples/capture_image.py
    例子dvg-utils包含许多示例,这些示例说明了如何构建图像或视频处理管道。让我们在 examples 文件夹中看看其中的一些示例。对象检测我们可以使用以下命令运行对象检测示例:$ python ./examples/detect_object_video.py
    INFO: Load configuration from config/detect_object_video.yml
    INFO: Capturing file: assets/videos/people_walking.mp4
    INFO: Codec: avc1
    INFO: Resolution: 402x300
    INFO: FPS: 30.0
    INFO: Capturing...
    INFO: 1283 it, 54.567 s, 0.043 s/it, 23.51 it/s
    1283it [00:54, 23.51it/s]
    该示例默认情况下会检测行人。
    
    只需进行少量配置,即可在需要时检测汽车:$ python ./examples/detect_object_video.py -cfo videoCapture.file.src=assets/videos/cars_driving.mp4 objectDetector.caffe.classes=["cars"]
    detect_object_video.py在examples/modules/object_detector/caffe_object_detector.py中使用Caffe MobileNet-SSD模型,并在config/detect_object_video.yml中进行配置(请参阅objectDetector部分)。Caffe MobileNet-SSD:https://github.com/chuanqi305/MobileNet-SSD对象跟踪要跟踪对象,我们需要先对其进行检测。我们已经有了对象检测器,可以在跟踪管道中重用它(此示例需要pip install scipy dlib):$ python ./examples/track_object_video.py
    INFO: Load configuration from config/track_object_video.yml
    INFO: Capturing file: assets/videos/people_walking.mp4
    INFO: Codec: avc1
    INFO: Resolution: 402x300
    INFO: FPS: 30.0
    INFO: Capturing...
    INFO: 1283 it, 11.233 s, 0.009 s/it, 114.21 it/s
    1283it [00:11, 114.17it/s]
    
    在我们的例子中,我们可以使用管道来实现这两种目标跟踪算法。一个基于OpenCV Tracking API (默认使用KCF tracker),第二个基于Dlib包。你可以通过在config/track_object_video.yml中改变objectTracker.tracker 设置来激活它,或者运行:$ python ./examples/track_object_video.py -cfo objectTracker.tracker=dlib
    以下文章对两种跟踪器都有很好的解释:使用OpenCV跟踪对象https://www.learnopencv.com/object-tracking-using-opencv-cpp-python/使用dlib进行对象跟踪https://www.pyimagesearch.com/2018/10/22/object-tracking-with-dlib/这个例子说明了尝试不同算法是多么容易。对象计数目标检测是跟踪的基础,目标跟踪是对被定义的虚拟线中的对象进行计数。这条线可能是商店的入口,而目标可能是一个人,所有这些我们都可以在不触及代码行的情况下进行配置。要查看运行中的对象计数器,请执行以下操作:$ python ./examples/count_object_video.py
    INFO: Load configuration from config/count_object_video.yml
    INFO: Capturing file: assets/videos/people_walking.mp4
    INFO: Codec: avc1
    INFO: Resolution: 402x300
    INFO: FPS: 30.0
    INFO: Capturing...
    INFO: 1283 it, 11.631 s, 0.009 s/it, 110.31 it/s
    1283it [00:11, 110.27it/s]  
    
    本文很好地描述了此示例的思想:OpenCV人群计数https://www.pyimagesearch.com/2018/08/13/opencv-people-counter/但我将其扩展为可以在图像的任何位置定义任何行(多亏有dvgutils.vis)