香橙派 AIpro开发体验:使用YOLOV8对USB摄像头画面进行目标检测

前言

YOLOv8 作为最新的目标检测算法,以其高精度、高速度和易用性,成为许多开发者首选。而香橙派 AIpro 作为一款高性能嵌入式开发板,采用昇腾AI技术路线,集成图形处理器,拥有8GB/16GB LPDDR4X,8/20 TOPS AI算力,为 AI 应用提供了坚实的硬件基础。本篇文章将分享使用香橙派 AIpro 和 YOLOv8 结合 USB 摄像头进行物体检测的实战经验,并探讨其在实际应用中的价值。

一、香橙派AIpro硬件准备

香橙派 AIpro 开发板、USB 摄像头、电源适配器,网线,micro SD卡预烧录ubuntu系统。

img

二、连接香橙派AIpro

1. 通过网线连接路由器和香橙派AIpro

为了确保香橙派AIpro与网络的稳定连接,我们采用网线将其直接接入路由器。随后,在电脑上运行ip扫描器对内网进行全面扫描,成功识别到设备“orangepiaipro”,其IP地址为192.168.1.7。

img

2. 通过wifi连接香橙派AIpro

我们在登录香橙派AIpro之后,可以参照以下方法进行wifi的连接。
扫描wifi

sudo nmcli dev wifi

连接wifi

sudo nmcli dev wifi connect wifi名称 password wifi密码

3. 使用vscode 通过ssh连接香橙派AIpro

Tip:使用vscode可以像本地开发一样 ,在香橙派AIpro上进行远程开发。
安装vscode 插件
1.Remote - SSH
2.Remote - SSH: Editing
3.Remote Explorer
img
创建一个ssh连接,用户名默认为HwHiAiUser,登录密码默认为Mind@123

ssh HwHiAiUser@192.168.1.7

img
我们连接上之后打开桌面文件夹,在桌面进行开发
img
选择桌面路径
img
同时我们打开终端
img

三、USB摄像头测试

1. 配置ipynb远程开发环境

1.1 创建一个video.ipynb 文件

img
创建好之后保存在桌面文件夹内,vscode会同步这个目录的文件,方便我们进行开发。
img
img

1.2 在远程主机中安装jupyter插件和python 插件

我们对这两个主要的插件进行安装,其他插件会自动安装上。
img
然后我们打开video.ipynb 文件 选择我们需要的python版本。
python3.10.12 是系统自动的python版本。
base(python 3.9.2) 是anaconda的基础python版本。
我们应该使用conda 环境,最好是新建conda环境,来避免可能出现的环境依赖问题。

img

2. 使用opencv读取USB摄像头进行拍照

我们可能会遇到无法读取摄像头的错误,是因为没有权限访问摄像头。
img
直接对摄像头的权限进行降级,让当前用户可以访问

sudo  chmod 666 /dev/video0

我们在video.ipynb中进行代码编写,可以直接显示摄像头画面

import cv2
from IPython.display import display, Image

camera = cv2.VideoCapture(0)
camera.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc('M','J','P','G'))
if not camera.isOpened():
    raise IOError("Impossible d'ouvrir la webcam")
ret, frame = camera.read()
if not ret:
    raise IOError("Impossible de capturer une image")
display(Image(data=cv2.imencode('.jpg', frame)[1]))
camera.release()

运行效果如下:
img

3. 使用opencv读取USB摄像头进行实时拍摄显示

我们在video.ipynb中进行如下python代码编写,可以直接显示摄像头画面

import cv2
import numpy as np
from IPython.display import display, clear_output,Image

# Initialize the camera
camera = cv2.VideoCapture(0)  # Use 0 for the default camera
# Set the codec to MJPG if it is supported
if camera.isOpened():
    camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
else:
    raise IOError("Cannot open the webcam")
try:
    while True:
        # Capture frame-by-frame
        ret, frame = camera.read()
        if not ret:
            raise IOError("Cannot capture frame")
        # Display the image
        clear_output(wait=True)
        # Afficher l'image capturée
        display(Image(data=cv2.imencode('.jpg', frame)[1]))
finally:
    # When everything done, release the capture
    camera.release()

本次使用的usb摄像头帧率比较低,所以有拖影,但从实时性的体验上来说,还是非常不错的。
在这里插入图片描述

四、使用yolov8进行目标检测

1. 使用torch cpu推理yolov8

本次测试使用的版本为yolov8.2 ,首先将yolov8中的ultralytics文件夹拖到香橙派AIpro的桌面上。

img
然后在video.ipynb中进行代码编写,调用yolov8库进行推理

import cv2
import numpy as np
from IPython.display import display, clear_output,Image
from ultralytics import YOLO
from time import time
# Load a model
model = YOLO('yolov8n.pt')  # pretrained YOLOv8n model
# Initialize the camera
camera = cv2.VideoCapture(0)  # Use 0 for the default camera
# Set the codec to MJPG if it is supported
if camera.isOpened():
    # camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280.0)
    # camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720.0)
    camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
else:
    raise IOError("Cannot open the webcam")
try:
    while True:
        # Capture frame-by-frame
        ret, frame = camera.read()
        if not ret:
            raise IOError("Cannot capture frame")
        s = time()
        results = model(frame,conf=0.25,iou=0.5,verbose=False)
        print(time()-s)
        for r in results:
            im = r.plot()
        # Display the image
        clear_output(wait=True)
        # Afficher l'image capturée
        display(Image(data=cv2.imencode('.jpg', im)[1]))
finally:
    # When everything done, release the capture
    camera.release()

直接调用原始库推理速度约为0.5s 一次

img

香橙派AIpro直接调用yolov8库使用torch cpu进行推理,推理时占用2核cpu,整体占用50%,如果多线程实现应该在0.2s左右,就是4-5帧。推理时内存占用也不高,表现还是不错的。

img

2. 使用opencv推理onnx模型

2.1 导出yolov8的onnx模型

img

2.2 onnx推理

编写python代码,使用opencv dnn推理onnx模型并读取usb摄像头进行检测

import cv2
import numpy as np
from IPython.display import display, clear_output,Image
from time import time
import cv2.dnn
from ultralytics.utils import ASSETS, yaml_load
from ultralytics.utils.checks import check_yaml
CLASSES = yaml_load(check_yaml('coco128.yaml'))['names']
colors = np.random.uniform(0, 255, size=(len(CLASSES), 3))
model: cv2.dnn.Net = cv2.dnn.readNetFromONNX("yolov8n.onnx")

def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):
    label = f'{CLASSES[class_id]} ({confidence:.2f})'
    color = colors[class_id]
    cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)
    cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

def main(original_image):
    [height, width, _] = original_image.shape
    length = max((height, width))
    image = np.zeros((length, length, 3), np.uint8)
    image[0:height, 0:width] = original_image
    scale = length / 640
    blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
    model.setInput(blob)
    outputs = model.forward()
    outputs = np.array([cv2.transpose(outputs[0])])
    rows = outputs.shape[1]
    boxes = []
    scores = []
    class_ids = []
    for i in range(rows):
        classes_scores = outputs[0][i][4:]
        (minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores)
        if maxScore >= 0.25:
            box = [
                outputs[0][i][0] - (0.5 * outputs[0][i][2]), outputs[0][i][1] - (0.5 * outputs[0][i][3]),
                outputs[0][i][2], outputs[0][i][3]]
            boxes.append(box)
            scores.append(maxScore)
            class_ids.append(maxClassIndex)
    result_boxes = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45, 0.5)

    detections = []
    for i in range(len(result_boxes)):
        index = result_boxes[i]
        box = boxes[index]
        detection = {
            'class_id': class_ids[index],
            'class_name': CLASSES[class_ids[index]],
            'confidence': scores[index],
            'box': box,
            'scale': scale}
        detections.append(detection)
        draw_bounding_box(original_image, class_ids[index], scores[index], round(box[0] * scale), round(box[1] * scale),
                          round((box[0] + box[2]) * scale), round((box[1] + box[3]) * scale))

# Initialize the camera
camera = cv2.VideoCapture(0)  # Use 0 for the default camera
# Set the codec to MJPG if it is supported
if camera.isOpened():
    # camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280.0)
    # camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720.0)
    camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
else:
    raise IOError("Cannot open the webcam")
try:
    while True:
        # Capture frame-by-frame
        ret, frame = camera.read()
        if not ret:
            raise IOError("Cannot capture frame")
        s = time()
        main(frame)
        print(time()-s)
        # Display the image
        clear_output(wait=True)
        # Afficher l'image capturée
        display(Image(data=cv2.imencode('.jpg', frame)[1]))

finally:
    # When everything done, release the capture
    camera.release()

onnx推理使用单核cpu,推理一次的速度约为0.7s

img

3. 使用npu 推理yolov8

3.1 onnx转换为OM模型

将ONNX模型转换为OM模型,用CANN提供的ATC工具将其转换为昇腾AI处理器能识别的OM模型。

atc --framework=5 --model=yolov8n.onnx --input_format=NCHW --output=yolov8n --soc_version=Ascend310B4

atc命令中各参数的含义如下:
–framework:原始框架类型,5表示ONNX。
–model:ONNX模型文件存储路径。
–input_format:输入的格式定义
–output:离线om模型的路径以及文件名。
–soc_version:昇腾AI处理器的型号。
在服务器种执行npu-smi info命令进行查询,在查询到的“Name”前增加Ascend信息,例如“Name”对应取值为310B4,实际配置的–soc_version值为Ascend310B4。

img

3.2 添加交换空间

若出现以下错误则是内存不足,可以添加交换空间

BrokenPipeError: [Errno 32] Broken pipe
/usr/local/miniconda3/lib/python3.9/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 97 leaked semaphore objects to clean up at shutdown
warnings.warn('resource_tracker: There appear to be %d ’

  1. 使用 root 用户执行:
su -
  1. 创建一个用于交换空间的文件,创建8GB的交换文件:
fallocate -l 8G /swapfile
chmod 600 /swapfile
  1. 设置交换文件
mkswap /swapfile
  1. 启用交换空间
swapon /swapfile
  1. 编辑/etc/fstab文件,使交换空间开机自动挂载:
echo '/swapfile none swap defaults 0 0' >> /etc/fstab

6.验证交换空间是否生效

free -m

通过top监控可以看到 转换过程占用内存大概 12G左右,不添加虚拟缓存内存是不够用的。
img

3.3 npu推理

编写python代码使用npu推理yolov8 对usb摄像头进行检测

import os

# Verify the path
print(os.environ['LD_LIBRARY_PATH'])
import cv2
import numpy as np
from IPython.display import display, clear_output,Image
from time import time
from ais_bench.infer.interface import InferSession
from ultralytics.utils import ASSETS, yaml_load
from ultralytics.utils.checks import check_yaml

CLASSES = yaml_load(check_yaml('coco128.yaml'))['names']

colors = np.random.uniform(0, 255, size=(len(CLASSES), 3))

model = InferSession(device_id=0, model_path="yolov8n.om")

def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):
    label = f'{CLASSES[class_id]} ({confidence:.2f})'
    color = colors[class_id]
    cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)
    cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)


def main(original_image):
    [height, width, _] = original_image.shape
    length = max((height, width))
    image = np.zeros((length, length, 3), np.uint8)
    image[0:height, 0:width] = original_image
    scale = length / 640

    blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
    
    begin_time = time()
    outputs = model.infer(feeds=blob, mode="static")
    end_time = time()
    print("om infer time:", end_time - begin_time)

    outputs = np.array([cv2.transpose(outputs[0][0])])
    rows = outputs.shape[1]

    boxes = []
    scores = []
    class_ids = []

    for i in range(rows):
        classes_scores = outputs[0][i][4:]
        (minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores)
        if maxScore >= 0.25:
            box = [
                outputs[0][i][0] - (0.5 * outputs[0][i][2]), outputs[0][i][1] - (0.5 * outputs[0][i][3]),
                outputs[0][i][2], outputs[0][i][3]]
            boxes.append(box)
            scores.append(maxScore)
            class_ids.append(maxClassIndex)

    result_boxes = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45, 0.5)

    detections = []
    for i in range(len(result_boxes)):
        index = result_boxes[i]
        box = boxes[index]
        detection = {
            'class_id': class_ids[index],
            'class_name': CLASSES[class_ids[index]],
            'confidence': scores[index],
            'box': box,
            'scale': scale}
        detections.append(detection)
        draw_bounding_box(original_image, class_ids[index], scores[index], round(box[0] * scale), round(box[1] * scale),
                          round((box[0] + box[2]) * scale), round((box[1] + box[3]) * scale))

# Initialize the camera
camera = cv2.VideoCapture(0)  # Use 0 for the default camera

# Set the codec to MJPG if it is supported
if camera.isOpened():
    # camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280.0)
    # camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720.0)
    camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
else:
    raise IOError("Cannot open the webcam")

    # Define the codec and create VideoWriter object
# Get the width and height of the frames
frame_width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"Frame width: {frame_width}, Frame height: {frame_height}")

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 30.0, (frame_width, frame_height))  # 20.0 is the frame rate

try:
    _start_time = time()
    while time() - _start_time < 5:
        # Capture frame-by-frame
        ret, frame = camera.read()
        if not ret:
            raise IOError("Cannot capture frame")
        main(frame)
        out.write(frame)

        # Display the image
        # clear_output(wait=True)
        
        # # Afficher l'image capturée
        # display(Image(data=cv2.imencode('.jpg', frame)[1]))

finally:
    # When everything done, release the capture
    camera.release()
    out.release()

与前面torch和onnx 的推理相比,基于昇腾CANN的推理效果,在速度上有了质的飞跃。

img
yolov8使用npu推理一帧的速度达到了惊人的0.017s,相比cpu提升了20-30倍。

img

五、总结

昇腾CANN框架的优势:

  1. 推理速度显著提升: 在使用YOLOv8模型进行推理时,我发现昇腾CANN的单帧处理速度能达到0.017秒,相比CPU提升了20-30倍,这对于实时性要求高的应用场景(如自动驾驶、安防监控)至关重要。
  2. 兼容性与扩展性强: 昇腾CANN支持多种模型和算法,并随着昇腾硬件的升级不断提升性能,为开发者提供了更广阔的选择空间。
    香橙派AIpro开发板的优势:
  3. 硬件性能出色: 能够流畅运行复杂的AI算法和模型,满足我的开发需求。
  4. 易用性高: 简单的设置和配置就能将AI应用部署到开发板上进行测试和验证,极大提升了开发效率。
  5. 扩展性强: 丰富的接口方便连接其他硬件设备,为开发更复杂的AI应用提供了更多可能性。

总的来说,我对其高效的推理速度、便捷的开发体验以及强大的扩展性印象深刻。
香橙派AIpro开发板为开发者提供了一个优秀的平台,可以方便地体验和利用昇腾CANN强大的AI推理能力。我相信,随着昇腾CANN和香橙派AIpro开发板的不断发展,它们将进一步推动AI技术的应用和普及。

六、参考

CANN开发指南
香橙派官网
昇腾论坛

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用 YOLOv8 进行实时目标检测并调用虚拟摄像头,可以按照以下步骤进行: 1. 安装 OpenCV 库和 PyTorch 库。 2. 下载 YOLOv8 模型和相关的配置文件,可以从 GitHub 上的 YOLOv8 项目中进行下载。 3. 使用 OpenCV 库来读取虚拟摄像头中的视频流,并将视频帧传递给 YOLOv8 模型进行目标检测。 4. 在检测到物体后,使用 OpenCV 库将检测结果在视频帧上进行标注,并将标注后的帧输出到虚拟摄像头中。 下面是一个基本的 Python 代码示例: ```python import cv2 import torch import numpy as np # 加载 YOLOv8 模型 model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # 打开虚拟摄像头 cap = cv2.VideoCapture(0) while True: # 读取视频帧 ret, frame = cap.read() # 将视频帧传递给 YOLOv8 模型进行目标检测 results = model(frame) # 标注检测结果 for det in results.xyxy[0]: cv2.rectangle(frame, (int(det[0]), int(det[1])), (int(det[2]), int(det[3])), (0, 255, 0), 2) cv2.putText(frame, f'{model.names[int(det[5])]} {det[4]:.2f}', (int(det[0]), int(det[1] - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) # 显示帧 cv2.imshow('frame', frame) # 将标注后的帧输出到虚拟摄像头中 # 注意,这里需要使用虚拟摄像头的 API 来输出帧 # 可以使用 pyfakewebcam 库来模拟虚拟摄像头 # 这里只是示例代码,具体实现需要根据自己的虚拟摄像头 API 进行修改 # output_cam.write(frame) # 检查是否按下了 q 键 if cv2.waitKey(1) == ord('q'): break # 释放资源 cap.release() # output_cam.release() cv2.destroyAllWindows() ``` 需要根据自己的虚拟摄像头 API 来修改输出帧的部分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图像处理大大大大大牛啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值