一步一步学OAK之一: Hello World(使用DepthAI Python API 显示彩色视频流)

news2024/11/16 11:50:57

作为编程世界的传统入门仪式,我们这里也以Hello World来命名我们的第一个项目,其实我们这个项目与Hello World没有半毛钱关系。
在这个程序中,我们使用DepthAI Python API来一步步实现显示OAK相机彩色视频流,并捕捉物体的功能

目录

  • 环境要求:
  • 创建程序
    • Setup 1: 创建文件
    • Setup 2: 安装依赖
    • Setup 3: 导入需要的包
    • Setup 4: 定义 pipeline
    • Setup 5:添加ColorCamera节点
    • Setup 6:定义移动网络检测网络节点
    • Setup 7:将彩色相机预览输出连接到神经网络输入
    • Setup 8:创建XLinkOut节点
    • Setup 9:初始化DepthAI 设备
    • Setup 10:添加辅助对象
    • Setup 11:定义两个变量,用于存储数据
    • Setup 12:定义辅助函数frameNorm
    • Setup 13:开始主程序循环
      • 定义变量从队列获取数据
      • 从rgb相机接收帧
      • 接收神经网络的结果
      • 显示结果
      • 终止程序
    • Setup 14:运行程序

环境要求:

  • Python >=3.6
  • DepthAI Python API
  • cv2,blobconverternumpy Python模块

创建程序

Setup 1: 创建文件

  • 创建一个文件夹,新建1-hello-world文件夹
  • 用vscode打开该文件夹
  • 新建一个hello_world.py 文件

Setup 2: 安装依赖

安装依赖前需要先创建和激活虚拟环境,我这里已经创建了虚拟环境OAKenv,在终端中输入cd…退回到OAKenv的根目录,输入 OAKenv\Scripts\activate激活虚拟环境

安装pip依赖项:

pip install numpy opencv-python depthai blobconverter --user

使用pip命令安装四个Python包:numpy、opencv-python、depthai和blobconverter。这些包的安装是针对当前用户进行的,并且使用了--user参数,表示将这些包安装到当前用户的本地环境中,而不是系统环境。

这四个包的作用如下:

  1. numpy:是用于进行科学计算和数值操作的Python库。它提供了高性能的多维数组对象和用于处理这些数组的函数。
  2. opencv-python:是OpenCV(开放源代码计算机视觉库)的Python接口。它提供了丰富的图像处理和计算机视觉功能,如图像读取、处理、分析、特征提取等。
  3. depthai:是一个用于深度学习和计算机视觉的库,特别用于使用DepthAI硬件加速器进行推理。DepthAI是一个结合了AI摄像头和嵌入式神经网络加速器的技术,可以提供实时的深度感知和智能分析功能。
  4. blobconverter:是一个用于转换深度学习模型的工具,用于将模型转换为可以在目标设备上运行的二进制格式。它能够将不同框架(如TensorFlow、PyTorch等)训练的模型转换为便于在特定设备上进行推理的格式。

Setup 3: 导入需要的包

导入项目需要的包

import numpy as np #numpy - 处理depthai返回的数据包数据
import cv2 # opencv -显示视频流
import depthai # depthai - 调用depthai 访问相机及其数据包进行图像采集
import blobconverter # blobconverter - 编译并下载MyriadX神经网络Blob

Setup 4: 定义 pipeline

DepthAI的任何动作,无论是神经推理还是彩色相机输出,都需要定义一个管道,包括与我们的需求相对应的节点和连接。

在这里,我们希望看到彩色相机的帧,以及在它们上面运行的简单神经网络。

创建一个空的pipeline对象

# 创建一个空的pipeline对象
pipeline = depthai.Pipeline()

Setup 5:添加ColorCamera节点

现在,我们将添加的第一个节点是ColorCamera。

cam_rgb = pipeline.create(depthai.node.ColorCamera)
cam_rgb.setPreviewSize(300,300)
cam_rgb.setInterleaved(False)

上面这段代码创建一个名为cam_rgbColorCamera节点,并设置预览的尺寸为300x300像素,并将图像的存储格式设置为非交错格式。

  1. pipeline.create(depthai.node.ColorCamera):使用depthai.node.ColorCamera创建一个ColorCamera节点,作为图像采集的源。pipeline是一个DepthAI的流水线(pipeline)对象。

  2. cam_rgb.setPreviewSize(300, 300):设置cam_rgb节点的预览大小为300x300像素。这意味着从相机采集的图像会被调整为300x300大小以进行显示或进一步处理。

  3. cam_rgb.setInterleaved(False):将图像的存储格式设置为非交错(non-interleaved)格式。交错格式指的是图像数据存储时将不同颜色通道的像素交错排列,而非交错格式则将每个颜色通道的像素按顺序存储。

这段代码的目的是配置cam_rgb节点,以便从相机采集RGB图像,并在后续处理中使用。

Setup 6:定义移动网络检测网络节点

接下来,定义一个具有mobilenetssd网络的MobileNetDetectionNetwork节点。此示例的blob文件将使用blobconverter工具自动编译和下载。blobconverter.from_zoo()函数返回模型的Path,因此我们可以直接将其放入detection_nn.setBlobPath()函数中。有了这个节点,nn的输出将在设备端进行解析,我们将收到一个现成的检测对象。为了使其正常工作,我们还需要设置置信阈值来过滤不正确的结果

detection_nn = pipeline.create(depthai.node.MobileNetDetectionNetwork)
# Set path of the blob (NN model). We will use blobconverter to convert&download the model
# detection_nn.setBlobPath("/path/to/model.blob")
detection_nn.setBlobPath(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6))
detection_nn.setConfidenceThreshold(0.5)

上面这段代码创建一个名为detection_nnMobileNetDetectionNetwork节点,并配置它用于目标检测的设置。

  1. pipeline.create(depthai.node.MobileNetDetectionNetwork):使用depthai.node.MobileNetDetectionNetwork创建一个MobileNetDetectionNetwork节点,用于目标检测。
  2. detection_nn.setBlobPath(blobconverter.from_zoo(name='mobilenet-ssd', shaves=6)):设置模型文件路径。这里使用了blobconverter.from_zoo()函数来从预训练模型库中下载并转换模型。name='mobilenet-ssd'表示选择了MobileNet-SSD模型,shaves=6表示选择了使用6个shave核心进行模型推理。
  3. detection_nn.setConfidenceThreshold(0.5):设置目标检测的置信度阈值为0.5。这意味着只有置信度大于0.5的目标才会被认为是有效的。

这段代码的目的是配置detection_nn节点,使其使用MobileNet-SSD目标检测模型,并设置置信度阈值为0.5。在后续的流水线运行中,该节点将使用模型对从相机采集的图像进行目标检测。

Setup 7:将彩色相机预览输出连接到神经网络输入

cam_rgb.preview.link(detection_nn.input)

这行代码将cam_rgb节点的预览输出链接到detection_nn节点的输入。

cam_rgb.preview表示cam_rgb节点的预览输出端口,通过这个端口可以获取到从相机采集的图像预览数据。.link(detection_nn.input)表示将cam_rgb.previewdetection_nn节点的输入端口进行链接,将图像数据传递给detection_nn节点进行目标检测。

这行代码的目的是建立数据流通路,将从相机采集的图像预览数据传递给detection_nn节点进行目标检测,并在后续流水线运行中触发节点的处理。

Setup 8:创建XLinkOut节点

现在,我们需要接收彩色相机帧和神经网络推理结果——因为这些结果是在设备上产生的,所以需要将它们传输到我们的机器(主机,这里是我的计算机)。设备和主机之间的通信由XLink处理,在这里,由于我们希望从设备到主机接收数据,我们将使用XLinkOut节点

xout_rgb = pipeline.create(depthai.node.XLinkOut)
xout_rgb.setStreamName("rgb")
cam_rgb.preview.link(xout_rgb.input)

xout_nn = pipeline.create(depthai.node.XLinkOut)
xout_nn.setStreamName("nn")
detection_nn.out.link(xout_nn.input)

这段代码创建了两个XLinkOut节点,并将节点连接到相应的输入和输出。

  1. xout_rgb = pipeline.create(depthai.node.XLinkOut):创建一个XLinkOut节点,命名为xout_rgb,用于输出相机采集的图像数据。

  2. xout_rgb.setStreamName("rgb"):设置xout_rgb节点的输出流名称为"rgb"。

  3. cam_rgb.preview.link(xout_rgb.input):将cam_rgb节点的预览输出链接到xout_rgb节点的输入,以实现将图像数据传递给xout_rgb节点进行输出。

  4. xout_nn = pipeline.create(depthai.node.XLinkOut):创建另一个XLinkOut节点,命名为xout_nn,用于输出目标检测的结果数据。

  5. xout_nn.setStreamName("nn"):设置xout_nn节点的输出流名称为"nn"。

  6. detection_nn.out.link(xout_nn.input):将detection_nn节点的输出链接到xout_nn节点的输入,以实现将目标检测结果数据传递给xout_nn节点进行输出。

这段代码的目的是创建两个XLinkOut节点,其中一个用于输出相机采集的图像数据,另一个用于输出目标检测的结果数据。通过链接节点之间的输入和输出,可以将数据流传递给对应的节点,并在流水线运行中实时输出结果。

Setup 9:初始化DepthAI 设备

定义了管道后,我们现在可以用管道初始化设备并启动它

with depthai.Device(pipeline) as device:

这里需要注意:默认情况下,DepthAI作为USB3设备访问。如果你想通过USB2进行通信,可以使用以下代码初始化DepthAI

device = depthai.Device(pipeline, usb2Mode=True)

从这里开始,管道将在设备上运行,产生我们要求的结果。让我们能够捕获它们

Setup 10:添加辅助对象

由于XLinkOut节点已经在管道中定义,我们现在将定义一个主机端输出队列来访问生成的结果

    q_rgb = device.getOutputQueue("rgb")
    q_nn = device.getOutputQueue("nn")

这段代码从设备中获取两个输出队列,分别对应图像数据和目标检测结果数据。

  1. q_rgb = device.getOutputQueue("rgb"):从设备中获取名为"rgb"的输出队列,用于接收相机采集的图像数据。这样,通过获取输出队列,可以从设备中获取实际的图像数据。

  2. q_nn = device.getOutputQueue("nn"):从设备中获取名为"nn"的输出队列,用于接收目标检测的结果数据。这样,通过获取输出队列,可以从设备中获取实际的目标检测结果数据。

通过获取输出队列,可以在Pipeline运行期间实时获取图像数据和目标检测结果数据,以便进行进一步的处理和使用。

Setup 11:定义两个变量,用于存储数据

    frame = None
    detections = []

初始化了两个变量:

  1. frame = Noneframe是一个用于存储图像帧数据的变量,初始值为None。这个变量可以被赋予实际的图像数据,用于后续的处理或显示。
  2. detections = []detections是一个空列表,用于存储目标检测结果。目标检测算法的输出结果通常是一组检测到的目标的框的坐标、类别标签和置信度等信息。这个空列表可以用于存储这些检测结果,以供后续使用。

Setup 12:定义辅助函数frameNorm

将边界框坐标从归一化的范围转换为实际的像素位置

由于神经网络的实现细节,推理结果中的边界框坐标表示为介于0和1之间的浮点数范围内 - 相对于帧的宽度/高度(例如,如果图像的宽度为200像素,并且神经网络nn返回的x_min坐标等于0.2,则意味着实际(归一化)的x_min坐标为40像素)。

所以需要定义一个辅助函数frameNorm,它将把这些在<0…1>范围的值转换为实际的像素位置。

    def frame_norm(frame,bbox):
        normVals = np.full(len(bbox),frame.shape[0])
        normVals[::2] = frame.shape[1]
        return (np.clip(np.array(bbox),0,1)*normVals).astype(int)

这段代码定义了一个名为frameNorm的函数,它接受两个参数:frame和bbox。它的作用是将边界框坐标从归一化的范围转换为实际的像素位置。

首先,函数创建了一个具有与bbox长度相同的数组normVals,其初始值为帧的高度(frame.shape[0])。数组中的偶数索引位置对应边界框的宽度值,奇数索引位置对应边界框的高度值。

接下来,通过将normVals[::2]值设置为frame.shape[1],将宽度值设置为frame的宽度。

然后,将bbox数组剪裁到范围[0, 1]之间,并将其乘以normVals数组,以将归一化的坐标值缩放到实际的像素位置。最后,使用astype将结果转换为整数类型。

最终,函数返回转换后的bbox,即实际的像素位置坐标。

Setup 13:开始主程序循环

准备好上面的一切后,我们就可以开始主程序循环了

    while True:

定义变量从队列获取数据

在这个循环中,首先要做的是从nn节点和彩色相机获取最新结果

        in_rgb = q_rgb.tryGet()
        in_nn = q_nn.tryGet()

这段代码中,in_rgb = q_rgb.tryGet()in_nn = q_nn.tryGet()是从队列q_rgbq_nn中尝试获取数据。

q_rgb.tryGet()将尝试从q_rgb队列中获取数据,并将获取到的数据赋值给in_rgb变量。如果队列中没有可用的数据,它将返回None

同样地,q_nn.tryGet()将尝试从q_nn队列中获取数据,并将获取到的数据赋值给in_nn变量。如果队列中没有可用的数据,它也将返回None

无论是来自rgb相机还是神经网络nn,都将以1D阵列的形式提供,因此它们都需要转换才能用于显示(我们已经定义了所需的转换之一-frameNorm函数)

从rgb相机接收帧

首先,从rgb相机接收帧,我们使用getCvFrame命令

        if in_rgb is not None:
            frame = in_rgb.getCvFrame()

在上面的代码中,我们首先检查in_rgb是否为空。如果不为空,我们通过getCvFrame()方法获取从RGB相机传输过来的一帧图像,并将其赋值给变量frame。这样我们就可以使用frame变量在后续进行图像处理或显示。

接收神经网络的结果

其次,我们接收神经网络的结果。默认MobileNetSSD结果有7个字段,每个字段分别为image_id、label、confidence、x_min、y_min、x_max、y_max,通过访问检测阵列,我们接收到允许我们访问这些字段的检测对象

        if in_nn is not None:
            detections = in_nn.detections

在上面的代码中,我们首先检查in_nn是否为空。如果不为空,我们获取in_nn中的检测结果,并将其赋值给变量detections。这些检测结果可能包括物体类别、位置、置信度等信息,可以用于后续的应用或显示。

in_nn.detections代表从神经网络模型in_nn中获取的检测结果。这个结果可能是一个列表、数组或其他数据结构,包含了在输入图像中检测到的物体的信息。

具体的结构和内容取决于所使用的神经网络模型和应用场景。通常,每个检测结果可能包含物体类别、边界框位置、置信度等信息。可以根据具体情况对这些信息进行解析和处理,以满足特定的需求。

显示结果

到目前为止,我们已经从DepthAI设备获取了所有的结果,唯一剩下的就是将它们实际显示出来。

        if frame is not None:
            for detection in detections:
                bbox = frame_norm(frame,(detection.xmin,detection.ymin,detection.xmax,detection.ymax))
                cv2.rectangle(frame,(bbox[0],bbox[1]),(bbox[2],bbox[3]),(255,0,0),2)
            cv2.imshow("preview",frame)

上述代码判断frame是否存在,如果存在帧(frame is not None),则使用OpenCV库将检测结果显示在图像上。对于每个检测结果,可以使用检测框的坐标信息(detection.xmindetection.ymindetection.xmaxdetection.ymax)将矩形框绘制在帧上。然后,使用cv2.rectangle函数绘制矩形框,并设置颜色为(255, 0, 0)、线条宽度为2。最后,使用cv2.imshow函数显示帧并命名为"preview"。

在这里可以看到我们之前定义的frame_norm函数用于归一化边界框坐标的用法。我们使用cv2.rectangle在RGB帧上绘制一个矩形框,作为物体的指示器,然后使用cv2.imshow显示帧。

终止程序

使用cv2.waitKey方法来终止程序,它等待用户按下一个键——在这里,我们希望在用户按下q键时跳出循环

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

Setup 14:运行程序

在终端中输入如下指令运行程序

python hello_world.py

在这里插入图片描述
在这里插入图片描述
到这里,我们的第一个OAK程序已经成功运行了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/696612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS 仿 -webkit-box-reflect 属性实现 图片 镜面 倒影 效果

背景 最近在支付宝小程序上面要实现图片的镜面倒影效果&#xff0c;于是乎&#xff0c;马上找到了-webkit-box-reflect属性&#xff0c;用上之后真的绝绝子&#xff0c;模拟器上也很完美&#xff0c;可是到真机上一看&#xff0c;iOS 不支持&#xff0c;只有安卓手机支持&…

基于web的家校联系平台的设计与实现(源码+文档+PPT+数据库)

以 web为基础、以 Java SSM (springmvc mybatis mysql)为框架、以spring, springmvc, mybatis, bootstrap, JSP, jquery为主要技术来完成一个家庭与学校之间的联系。在框架下进行开发&#xff0c;管理员可以在后台输入信息、管理信息&#xff0c;设置网站信息&#xff0c;管理和…

【FFmpeg实战】H264 NALU分析

视频序列 宏块结构 NALU分层 H264的主要目标是为了有高的视频压缩比和良好的网络亲和性&#xff0c;为了达成这两个目标&#xff0c;H264的解决方案是将系统框架分为两个层面&#xff0c; VCL(视频编码层)和 NAL(网络提取层). VCL&#xff1a;包括核心压缩引擎和块&#xff…

[数据分析与可视化] 基于matplotlib-scalebar库绘制比例尺

matplotlib-scalebar是一个Python库&#xff0c;用于在matplotlib图形中添加比例尺。它允许用户指定比例尺的大小、位置、字体和颜色&#xff0c;以及比例尺的单位。该库支持不同的比例尺单位&#xff0c;例如米、英尺、英寸等。matplotlib-scalebar安装命令如下&#xff1a; p…

王道考研计算机网络第三章知识点汇总

3.1数据链路层功能概述&#xff1a; 3.2封装成帧和透明传输 重点理解透明传输的概率&#xff1a;可以形象地理解为小秘没有权限打开这5份文件 字符计数法如果其中一个计数字段出差错那么后续字段全部都错误&#xff0c;将会导致灾难性的错误。 字符填充法相当于编程时在/前面再…

JsFu0k批量探测JS存在的敏感关键字

这是一个演示 GitHub地址&#xff1a;https://github.com/jumppppp/go/tree/master/htools/jsfu0k 输出窗口 输出的详细文件 以上演示的是全字匹配 这个自动化工具模仿人工在一个网页内进行寻找js中敏感信息 流程&#xff1a; 填写配置&#xff08;输入批量域名&#xff0…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第九天 9/50

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

Eclipse中的实用工具之Debug

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Debug的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么是Debug 二.为什么要使用Debug 三…

springboot+element-ui多文件一次上传

前端&#xff1a; <el-uploaddrag:multiple"true":limit"10":auto-upload"false":file-list"fileList"ref"fileUpload"><i class"el-icon-upload"></i><div class"el-upload__text&quo…

【云原生】Pause 容器介绍

Pause 容器 Pause 容器&#xff0c;又叫 Infra 容器 我们知道在 kubelet 的配置中有这样一个参数&#xff1a; KUBELET_POD_INFRA_CONTAINER--pod-infra-container-imageregistry.access.redhat.com/rhel7/pod-infrastructure:latest上面是 openshift 中的配置参数&#xff…

关于Java类加问题我竟让面试官哑口无言

学习类加载之前我们先看看从面试官的角度会问哪些问题&#xff1f;毕竟带着问题学习会比较高效。 直击面试 看你简历写得熟悉 JVM&#xff0c;那你说说类的加载过程吧&#xff1f; 我们可以自定义一个 String 类来使用吗&#xff1f; 什么是类加载器&#xff0c;类加载器有哪些…

雨水情自动监测报警系统解决方案

随着夏季雨季的到来&#xff0c;对全国各地的防汛工作形成挑战&#xff0c;为了实现有效的雨水管理和应对极端天气情况&#xff0c;建立一套科学高效的雨水情监测系统有着重要作用。雨水情监测系统能够提供及时准确的雨水信息&#xff0c;帮助决策者进行全面的天气分析和预警&a…

数字化转型排头兵,金融行业如何利用科技赋能业务 | TVP金融交流会

引言 金融行业&#xff0c;是数字化转型浪潮中的排头兵。这个上千年来&#xff0c;不断创新的行业&#xff0c;从以物易物到纸币发行再到数字资产&#xff0c;承袭至今的是保障客户资产安全&#xff0c;提升资产流通效率的本心。进入产业互联网时代以后&#xff0c;金融科技的发…

第5讲:使用ajax技术实现局部刷新功能(xml数据)

使用ajax技术实现局部刷新功能&#xff0c;每2秒刷新一次数据&#xff0c;本案例使用原生态xmlhttprequest对象&#xff0c;GET方法通讯&#xff0c;使用responseXML属性返回xml格式数据&#xff0c;同时刷新界面数据。 ajax封装库(ajax.js) var xmlhttpnull; //创建XMLHttpRe…

adb-学会查看日志文件

目录 一、获取日志文件 二、日志级别 三、日志缓冲区 四、缓冲区的类型 &#x1f381;更多干货 完整版文档下载方式&#xff1a; 一、获取日志文件 一般情况下&#xff0c;我们在做app测试时&#xff0c;其实并不需要经常使用adb去抓取我们的日志&#xff0c;通常情况下…

使用GPIO来模拟UART

前言 最近在看一些秋招的笔试和面试题&#xff0c;刚好看到一个老哥的经验贴&#xff0c;他面试的时候被问到了如果芯片串口资源不够了该怎么办&#xff1f;其实可以用IO口来模拟串口&#xff0c;但我之前也没有具体用代码实现过&#xff0c;借此机会用32开发板上的两个IO口来…

力扣 404. 左叶子之和

题目来源&#xff1a;https://leetcode.cn/problems/sum-of-left-leaves/description/ C题解1&#xff1a;递归法&#xff0c;前序遍历。 1. 确定输入参数&#xff1a;当前节点&#xff0c;左叶子的和&#xff1b; 2. 确定终止条件&#xff1a;空节点时返回&#xff1b; 3. …

【每日一短语】在必要情况下

1、短语及释义 in a pinch 释义&#xff1a; 在紧要关头&#xff1b;在必要情况下 2、示例及出处 美剧&#xff1a;《生活大爆炸》第七季第21集 The Big Bang Theory, Season 7 Episode 21 Sheldon Cooper: Penny, there’s only one cookie with something in the middle tha…

基于STM32设计的城市绿化云端监控系统(华为云IOT)

一、设计需求 1.1 项目背景 随着科技的蓬勃发展改变了很多传统行业的作业方式,当我们用移动支付代替现金交易时,当我们足不出户就能满足饥饿的身体时,我们的生活方式因为科技而发生了改变;同样科技也在改变着我们周围的点点滴滴,城市绿化养护亦是如此。 通过智慧控制系统…

在Docker中使用MindSpore GPU版本

文章目录 在Docker中使用MindSpore GPU版本获取安装命令安装安装nvidia-container-toolkit获取MindSpore镜像测试运行MindSpore镜像运行代码 使用VSCode开发 在Docker中使用MindSpore GPU版本 参考官方文档&#xff1a;安装指南 获取安装命令 如图所示 命令为 docker pull…