openvino系列 18. 通过OpenVINO和OpenCV实现实时的物体识别(RTSP,USB视频读取以及视频文件读取)

这篇具有很好参考价值的文章主要介绍了openvino系列 18. 通过OpenVINO和OpenCV实现实时的物体识别(RTSP,USB视频读取以及视频文件读取)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

openvino系列 18. 通过OpenVINO和OpenCV实现实时的物体识别(RTSP,USB视频读取以及视频文件读取)

在这个案例中,我们将OpenVINO的SSDLite MobileNetV2物体识别算法在视频流中进行推理。另外,如何通过多线程的方式进行视频读取,以及视频分析,这段代码是很值得一学。此案例涉及:

  • 读取 Tensorflow 物体识别预训练模型
  • 将 Tensorflow 模型转化为 IR 中间件
  • 通过 OpenCV 实现视频但一个单独线程读取,主线程调用,在需要的时候(这段代码很值得一读)
  • 实时物体识别结果呈现,实现USB,RTSP视频流,以及视频文件的视频分析。

环境描述:

  • 本案例运行环境:Win10,9代i7笔记本
  • IDE:VSCode
  • openvino版本:2022.1
  • 代码链接


0 代码的运行

将Gitee代码下载下来后,进入13-realtime-objectdetection,你需要新建一个虚拟环境,并下载相关的依赖(关于OpenVINO的安装和使用,这里就不再赘述,需要了解的同学可以直接打开Gitee的链接,在前几个章节或主路径下的README文件有介绍)。进入虚拟环境后,直接在terminal中运行python realtime-objectdetection.py即可。如果你对于一步步调试感兴趣,可以看一下realtime-objectdetection.ipynb

1 关于SSDLite MobileNetV2

我们一如既往地先看一下这个预训练模型。Intel的Open Model Zoo中提供了许多与训练模型,感兴趣的同学可以去看看。SSDLite MobileNetV2模型一看便知是SSDLite+MobileNetV2组成的一个物体识别模型。概念我们就不赘述了,描述一下其IR模型的输入输出(这里我们需要先下载TensorFlow版本的原始模型,再转换成IR模型):

输入图像的大小是1, 300, 300, 3,格式为[B, H, W, C],即[batch size,image height,image width,number of channels],图像为BGR格式;
模型输出的尺寸是1, 1, N, 7,N为识别到的框框数量,7指的是[image_id, label, conf, x_min, y_min, x_max, y_max]

2 模型的下载,转化和加载

这里直接附上代码,这里对于模型的下载,转化和加载做具体解释,感兴趣的同学可以参见之前的博客或代码,比如4-model-optimizer-convert2IR

import collections
import os
import sys
import time

import cv2
import numpy as np
from IPython import display
from openvino.runtime import Core
import threading

'''
下载ssdlite_mobilenet_v2原模型,并将其放入model文件夹中。
'''
base_model_dir = "model"
# model name as named in Open Model Zoo
model_name = "ssdlite_mobilenet_v2"

download_command = f"omz_downloader " \
                   f"--name {model_name} " \
                   f"--output_dir {base_model_dir} " \
                   f"--cache_dir {base_model_dir}"
! $download_command
print("1 - Download ssdlite_mobilenet_v2 original TensorFlow model.")

'''
将TensorFlow模型转化为IR模型,这里我们的模型精度调整为FP16,默认是FP32
'''

precision = "FP16"

# output path for the conversion
converted_model_path = f"model/public/{model_name}/{precision}/{model_name}.xml"

if not os.path.exists(converted_model_path):
    convert_command = f"omz_converter " \
                      f"--name {model_name} " \
                      f"--download_dir {base_model_dir} " \
                      f"--precisions {precision}"
    ! $convert_command
print("2 - Transform original model into IR format.")

'''
Load the Model
我们将模型下载下来并转换成IR模型后,加载模型
'''
# initialize inference engine
ie_core = Core()
# read the network and corresponding weights from file
model = ie_core.read_model(model=converted_model_path)
# compile the model for the CPU (you can choose manually CPU, GPU, MYRIAD etc.)
# or let the engine choose the best available device (AUTO)
compiled_model = ie_core.compile_model(model=model, device_name="CPU")
print("3 - Load model and compile model.")
# get input and output nodes
input_layer = compiled_model.input(0)
output_layer = compiled_model.output(0)
print("- Input layer info: ", input_layer)
print("- Output layer info: ", output_layer)
# get input size
height, width = list(input_layer.shape)[1:3]

Terminal中打印:

################|| Downloading ssdlite_mobilenet_v2 ||################
========== Retrieving model\public\ssdlite_mobilenet_v2\ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz from the cache
========== Unpacking model\public\ssdlite_mobilenet_v2\ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz

1 - Download ssdlite_mobilenet_v2 original TensorFlow model.
2 - Transform original model into IR format.
3 - Load model and compile model.
- Input layer info:  <ConstOutput: names[image_tensor, image_tensor:0] shape{1,300,300,3} type: u8>
- Output layer info:  <ConstOutput: names[detection_boxes, detection_boxes:0] shape{1,1,100,7} type: f32>

3 VideoPlayer 类

这一部分就是我觉得很值得一看的地方了。VideoPlayer 类中,我们通过 cv2.VideoCapture 读取每一帧视频数据,新建一个线程,这个线程负责按照指定的FPS读取视频数据。而主线程需要的时候,可以通过 next 函数调用下一帧图像。这里的代码写的非常好,因为如果我们将推理和读每一帧图像数据放在同一个线程,就可能会发生丢帧导致的各种问题,比如视频卡顿,延迟,甚至是延迟时间太长导致的程序“奔溃”。
三种视频输入方式在source的不同写法:

  • 视频文件:比如,…/201-vision-monodepth/data/Coco Walking in Berkeley.mp4
  • USB摄像头:比如,0(取决于接口的值,可能是0,或者1,或者其他)
  • RTSP流:比如,rtsp://192.168.1.2:8080/out.h264

VIdeoPlayer 类相关的代码如下:

class VideoPlayer:
    """
    Custom video player to fulfill FPS requirements. You can set target FPS and output size,
    flip the video horizontally or skip first N frames.

    :param source: Video source. It could be either camera device or video file. For rtsp camera, format should be something like: rtsp://192.168.1.2:8080/out.h264
    :param size: Output frame size.
    :param flip: Flip source horizontally.
    :param fps: Target FPS.
    :param skip_first_frames: Skip first N frames.
    """

    def __init__(self, source, size=None, flip=False, fps=None, skip_first_frames=0):
        self.__cap = cv2.VideoCapture(source)
        if not self.__cap.isOpened():
            raise RuntimeError(
                f"Cannot open {'camera' if isinstance(source, int) else ''} {source}"
            )
        # skip first N frames
        self.__cap.set(cv2.CAP_PROP_POS_FRAMES, skip_first_frames)
        # fps of input file
        self.__input_fps = self.__cap.get(cv2.CAP_PROP_FPS)
        if self.__input_fps <= 0:
            self.__input_fps = 60
        # target fps given by user
        self.__output_fps = fps if fps is not None else self.__input_fps
        self.__flip = flip
        self.__size = None
        self.__interpolation = None
        if size is not None:
            self.__size = size
            # AREA better for shrinking, LINEAR better for enlarging
            self.__interpolation = (
                cv2.INTER_AREA
                if size[0] < self.__cap.get(cv2.CAP_PROP_FRAME_WIDTH)
                else cv2.INTER_LINEAR
            )
        # first frame
        _, self.__frame = self.__cap.read()
        self.__lock = threading.Lock()
        self.__thread = None
        self.__stop = False

    """
    Start playing.
    """

    def start(self):
        self.__stop = False
        self.__thread = threading.Thread(target=self.__run, daemon=True)
        self.__thread.start()

    """
    Stop playing and release resources.
    """

    def stop(self):
        self.__stop = True
        if self.__thread is not None:
            self.__thread.join()
        self.__cap.release()

    def __run(self):
        prev_time = 0
        while not self.__stop:
            t1 = time.time()
            ret, frame = self.__cap.read()
            if not ret:
                break

            # fulfill target fps
            if 1 / self.__output_fps < time.time() - prev_time:
                prev_time = time.time()
                # replace by current frame
                with self.__lock:
                    self.__frame = frame

            t2 = time.time()
            # time to wait [s] to fulfill input fps
            wait_time = 1 / self.__input_fps - (t2 - t1)
            # wait until
            time.sleep(max(0, wait_time))

        self.__frame = None

    """
    Get current frame.
    """

    def next(self):
        with self.__lock:
            if self.__frame is None:
                return None
            # need to copy frame, because can be cached and reused if fps is low
            frame = self.__frame.copy()
        if self.__size is not None:
            frame = cv2.resize(frame, self.__size, interpolation=self.__interpolation)
        if self.__flip:
            frame = cv2.flip(frame, 1)
        return frame

除此之外,还有一些可视化相关的函数。我们列出所有可用的类并为它们创建颜色。 然后,在后处理阶段,我们将归一化坐标为[0, 1]的框转换为像素坐标为[0, image_size_in_px]的框。之后,我们使用非最大抑制来删除重叠框以及低于阈值为0.5的框。最后,我们可以将剩下的绘制框和标签绘制在视频中。

# https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/
classes = [
    "background", "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
    "truck", "boat", "traffic light", "fire hydrant", "street sign", "stop sign",
    "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant",
    "bear", "zebra", "giraffe", "hat", "backpack", "umbrella", "shoe", "eye glasses",
    "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
    "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
    "plate", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
    "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair",
    "couch", "potted plant", "bed", "mirror", "dining table", "window", "desk", "toilet",
    "door", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven",
    "toaster", "sink", "refrigerator", "blender", "book", "clock", "vase", "scissors",
    "teddy bear", "hair drier", "toothbrush", "hair brush"
]

# colors for above classes (Rainbow Color Map)
colors = cv2.applyColorMap(
    src=np.arange(0, 255, 255 / len(classes), dtype=np.float32).astype(np.uint8),
    colormap=cv2.COLORMAP_RAINBOW,
).squeeze()
print("4 - 我们列出所有可用的类并为它们创建颜色。")

print("5 - 我们使用非最大抑制来删除重叠框以及低于阈值为0.5的框。最后,我们可以将剩下的绘制框和标签绘制在视频中。")
def process_results(frame, results, thresh=0.6):
    # size of the original frame
    h, w = frame.shape[:2]
    # results is a tensor [1, 1, 100, 7]
    results = results.squeeze()
    boxes = []
    labels = []
    scores = []
    for _, label, score, xmin, ymin, xmax, ymax in results:
        # create a box with pixels coordinates from the box with normalized coordinates [0,1]
        boxes.append(
            tuple(map(int, (xmin * w, ymin * h, (xmax - xmin) * w, (ymax - ymin) * h)))
        )
        labels.append(int(label))
        scores.append(float(score))

    # apply non-maximum suppression to get rid of many overlapping entities
    # see https://paperswithcode.com/method/non-maximum-suppression
    # this algorithm returns indices of objects to keep
    indices = cv2.dnn.NMSBoxes(
        bboxes=boxes, scores=scores, score_threshold=thresh, nms_threshold=0.6
    )

    # if there are no boxes
    if len(indices) == 0:
        return []

    # filter detected objects
    return [(labels[idx], scores[idx], boxes[idx]) for idx in indices.flatten()]


def draw_boxes(frame, boxes):
    for label, score, box in boxes:
        # choose color for the label
        color = tuple(map(int, colors[label]))
        # draw box
        x2 = box[0] + box[2]
        y2 = box[1] + box[3]
        cv2.rectangle(img=frame, pt1=box[:2], pt2=(x2, y2), color=color, thickness=3)

        # draw label name inside the box
        cv2.putText(
            img=frame,
            text=f"{classes[label]} {score:.2f}",
            org=(box[0] + 10, box[1] + 30),
            fontFace=cv2.FONT_HERSHEY_COMPLEX,
            fontScale=frame.shape[1] / 1000,
            color=color,
            thickness=1,
            lineType=cv2.LINE_AA,
        )

    return frame

4 主程序

最后,我们附上主程序,即将物体识别放入视频流中处理并可视化的主要程序。文章来源地址https://www.toymoban.com/news/detail-432224.html

'''
主程序
- source: 这里支持三种视频输入方式:
    - 视频文件:../201-vision-monodepth/data/Coco Walking in Berkeley.mp4
    - USB摄像头:0(取决于接口的值,可能是0,或者1,或者其他)
    - RTSP流:rtsp://192.168.1.2:8080/out.h264
- flip: 一些摄像头出来的图象是倒的,这里需要flip一下。
- use_popup: 如果我们是在.py下运行,需要弹窗显示视频结果,那么设置为True,如果我们是在notebook中运行,设置为false。
'''
def run_object_detection(source=0, flip=False, use_popup=False, skip_first_frames=0):
    player = None
    try:
        # create video player to play with target fps
        player = VideoPlayer(
            source=source, flip=flip, fps=25, skip_first_frames=skip_first_frames
        )
        # start capturing
        player.start()
        if use_popup:
            title = "Press ESC to Exit"
            cv2.namedWindow(
                winname=title, flags=cv2.WINDOW_GUI_NORMAL | cv2.WINDOW_AUTOSIZE
            )

        processing_times = collections.deque()
        while True:
            # grab the frame
            frame = player.next()
            if frame is None:
                print("Source ended")
                break
            # if frame larger than full HD, reduce size to improve the performance
            scale = 1280 / max(frame.shape)
            if scale < 1:
                frame = cv2.resize(
                    src=frame,
                    dsize=None,
                    fx=scale,
                    fy=scale,
                    interpolation=cv2.INTER_AREA,
                )

            # resize image and change dims to fit neural network input
            input_img = cv2.resize(
                src=frame, dsize=(width, height), interpolation=cv2.INTER_AREA
            )
            # create batch of images (size = 1)
            input_img = input_img[np.newaxis, ...]

            # measure processing time

            start_time = time.time()
            # get results
            results = compiled_model([input_img])[output_layer]
            stop_time = time.time()
            # get poses from network results
            boxes = process_results(frame=frame, results=results)

            # draw boxes on a frame
            frame = draw_boxes(frame=frame, boxes=boxes)

            processing_times.append(stop_time - start_time)
            # use processing times from last 200 frames
            if len(processing_times) > 200:
                processing_times.popleft()

            _, f_width = frame.shape[:2]
            # mean processing time [ms]
            processing_time = np.mean(processing_times) * 1000
            fps = 1000 / processing_time
            cv2.putText(
                img=frame,
                text=f"Inference time: {processing_time:.1f}ms ({fps:.1f} FPS)",
                org=(20, 40),
                fontFace=cv2.FONT_HERSHEY_COMPLEX,
                fontScale=f_width / 1000,
                color=(0, 0, 255),
                thickness=1,
                lineType=cv2.LINE_AA,
            )

            # use this workaround if there is flickering
            if use_popup:
                cv2.imshow(winname=title, mat=frame)
                key = cv2.waitKey(1)
                # escape = 27
                if key == 27:
                    break
            else:
                # encode numpy array to jpg
                _, encoded_img = cv2.imencode(
                    ext=".jpg", img=frame, params=[cv2.IMWRITE_JPEG_QUALITY, 100]
                )
                # create IPython image
                i = display.Image(data=encoded_img)
                # display the image in this notebook
                display.clear_output(wait=True)
                display.display(i)
    # ctrl-c
    except KeyboardInterrupt:
        print("Interrupted")
    # any different error
    except RuntimeError as e:
        print(e)
    finally:
        if player is not None:
            # stop capturing
            player.stop()
        if use_popup:
            cv2.destroyAllWindows()

到了这里,关于openvino系列 18. 通过OpenVINO和OpenCV实现实时的物体识别(RTSP,USB视频读取以及视频文件读取)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【模型部署 01】C++实现GoogLeNet在OpenCV DNN、ONNXRuntime、TensorRT、OpenVINO上的推理部署

    深度学习领域常用的基于CPU/GPU的推理方式有OpenCV DNN、ONNXRuntime、TensorRT以及OpenVINO。这几种方式的推理过程可以统一用下图来概述。整体可分为模型初始化部分和推理部分,后者包括步骤2-5。 以GoogLeNet模型为例,测得几种推理方式在推理部分的耗时如下: 结论: GPU加速首选

    2024年02月06日
    浏览(38)
  • 【模型部署 01】C++实现分类模型(以GoogLeNet为例)在OpenCV DNN、ONNXRuntime、TensorRT、OpenVINO上的推理部署

    深度学习领域常用的基于CPU/GPU的推理方式有OpenCV DNN、ONNXRuntime、TensorRT以及OpenVINO。这几种方式的推理过程可以统一用下图来概述。整体可分为模型初始化部分和推理部分,后者包括步骤2-5。 以GoogLeNet模型为例,测得几种推理方式在推理部分的耗时如下: 结论: GPU加速首选

    2024年02月06日
    浏览(42)
  • OpenVINO 2022.3之二:Windows安装OpenVINO

    OpenVINO 2022.3之二:Windows安装OpenVINO 安装下载页 Download Intel® Distribution of OpenVINO™ Toolkit OpenVINO安装包分为两个选项: OpenVINO Runtime 和 OpenVINO Development Tools 。 OpenVINO Runtime包含用于在处理器设备上运行机器学习模型推理的核心库。 OpenVINO Development Tools是一组用于处理OpenVINO和O

    2024年02月11日
    浏览(209)
  • OpenVINO 2022.3实战六:NNCF 实现 YOLOv5 模型 INT8 量化

    使用OpenVINO模型优化器将YOLOv5模型转换为OpenVINO IR格式,以便在Intel硬件上进行推理。 下载yolov5代码 ultralytics/yolov5 导出模型为onnx模型,接着使用mo导出openvino fp32和fp16模型 将训练数据集准备成可用于量化的格式。 配置量化管道,例如选择适当的量化算法和设置目标精度。 在

    2024年02月08日
    浏览(32)
  • 【OpenVINO 】在 MacOS 上编译 OpenVINO C++ 项目

    前言 英特尔公司发行的模型部署工具OpenVINO™模型部署套件,可以实现在不同系统环境下运行,且发布的OpenVINO™ 2023最新版目前已经支持MacOS系统并同时支持在苹果M系列芯片上部署模型。在该项目中,我们将向大家展示如何在MacOS系统、M2芯片的Macbook Air电脑上,展示使用Op

    2024年02月02日
    浏览(30)
  • 什么是OpenVino?以及如何使用OpenVino运行yolo

    目录 Openvino简介 如何使用它? 构建源代码 Openvino IR模型 第一个Openvino示例 C语言示例 C++示例 使用OpenVino跑Yolo模型 Openvino 是由 Intel 开发的专门用于优化和部署人工智能推理的半开源的工具包,主要用于对深度 推理做优化 。 Openvino内部集成了 Opencv 、 TensorFlow 模块,除此之外

    2023年04月26日
    浏览(46)
  • 【OpenVINO】 使用 OpenVINO CSharp API 部署 PaddleOCR 项目介绍

    前言:   在之前的项目中,我们已经使用 OpenVINO TM CSharp API 部署 PaddleOCR 全系列模型,但随着PaddleOCRv4版本发布以及OpenVINO CSharp API版本迭代,上一版本的项目已经不再适用。因此在推出的最新项目中,已经完成了对PaddleOCRv4的匹配,并且采用了最新版本的 OpenVINO TM CSharp API,

    2024年02月03日
    浏览(32)
  • OpenVINO 2022.3之七:OpenVINO 预处理API提升模型推理性能

    OpenVINO™ 2022.3 提供OpenVINO™ Runtime原生的用于数据预处理的API函数。 如果没有预处理API,那么输入数据的预处理操作只能放在CPU上实现,CPU完成数据预处理后,再将预处理后的数据传给iGPU、VPU等AI加速计算设备进行推理计算。 有了预处理API后,就能将预处理操作集成到在模型

    2024年02月04日
    浏览(200)
  • 【OpenVINO】基于 OpenVINO C# API 部署 RT-DETR 模型

      RT-DETR是在DETR模型基础上进行改进的,一种基于 DETR 架构的实时端到端检测器,它通过使用一系列新的技术和算法,实现了更高效的训练和推理,在前文我们发表了《基于 OpenVINO™ Python API 部署 RT-DETR 模型 | 开发者实战》和《基于 OpenVINO™ C++ API 部署 RT-DETR 模型 | 开发者实

    2024年01月23日
    浏览(40)
  • 【OpenVINO】基于 OpenVINO C++ API 部署 RT-DETR 模型

      RT-DETR是在DETR模型基础上进行改进的,一种基于 DETR 架构的实时端到端检测器,它通过使用一系列新的技术和算法,实现了更高效的训练和推理,在前文我们发表了《基于 OpenVINO™ Python API 部署 RT-DETR 模型 | 开发者实战》,在该文章中,我们基于OpenVINO™ Python API 向大家展

    2024年01月22日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包