基于Aidlux的停车标志检测(可修改为coco 80类目标检测)

news2024/11/26 22:20:07

●项目名称
基于Aidlux的停车标志检测(可修改为coco 80类目标检测)

●项目简介

本项目在Aidlux上部署检测停车标志检测,并可在源码上修改coco 80类目标检测索引直接检测其他79类目标,可以直接修改、快速移植到自己的项目中。

●预期效果

本项目使用利用安装AidLux的AidLux设备s855实现,可以让任何AidLux使用者快速上手,体验深度学习检测效果,提高开发乐趣。

边缘计算设备的优势主要包括以下几个方面:
节省带宽:边缘计算设备可以在源头处理数据,只传输重要的数据,从而节省带宽。
减少延迟:边缘计算设备可以减少等待时间,提高响应速度。
优化网络性能:边缘计算设备可以帮助企业实时分析和处理数据,从而提高网络性能。
提供本地化服务:边缘计算设备可以提供本地化服务,例如在智能城市、自动驾驶汽车和医疗保健行业中,边缘计算设备可以提供更快速、更准确的服务。
提高安全性:边缘计算设备可以减少数据传输过程中的安全风险,提高安全性。

对于大多数企业来说,coco的80类可支持大部分场景的预研、模拟,本项目将yolov5移植至AidLux,可在源码中直接修改类别,实现80类中任何一类的检测。

对于开发者而言,AI项目中各种算法的数据集准备+模型训练+模型部署依然存在着不小的难度。AidLux的出现,可以将我们的安卓设备以非虚拟的形式变成同时拥有Android和Linux系统环境的边缘计算设备,支持主流AI框架,非常易于部署,还有专门的接口调度算力资源,极大地降低了AI应用落地门槛。

Aidlux简介

Aidlux基于ARM架构的跨生态(Android/鸿蒙+Linux)一站式AIoT应用开发和部署平台
在这里插入图片描述
可在安卓手机(软硬件最低配置要求:①Android 系统版本 >= 6,②剩余存储空间 > 650MB (AidLux1.1),③CPU 支持 arm64-v8a 架构)

和其发布的边缘计算设备上运行、开发

下面上源码:

yolov5.py

# aidlux相关
from cvs import *
import aidlite_gpu
from utils import detect_postprocess, preprocess_img, draw_detect_res

import cv2



# 加载模型
model_path = 'yolov5s-fp16.tflite'
# 定义输入输出shape
in_shape = [1 * 640 * 640 * 3 * 4]
out_shape = [1 * 25200 * 85 * 4, 1 * 3 * 80 * 80 * 85 * 4, 1 * 3 * 40 * 40 * 85 * 4, 1 * 3 * 20 * 20 * 85 * 4]

# 载入模型
aidlite = aidlite_gpu.aidlite()
# 载入yolov5检测模型
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 0)

# cap = cvs.VideoCapture(0)
sign = 11


frame=cvs.imread("5.jpg",1)
# 预处理
img = preprocess_img(frame, target_shape=(640, 640), div_num=255, means=None, stds=None)

aidlite.setInput_Float32(img, 640, 640)
# 推理
aidlite.invoke()
pred = aidlite.getOutput_Float32(0)
pred = pred.reshape(1, 25200, 85)[0]
pred = detect_postprocess(pred, frame.shape, [640, 640, 3], conf_thres=0.5, iou_thres=0.45)
res_img, detec_taget = draw_detect_res(frame, pred, sign)

if detec_taget == 1:
    cv2.imwrite("detect_image.jpg", res_img)
    cvs.imshow(res_img)
其中,经过请教rockey老师和江大白老师得知,cvs是将opencv在aidlux做了兼容性开发,语法同opencv,也这里是读取图片的方式,也可用读取摄像头的方式。我们检测stop sign图片,在coco 80类目标检测中索引为11(从0开始),所以设置sign=0,。如果是行人或者其他,直接修改sign的值为对应索引即可。


相关后处理函数utils.py

```python
import cv2
import numpy as np

coco_class = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
        'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
        'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
        'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
        'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
        'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
        'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
        'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
        'hair drier', 'toothbrush']

def xywh2xyxy(x):
    '''
    Box (center x, center y, width, height) to (x1, y1, x2, y2)
    '''
    y = np.copy(x)
    y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left x
    y[:, 1] = x[:, 1] - x[:, 3] / 2  # top left y
    y[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right x
    y[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right y
    return y

def xyxy2xywh(box):
    '''
    Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
    '''
    box[:, 2:] = box[:, 2:] - box[:, :2]
    return box

def NMS(dets, thresh):
    '''
    单类NMS算法
    dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
    '''
    x1 = dets[:,0]
    y1 = dets[:,1]
    x2 = dets[:,2]
    y2 = dets[:,3]
    areas = (y2-y1+1) * (x2-x1+1)
    scores = dets[:,4]
    keep = []
    index = scores.argsort()[::-1]
    while index.size >0:
        i = index[0]       # every time the first is the biggst, and add it directly
        keep.append(i)
        x11 = np.maximum(x1[i], x1[index[1:]])    # calculate the points of overlap 
        y11 = np.maximum(y1[i], y1[index[1:]])
        x22 = np.minimum(x2[i], x2[index[1:]])
        y22 = np.minimum(y2[i], y2[index[1:]])
        w = np.maximum(0, x22-x11+1)    # the weights of overlap
        h = np.maximum(0, y22-y11+1)    # the height of overlap
        overlaps = w*h
        ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
        idx = np.where(ious<=thresh)[0]
        index = index[idx+1]   # because index start from 1
 
    return dets[keep]

def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
    # Resize and pad image while meeting stride-multiple constraints
    shape = img.shape[:2]  # current shape [height, width]
    if isinstance(new_shape, int):
        new_shape = (new_shape, new_shape)

    # Scale ratio (new / old)
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
    if not scaleup:  # only scale down, do not scale up (for better test mAP)
        r = min(r, 1.0)

    # Compute padding
    ratio = r, r  # width, height ratios
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding
    if auto:  # minimum rectangle
        dw, dh = np.mod(dw, stride), np.mod(dh, stride)  # wh padding
    elif scaleFill:  # stretch
        dw, dh = 0.0, 0.0
        new_unpad = (new_shape[1], new_shape[0])
        ratio = new_shape[1] / shape[1], new_shape[0] / shape[0]  # width, height ratios

    dw /= 2  # divide padding into 2 sides
    dh /= 2

    if shape[::-1] != new_unpad:  # resize
        img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
    return img, ratio, (dw, dh)

def preprocess_img(img, target_shape:tuple=None, div_num=255, means:list=[0.485, 0.456, 0.406], stds:list=[0.229, 0.224, 0.225]):
    '''
    图像预处理:
    target_shape: 目标shape
    div_num: 归一化除数
    means: len(means)==图像通道数,通道均值, None不进行zscore
    stds: len(stds)==图像通道数,通道方差, None不进行zscore
    '''
    img_processed = np.copy(img)
    # resize
    if target_shape:
        # img_processed = cv2.resize(img_processed, target_shape)
        img_processed = letterbox(img_processed, target_shape, stride=None, auto=False)[0]

    img_processed = img_processed.astype(np.float32)
    img_processed = img_processed/div_num

    # z-score
    if means is not None and stds is not None:
        means = np.array(means).reshape(1, 1, -1)
        stds = np.array(stds).reshape(1, 1, -1)
        img_processed = (img_processed-means)/stds

    # unsqueeze
    img_processed = img_processed[None, :]

    return img_processed.astype(np.float32)
    
def convert_shape(shapes:tuple or list, int8=False):
    '''
    转化为aidlite需要的格式
    '''
    if isinstance(shapes, tuple):
        shapes = [shapes]
    out = []
    for shape in shapes:
        nums = 1 if int8 else 4
        for n in shape:
            nums *= n
        out.append(nums)
    return out

def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None):
    # Rescale coords (xyxy) from img1_shape to img0_shape
    if ratio_pad is None:  # calculate from img0_shape
        gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new
        pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding
    else:
        gain = ratio_pad[0][0]
        pad = ratio_pad[1]

    coords[:, [0, 2]] -= pad[0]  # x padding
    coords[:, [1, 3]] -= pad[1]  # y padding
    coords[:, :4] /= gain
    clip_coords(coords, img0_shape)
    return coords


def clip_coords(boxes, img_shape):
    # Clip bounding xyxy bounding boxes to image shape (height, width)
    boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0])  # x1
    boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1])  # y1
    boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2])  # x2
    boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3])  # y2

def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
    '''
    检测输出后处理
    prediction: aidlite模型预测输出
    img0shape: 原始图片shape
    img1shape: 输入图片shape
    conf_thres: 置信度阈值
    iou_thres: IOU阈值
    return: list[np.ndarray(N, 5)], 对应类别的坐标框信息, xywh、conf
    '''
    h, w, _ = img1shape
    cls_num = prediction.shape[-1] - 5
    valid_condidates = prediction[prediction[..., 4] > conf_thres]
    valid_condidates[:, 0] *= w
    valid_condidates[:, 1] *= h
    valid_condidates[:, 2] *= w
    valid_condidates[:, 3] *= h
    valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
    valid_condidates = valid_condidates[(valid_condidates[:, 0] > 0) & (valid_condidates[:, 1] > 0) & (valid_condidates[:, 2] > 0) & (valid_condidates[:, 3] > 0)]
    box_cls = valid_condidates[:, 5:].argmax(1)
    cls_box = []
    for i in range(cls_num):
        temp_boxes = valid_condidates[box_cls == i]
        if(len(temp_boxes) == 0):
            cls_box.append([])
            continue
        temp_boxes = NMS(temp_boxes, iou_thres)
        temp_boxes[:, :4] = scale_coords([h, w], temp_boxes[:, :4] , img0shape).round()
        temp_boxes[:, :4] = xyxy2xywh(temp_boxes[:, :4])
        cls_box.append(temp_boxes[:, :5])
    return cls_box

def draw_detect_res(img, all_boxes,sign):
    '''
    检测结果绘制
    '''
    img = img.astype(np.uint8)
    color_step = int(255/len(all_boxes))
    for bi in range(len(all_boxes)):
        if len(all_boxes[bi]) == 0:
            continue
        for box in all_boxes[bi]:
            x, y, w, h = [int(t) for t in box[:4]]
            if bi != sign:
                continue
            if bi == sign:
                type = 1
            cv2.putText(img, f'{coco_class[bi]}', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
            cv2.rectangle(img, (x,y), (x+w, y+h),(0, bi*color_step, 255-bi*color_step),thickness = 2)
    return img,type

所有文件(测试图片、python文件及yolov5s推理模型)

在这里插入图片描述

●操作流程

远程链接Aidlux,并找到home文件夹,将包含上述文件的文件夹上传

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
双击打开yolov5.py 并点击Bulid
在这里插入图片描述
找到Run Now 并点击运行
在这里插入图片描述
运行结果:
在这里插入图片描述
源码在这里


在Aidlux小助手建议下增加了视频检测:

# aidlux相关
from cvs import *
import aidlite_gpu
from utils import detect_postprocess, preprocess_img, draw_detect_res


import time
import requests
import cv2



# 加载模型
model_path = 'yolov5s-fp16.tflite'
# 定义输入输出shape
in_shape = [1 * 640 * 640 * 3 * 4]
out_shape = [1 * 25200 * 85 * 4, 1 * 3 * 80 * 80 * 85 * 4, 1 * 3 * 40 * 40 * 85 * 4, 1 * 3 * 20 * 20 * 85 * 4]

# 载入模型
aidlite = aidlite_gpu.aidlite()
# 载入yolov5检测模型
aidlite.ANNModel(model_path, in_shape, out_shape, 4, 0)


sign = 14   #stop sign:11  bird:14


cap = cvs.VideoCapture("bird.mp4")

# # 定义保存视频的编码格式、分辨率和帧率等信息
# fourcc = cvs.VideoWriter_fourcc(*'XVID')
# out = cvs.VideoWriter('result.avi', fourcc, 20.0, (640,  640))

while True:
    frame = cap.read()
    if frame is None:
        continue

# 预处理
    img = preprocess_img(frame, target_shape=(640, 640), div_num=255, means=None, stds=None)
    
    aidlite.setInput_Float32(img, 640, 640)
    # 推理
    aidlite.invoke()
    pred = aidlite.getOutput_Float32(0)
    pred = pred.reshape(1, 25200, 85)[0]
    pred = detect_postprocess(pred, frame.shape, [640, 640, 3], conf_thres=0.5, iou_thres=0.45)
    res_img, detec_taget = draw_detect_res(frame, pred, sign)
    
    if detec_taget == 1:
        cv2.imwrite("detect_image.jpg", res_img)

    # #保存摄像头视频
    # fourcc = cvs.VideoWriter_fourcc(*'XVID')
    # out = cvs.VideoWriter('result.avi', fourcc, 20.0, (640, 640))
    cvs.imshow(res_img)
    
    # out.write(res_img)
    
    # 释放资源
cap.release()
out.release()
# 关闭窗口
cvs.destroyAllWindows()
        # cvs.imshow(res_img)

演示视频:

基于Aidlux的鸟类检测

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

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

相关文章

【学习笔记】Java——消息队列kafka

kafka 1、Kafka combines three key capabilities&#xff1a;2、kafka是如何工作的&#xff1a;3、Kafka APIS&#xff1a;4、kafka集群 1、Kafka combines three key capabilities&#xff1a; To publish (write) and subscribe to (read) streams of events, including co…

中国游戏等“春”来

对于游戏行业来说&#xff0c;2023年将是压力依旧的一年&#xff0c;但或许也是转型调优的希望之年。 压力在于&#xff0c;互联网流量见顶&#xff0c;用户付费意愿降低&#xff0c;行业整体进入下行周期&#xff0c;彻底进入存量竞争时代。《2022年中国游戏产业报告》显示&a…

相机标定实战之双目标定

相机标定原理 文章目录 相机标定原理前言一、采集图像二、基于Matlab单双目标定流程采集棋盘图 三、基于OpenCV-Python双目标定流程检测棋盘格角点对角点进行亚像素精细化单目标定双目标定双目校正保存标定参数读取标定参数代码示例 参考 前言 相机标定可以说是计算机视觉/机器…

哪个公司的 CEO 不想拥有一个自己的数字克隆?

⚠️ FBI Warning&#xff1a;本文纯属作者自娱自乐&#xff0c;数字人的观点不代表 CEO 本人的观点&#xff0c;请大家不要上当受骗&#xff01;&#xff01; 哪个公司的 CEO 不想拥有一个自己的数字克隆&#xff1f; 想象&#x1f914;一下&#xff0c;如果 CEO 数字克隆上线…

python基础语法总结

1.打印输出 print(“Hello World”) 在许多大众的编程语言中&#xff0c;需要在每个语句的末尾添加分号,但Python并非如此。Python是一种简洁的编程语言&#xff0c;你不需要添加不必要的字符和语法。在Python中&#xff0c;一条语句结束于一行的结尾&#xff08;方括号&…

找不到msvcp120dll,无法继续执行代码的修复方法

本教程操作系统&#xff1a;Windows系统、 msvcp120.dll是电脑文件中的dll文件&#xff08;动态链接库文件&#xff09;。如果计算机中丢失了某个dll文件&#xff0c;可能会导致某些软件和游戏等程序无法正常启动运行&#xff0c;并且导致电脑系统弹窗报错。 msvcp120.dll文件…

IDEA整合GO并创建module工程

IDEA整合Go 安装包环境配置idea配置并创建test mode 安装包 1.去官网下载对应还的安装包 官网下载地址 我选择下载的window 版本&#xff1a; 直接按照对应的目录&#xff0c;然后点击下一步 环境配置 1.配置go环境变量 在高级环境变量PAHT中添加安装包的**/bin 目录&…

mysql数据库的基础

mysql数据库 一、数据库的基本概念二、关系数据库三、SQL语句增改查删 四、natvicat for mysql软件 一、数据库的基本概念 数据&#xff08;data&#xff09; 描述事物的符号记录包括数字、文字、图形、图像、声音、档案记录等以“记录”形式按统一的格式进行存储 表&#x…

基于Java少儿编程网上报名系统设计与实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

sizeof 和 strlen !!!

定义 sizeof()是单目操作符&#xff0c;是可以求变量&#xff08;类型&#xff09;所占空间的大小&#xff0c;不在乎内存中存放的是什么&#xff0c;只在乎内存大小 strlen()是函数&#xff0c;是计算字符串的长度的 它从内存的某个位置&#xff08;可以是字符串开头&#x…

进程管道:pipe调用

在看过高级的popen函数之后&#xff0c;我们再来看看底层的pipe函数。通过这个函数在两个程序之间传递数据不需要启动一个shell来解释请求的命令。它同时还提供了对读写数据的更多控制。pipe函数的原型如下所示&#xff1a; #include <unistd.h> int pipe(int pipefd[2])…

OS的事件机制-Event

Event在OSEK OS中&#xff0c;其实就是一个flag的作用&#xff0c;如果某个TASK执行了&#xff0c;就调用<SetEvent()>把flag就置起来&#xff0c;和这个task关联的另一个TASK也执行了&#xff0c;就可以把flag清掉<ClearEvent>&#xff0c;如果第一个TASK没有执行…

这才是你想了解的Redis

文章简介 redis作为一个基于内存的数据结构存储系统&#xff0c;由于它的灵活性和可拓展性强&#xff0c;在我们日常开发中经常被用作数据库、缓存或者消息代理。本文就从Redis的基本部署使用说到Redis的集群、锁和消息对列 Redis基本使用 一、安装 下载地址&#xff1a;htt…

mySql 储存过程 多个结果返回解析

当需要查询复杂的数据模型并返回多个结果集时&#xff0c;使用 MySQL 存储过程可以有效地优化性能。同时&#xff0c;在开发中使用 Mybatis 可以方便地调用 MySQL 存储过程并获取多个结果集。本文将介绍如何在 Mybatis 中调用 MySQL 存储过程&#xff0c;并获取多个结果集。 1、…

Java并发之原子类

一、原子类简介 1 什么是原子类 Java中提供了一些原子类&#xff0c;原子类包装了一个变量&#xff0c;并且提供了一系列对变量进行原子性操作的方法。原子性的意思是对于一组操作&#xff0c;要么全部执行成功&#xff0c;要么全部执行失败&#xff0c;不能只有其中某几个执…

基础知识学习---牛客网C++面试宝典(三)C/C++基础之面向对象

1、本栏用来记录社招找工作过程中的内容&#xff0c;包括基础知识学习以及面试问题的记录等&#xff0c;以便于后续个人回顾学习&#xff1b; 暂时只有2023年3月份&#xff0c;第一次社招找工作的过程&#xff1b; 2、个人经历&#xff1a; 研究生期间课题是SLAM在无人机上的应…

测试新手百科:Postman简介、安装、入门使用方法详细攻略!

本文关键词&#xff1a;Postman基础 目录 一、Postman背景介绍 二、Postman的操作环境 三、Postman下载安装 四、Postman的基础功能 五、接口请求流程 六、管理用例—Collections 七、身份验证Authentication 一、Postman背景介绍 用户在开发或者调试网络程序或者是网…

【答题】在线答卷-答题系统的微信小程序开发流程详解

用死记硬背的方法学习的学生&#xff0c;面对桌上堆积成厚厚的书本&#xff0c;是否感觉鸭梨山大呢&#xff0c;想着教育却面临着学习成本不小问题&#xff0c;是否感觉各种不便呢&#xff0c;如果对编程代码有感兴趣&#xff0c;不妨试试做一个自己的在线答题系统&#xff0c;…

有效性常见标志词

有效性常见标志词 混淆概念常见标志词 &#xff08; 1 &#xff09; 既然…那么… &#xff08; 2 &#xff09; 也就是说… &#xff08; 3 &#xff09; 很显然… &#xff08; 4 &#xff09; 因为A 就是B…所以… &#xff08; 5 &#xff09; 某主体A 是 &#xff0c;…

低代码01之构建项目框架

目录 低代码之构建框架11&#xff1a;项目初始化2&#xff1a;src / data.json 数据 &#xff08; 容器大小与渲染的表单数据 &#xff09;3&#xff1a;App.vue ( 导入editor组件传递data.json之中的数据与 向下提供组件配置数据config )4&#xff1a;src / packages / editor…