RK3568笔记二十二:基于TACO的垃圾检测和识别

若该文为原创文章,转载请注明原文出处。

基于TACO数据集,使用YOLOv8分割模型进行垃圾检测和识别,并在ATK-RK3568上部署运行。

一、环境

1、测试训练环境:AutoDL.

2、平台:rk3568

3、开发板: ATK-RK3568正点原子板子

4、环境:buildroot

5、虚拟机:正点原子提供的ubuntu 20

二、测试

个人电脑没有GPU,在AutoDL租了服务器,配置如下:将在上面测试并训练。

PyTorch  1.8.1
Python  3.8(ubuntu18.04) 

CUDA 11.0

三、环境安装

1、使用conda创建虚拟环境

conda create -n yolov8 python=3.8
conda activate yolov8

2、 安装YOLOv8

# 拉取代码
git clone https://github.com/ultralytics/ultralytics
cd ultralytics

pip install -e .

三、下载TACO数据集

TACO 是一个包含在不同环境下(室内、树林、道路和海滩) 拍摄的垃圾图像数据集。

下载地址:

git clone https://github.com/pedropro/TACO.git

进入TACO目录

运行脚本下载图像数据,默认下载官方数据集(annotations.json)是1500张。

python download.py

下载成功后会在data目录下看到很多数据集

在TACO目录下创建demo_test.py,内容如下,可以查看数据集的相关信息:

# 参考demo.ipynb,查看官方数据集整体信息
# demo_test.py
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()

dataset_path = './data'
anns_file_path = dataset_path + '/' + 'annotations.json'

# Read annotations
with open(anns_file_path, 'r') as f:
    dataset = json.loads(f.read())

categories = dataset['categories']
anns = dataset['annotations']
imgs = dataset['images']
nr_cats = len(categories)
nr_annotations = len(anns)
nr_images = len(imgs)

# Load categories and super categories
cat_names = []
super_cat_names = []
super_cat_ids = {}
super_cat_last_name = ''
nr_super_cats = 0
for cat_it in categories:
    cat_names.append(cat_it['name'])
    super_cat_name = cat_it['supercategory']
    # Adding new supercat
    if super_cat_name != super_cat_last_name:
        super_cat_names.append(super_cat_name)
        super_cat_ids[super_cat_name] = nr_super_cats
        super_cat_last_name = super_cat_name
        nr_super_cats += 1

print('Number of super categories:', nr_super_cats)
print('Number of categories:', nr_cats)
print('Number of annotations:', nr_annotations)
print('Number of images:', nr_images)

在运行测试前先安装一些文件

pip install requirements.txt

安装后执行python demo_test.py

执行后输出

总共1500张图像,有60个类别,4784个标注。

四、数据集处理

TACO数据集标注信息和COCO格式一样,我们需要将数据集划分,并转换成YOLO格式。

利用TACO仓库提供的detector/split_dataset.py,我们将TACO数据集的标注信息annotations.json划分成三份 train, val, test,生成对应的json文件。

python  detector/split_dataset.py --dataset_dir ./data  --test_percentage 5 --val_percentage 10 --nr_trials 1

在TACO目录下执行上面命令, 将在data目录下生成annotations_0_train.json,annotations_0_val.json,annotations_0_test.json三个文件, 并且划分测试集占5%,评估数据占10%,剩下的是训练集数据。

由于YOLOv8分割模型训的标注格式如下:

<id> <x_1> <y_1> ... <x_n> <y_n>

具体的形式,可以参考yolov8-seg测试数据 COCO8-Seg数据集 。

所以使用下面代码把前面将划分的数据集的json文件,然后转换成yolo数据集要求的格式

在TACO目录 下创建taco2yolo.py,内容如下:

import os
from pycocotools.coco import COCO
import numpy as np
import tqdm
import argparse
import shutil

def arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('--annotation_path', type=str,default='./data/annotations.json', help='dataset annotations')
    parser.add_argument('--save_path', type=str, default='./taco')
    parser.add_argument('--subset', type=str, default='train', required=False, help='which subset(train, val, test)')
    args = parser.parse_args()
    return args


if __name__ == '__main__':
    args = arg_parser()
    annotation_path = args.annotation_path
    yolo_image_path = args.save_path + '/images/' + args.subset
    yolo_label_path = args.save_path +'/labels/' + args.subset

    os.makedirs(yolo_image_path, exist_ok=True)
    os.makedirs(yolo_label_path, exist_ok=True)

    data_source = COCO(annotation_file=annotation_path)

    # 类别ID
    catIds = data_source.getCatIds()
    # 获取类别名称
    categories = data_source.loadCats(catIds)
    categories.sort(key=lambda x: x['id'])

    # 保存类别
    class_path = args.save_path + '/classes.txt'
    with open(class_path, "w") as file:
        for item in categories:
            file.write(f"{item['id']}: {item['name']}\n")

    #遍历每张图片
    img_ids = data_source.getImgIds()
    for index, img_id in tqdm.tqdm(enumerate(img_ids)):
        img_info = data_source.loadImgs(img_id)[0]
        file_name = img_info['file_name'].replace('/', '_')
        save_name = file_name.split('.')[0]

        height = img_info['height']
        width = img_info['width']

        save_label_path = yolo_label_path + '/' + save_name + '.txt'
        with open(save_label_path, mode='w') as fp:
            annotation_id = data_source.getAnnIds(img_id)
            if len(annotation_id) == 0:
                fp.write('')
                shutil.copy('data/{}'.format(img_info['file_name']), os.path.join(yolo_image_path, file_name))
                continue

            annotations = data_source.loadAnns(annotation_id)

            for annotation in annotations:
                category_id = annotation["category_id"]
                seg_labels = []
                for segmentation in annotation["segmentation"]:
                    points = np.array(segmentation).reshape((int(len(segmentation) / 2), 2))
                    for point in points:
                        x = point[0] / width
                        y = point[1] / height
                        seg_labels.append(x)
                        seg_labels.append(y)
                fp.write(str(category_id) + " " + " ".join([str(a) for a in seg_labels]) + "\n")

        shutil.copy('data/{}'.format(img_info['file_name']), os.path.join(yolo_image_path, file_name))

执行下面生成各种数据集:

1、 测试集数据

python taco2yolo.py --annotation_path ./data/annotations_0_test.json  --subset test

运行出错:ModuleNotFoundError: No module named 'pycocotools'
安装:pip install pycocotools

2、评估集

python taco2yolo.py --annotation_path ./data/annotations_0_val.json  --subset val

3、训练集

python taco2yolo.py --annotation_path ./data/annotations_0_train.json  --subset train

会在当前目录下生成TACO目录结构如下:

五、模型训练

需要添加两个文件,数据集配置文件和模型配置文件。

1、新增数据集配置文件

在 ultralytics/cfg/datasets/下创建一个名称为taco-seg.yaml的文件,内容如下:


path: /root/TACO-master/taco # dataset root dir
train: images/train # train images (relative to 'path')
val: images/val # val images (relative to 'path')
test: images/test # test images (optional)

# Classes
names:
  0: Aluminium foil
  1: Battery
  2: Aluminium blister pack
  3: Carded blister pack
  4: Other plastic bottle
  5: Clear plastic bottle
  6: Glass bottle
  7: Plastic bottle cap
  8: Metal bottle cap
  9: Broken glass
  10: Food Can
  11: Aerosol
  12: Drink can
  13: Toilet tube
  14: Other carton
  15: Egg carton
  16: Drink carton
  17: Corrugated carton
  18: Meal carton
  19: Pizza box
  20: Paper cup
  21: Disposable plastic cup
  22: Foam cup
  23: Glass cup
  24: Other plastic cup
  25: Food waste
  26: Glass jar
  27: Plastic lid
  28: Metal lid
  29: Other plastic
  30: Magazine paper
  31: Tissues
  32: Wrapping paper
  33: Normal paper
  34: Paper bag
  35: Plastified paper bag
  36: Plastic film
  37: Six pack rings
  38: Garbage bag
  39: Other plastic wrapper
  40: Single-use carrier bag
  41: Polypropylene bag
  42: Crisp packet
  43: Spread tub
  44: Tupperware
  45: Disposable food container
  46: Foam food container
  47: Other plastic container
  48: Plastic glooves
  49: Plastic utensils
  50: Pop tab
  51: Rope & strings
  52: Scrap metal
  53: Shoe
  54: Squeezable tube
  55: Plastic straw
  56: Paper straw
  57: Styrofoam piece
  58: Unlabeled litter
  59: Cigarette

需要注意人的是PATH:  训练集路径

2、新增修改模型配置文件

在目录ultralytics/cfg/models/v8/ 下创建文件yolov8n-seg-taco.yaml,内容如下:


# Ultralytics YOLO 馃殌, AGPL-3.0 license
# YOLOv8-seg instance segmentation model. For Usage examples see https://docs.ultralytics.com/tasks/segment

# Parameters
nc: 60 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n-seg.yaml' will call yolov8-seg.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]
  s: [0.33, 0.50, 1024]
  m: [0.67, 0.75, 768]
  l: [1.00, 1.00, 512]
  x: [1.00, 1.25, 512]

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 3, C2f, [512]] # 12

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 3, C2f, [256]] # 15 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]] # cat head P4
  - [-1, 3, C2f, [512]] # 18 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]] # cat head P5
  - [-1, 3, C2f, [1024]] # 21 (P5/32-large)

  - [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Segment(P3, P4, P5)


接下来使用命令训练模型:

 yolo segment train data=taco-seg.yaml model=yolov8n-seg-taco.yaml epochs=100 batch=16 imgsz=640
 yolo segment val model=runs/segment/train/weights/last.pt

等待训练结束,会在runs/segment/train/weights目录下生成pt模型文件。

对训练的模型进行评估:

六、模型导出

部署到 ATK-RK3568用的是RKNN模型,需要先把pt模型转成ONNX在转成RKNN.

使用RK提供的airockchip/ultralytics_yolov8 仓库转换并导出。

拉取仓库:

在root目录下,拉取airockchip/ultralytics_yolov8

git clone https://github.com/airockchip/ultralytics_yolov8.git
cd ultralytics_yolov8

修改ultralytics/cfg/default.yaml文件:

修改这个文件主要是修改模型的地址

1、导出ONNX模型

先执行命令,主要是切换路径

export PYTHONPATH=./

执行命令导出

python ultralytics/engine/exporter.py

出错:ModuleNotFoundError: No module named 'onnx'

处理:pip install onnx

导出的onnx模型保存在best.pt模型路径下,名称为best.onnx,使用 Netron 查看下该模型的输出:

经过ultralytics_yolov8仓库导出的onnx模型,输入是13x640x640,输出总共13个,分为三个特征图相关(12个)和一个分割掩码(132x160x160)

以特征图8080为例,相关的输出为164x80x80、160x80x80、11x80x80、132x80x80。

  • 第一个164x80x80与检测框坐标相关,经过相关后处理得到框的坐标(x1, y1, w, h);

  • 第二个160x80x80,“80x80”表示检测框数量,“60”表示60个类别的置信度;

  • 第三个11x80x80,表示检测框的60个类别的置信度的总和,用于在后处理加速过滤框;

  • 第四个132x80x80是和分割掩码相关的权重。

2、转成RKNN

rknn模型是通过 toolkit2 转换的。环境搭建自行搭建。

参考简单的转换例程onnx2rknn.py

import os
import sys
import numpy as np
from rknn.api import RKNN
 
DATASET_PATH = '../dataset/coco_subset_20.txt'
DEFAULT_QUANT = True
 
def parse_arg():
    if len(sys.argv) < 3:
        print("Usage: python3 {} [onnx_model_path] [platform] [dtype(optional)] [output_rknn_path(optional)]".format(sys.argv[0]));
        print("       platform choose from [rk3562,rk3566,rk3568,rk3588]")
        print("       dtype choose from    [i8, fp]")
        print("Example: python onnx2rknn.py ./yolov8n.onnx rk3588")
        exit(1)
 
    model_path = sys.argv[1]
    platform = sys.argv[2]
 
    do_quant = DEFAULT_QUANT
    if len(sys.argv) > 3:
        model_type = sys.argv[3]
        if model_type not in ['i8', 'fp']:
            print("ERROR: Invalid model type: {}".format(model_type))
            exit(1)
        elif model_type == 'i8':
            do_quant = True
        else:
            do_quant = False
 
    if len(sys.argv) > 4:
        output_path = sys.argv[4]
    else:
        output_path = "./model/yolov8_seg_"+platform+".rknn"
 
    return model_path, platform, do_quant, output_path
 
if __name__ == '__main__':
    model_path, platform, do_quant, output_path = parse_arg()
 
    # Create RKNN object
    rknn = RKNN(verbose=False)
 
    # Pre-process config
    print('--> Config model')
    rknn.config(mean_values=[[0, 0, 0]], std_values=[
                    [255, 255, 255]], target_platform=platform)
    print('done')
 
    # Load model
    print('--> Loading model')
    ret = rknn.load_onnx(model=model_path)
    #ret = rknn.load_pytorch(model=model_path, input_size_list=[[1, 3, 640, 640]])
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')
 
    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=do_quant, dataset=DATASET_PATH)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')
 
    # Export rknn model
    print('--> Export rknn model')
    ret = rknn.export_rknn(output_path)
    if ret != 0:
        print('Export rknn model failed!')
        exit(ret)
    print('done')
 
    # 精度分析,,输出目录./snapshot
    #print('--> Accuracy analysis')
    #ret = rknn.accuracy_analysis(inputs=['./subset/000000052891.jpg'])
    #if ret != 0:
    #    print('Accuracy analysis failed!')
    #    exit(ret)
    #print('done')
 
    # Release
    rknn.release()

执行下面命令转成RKNN模型

python onnx2rknn.py best.onnx rk3568 i8

七、部署测试

对yolov8-seg模型的后处理参考 rknn_model_zoo 的部署例程。

推理程序大致步骤是:

  • 读取图像,初始化模型,图像预处理

  • 模型推理

  • 后处理(boxes解码和NMS以及mask的处理)

  • 结果可视化或者保存到图像

测试参考前面文章自行测试。

测试结果

如有侵权,或需要完整代码,请及时联系博主。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu Vs code配置ROS开发环境

文章目录 1.开发环境2.集成开发环境搭建2.1 安装Ros2.2 安装 Vs code2.3 安装vs code 插件 3.Vs code 配置ROS3.1 创建ROS工作空间3.2 从文件夹启动Vs code3.3 使用Vscode 编译ROS 空间3.4 使用Vs code 创建功能包 4.编写简单Demo实例4.1编写代码4.2编译与执行 1.开发环境 系统…

(文章复现)分布式电源选址定容的多目标优化算法

参考文献&#xff1a; [1]夏澍,周明,李庚银.分布式电源选址定容的多目标优化算法[J].电网技术,2011,35(09):115-121. [2] Ye Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, “PlatEMO: A MATLAB platform for evolutionary multi-objective optimization [educational for…

毕设论文的分类号与UDC查询

对于毕业论文分类号与UDC&#xff0c;可以根据个人研究领域查询。 中图分类号查询链接&#xff1a; 中图分类号查询 | 中国图书馆分类法 | 中图法 | 中图分类号 (clcindex.com)https://www.clcindex.com/category/ UDC查询链接: UDC Summaryhttps://udcsummary.info/php/ind…

探秘计算机内部的魔法:模拟计算机内部的怎么使用门电路实现运算的奥秘

1.前言 在当今数字时代&#xff0c;我们享受着计算机带来的便利和效率&#xff0c;但很少有人意识到在计算机背后的神秘世界。计算机内部运算的奥秘并非仅仅是一系列简单的加减乘除&#xff0c;而是依托着深奥的门电路与位运算符展开的神秘舞蹈。在这篇博客中&#xff0c;我们…

Web3与社会契约:去中心化治理的新模式

在数字化时代&#xff0c;技术不断为我们提供新的可能性&#xff0c;而Web3技术作为一种基于区块链的创新&#xff0c;正在引领着互联网的下一波变革。它不仅改变了我们的经济模式和商业逻辑&#xff0c;还对社会契约和权力结构提出了全新的挑战和思考。本文将深入探讨Web3的基…

OpenAI宣布GPT-4-Turbo全面升级,GPT-4 Turbo 新增视觉理解能力,可同时处理文本和图像信息

OpenAI宣布GPT-4-Turbo全面升级&#xff0c;GPT-4 Turbo with Vision新增视觉理解能力&#xff0c;可同时处理文本和图像信息&#xff0c;极大简化了开发流程。 OpenAI宣布GPT-4 Turbo全面升级&#xff01;根据官方说法&#xff0c;这一波 GPT 的升级包括&#xff1a; 更长的上…

Buck变换电路

Buck变换电路 Buck变换电路是最基本的DC/DC拓扑电路&#xff0c;属于非隔离型直流变换器&#xff0c;其输出电压小于输入电压。Buck变换电路具有效率高、输出稳定、控制简单和成本低的优点&#xff0c;广泛应用于稳压电源、光伏发电、LED驱动和能量回收系统。 电路原理 Buck变…

bestvike --bvframe学习

ref title fetch后台api 分页属性&#xff0c;pagination 要差几条&#xff1f;pagelimit 在api中写一个饭方法&#xff0c;vue中用用他 vue.cinfig.js中配置别名 nacos微服务 实体类要继承basedata&#xff08;封装了公共数据&#xff09; 控制器autowired&#xff0c;getm…

【Java开发指南 | 第四篇】Java常量、自动类型转换、修饰符

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 Java常量自动类型转换Java修饰符 Java常量 常量在程序运行时是不能被修改的。 在 Java 中使用 final 关键字来修饰常量&#xff0c;声明方式和变量类似&#xff1a; final double PI 3.1415927;自动类型转换…

大数据平台搭建2024(一)

一&#xff1a;基础配置 创建虚拟机并查出ip地址进行连接 ip a1.配置node01静态ip地址与主机名 vi /etc/sysconfig/network-scripts/ifcfg-ens33修改或添加如下内容&#xff1a; BOOTPROTO"static" ONBOOTyes #根据虚拟机网卡信息配置 IPADDR192.168.200.141 NET…

ENVI实战—一文学会使用GLT配准工具对风云数据进行几何校正

实验2&#xff1a;学会使用GLT配准工具 目的&#xff1a;完成气象卫星数据的校正&#xff0c;掌握利用GLT配准工具实验地理配准的方法 过程&#xff1a; ①读取影像&#xff1a;选择“文件”&#xff0c;选择“HS5”文件并打开&#xff0c;在弹出的科学数据集浏览器中&#x…

秘塔和Kimi AI在资料查询和学习中的使用对比

一、引言 最近老猿在网上查资料时&#xff0c;基本上都使用Kimi AI进行查询&#xff0c;发现其查询资料后总结到位&#xff0c;知识点的准确度较高。今天早上收到一个消息&#xff0c;说新推出的秘塔AI比Kimi更新进&#xff0c;老猿利用在学习的《统计知识学习》简单对比试用了…

JS算法题:找到数组中第 k 大的元素

问题描述&#xff1a; 给定一个未排序的整数数组&#xff0c;找到其中第 k 大的元素。注意&#xff0c;你可以假设 k 总是有效的&#xff0c;且 1 ≤ k ≤ 数组的长度。 举个例子&#xff1a; 如果给定数组是 [3,2,1,5,6,4]&#xff0c;k 是 2&#xff0c;那么第 2 大的元素…

每日OJ题_BFS解决FloodFill①_力扣733. 图像渲染

目录 BFS解决FloodFill简介 力扣733. 图像渲染 解析代码 BFS解决FloodFill简介 FloodeFill算法即填充算法&#xff0c;中文&#xff1a;洪水灌溉&#xff0c;算法原理就是从一个点开始向四周扩散&#xff0c;向周围可以走到的点填充颜色&#xff0c;直到将可扩散到的点全部填…

(踩坑)Please refer to 异常和Error creating bean with name 异常

一、Please refer to 异常 如图所示&#xff0c;在使用maven构建项目的时候&#xff0c;如果提示该错误&#xff0c;则可能是xml配置文件有问题或者测试类等。但是没有明确的异常信息&#xff0c;所以做以下小改动&#xff0c;可以查看异常信息。 在IDEA工具中&#xff0c;打…

【C/C++笔试练习】read函数、虚拟存储、用户态、线程特点、缺页处理、调度算法、进程优先级、锁的使用、创建进程、不用加减乘除做加法、三角形

文章目录 C/C笔试练习选择部分&#xff08;1&#xff09;read函数&#xff08;2&#xff09;虚拟存储&#xff08;3&#xff09;用户态&#xff08;4&#xff09;线程特点&#xff08;5&#xff09;缺页处理&#xff08;6&#xff09;调度算法&#xff08;7&#xff09;进程优先…

JDK1.8新特性

JDK8新特性 ​ Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台 课程内容的介绍 了解Java发展史Lambda表达式…

数字人项目 ER-NeRF 的使用和部署详细教程

文章目录 1. ER-NeRF简介2. ER-NeRF部署3. 训练自己的数字人4. 生成数字人视频5. 其他数字人模型比较常见错误 1. ER-NeRF简介 ER-NeRF&#xff08;官方链接&#xff09;是一个Talking Portrait Synthesis&#xff08;对嘴型&#xff09;项目。即&#xff1a;给一段某人说话的…

微信小程序-长按显示,点击空白区域关闭

<view bind:tap"closeLongAction"><view bind:longpress"openAction></view><view wx:if"{{longActionIsShow}}"> 长按显示的区域 </view> </view>openAction(e) {console.log(322,e);this.setData({longActionI…

【解读】《中华人民共和国网络安全法》:所有IT从业者都应知应懂

随着网络的快速发展&#xff0c;当今社会存在的网络安全问题也是接踵而来&#xff1a;网络入侵、网络攻击等非法活动威胁信息安全&#xff1b;非法获取公民信息、侵犯知识产权、损害公民合法利益&#xff1b;宣扬恐怖主义、极端主义&#xff0c;严重危害国家安全和社会公共利益…
最新文章