这篇文章主要是简述RK3568部署YOLOV11,主要是由于正点原子的教程里面没有介绍yolo11的配置过程,所有想着自己配置一下,不涉及训练过程,配置模型测试过程如下,首先你得跑过正点原子的相关教程因为不会涉及到SDK,包和编译链的安装。

首先大概讲一下转换过程,模型转换,以下模型转换成rknn模型。
PyTorch 模型:.pt文件、.pth文件
RKNN-Toolkit2 通常通过先将 PyTorch 模型导出为 ONNX 格式,再进行转换。您需要先在 PyTorch 中将模型保存为 .pt或 .pth文件,或直接导出为 ONNX 格式。
ONNX 模型:.onnx文件(这是连接不同框架的通用中间格式,非常常用)。

在这里插入图片描述
参考文章链接:
https://blog.csdn.net/qq_29676069/article/details/151626417?fromshare=blogdetail&sharetype=blogdetail&sharerId=151626417&sharerefer=PC&sharesource=weixin_52531699&sharefrom=from_link

https://gitee.com/wirelesser/rknn_model_zoo/blob/main/examples/yolov8/README.md

http://www.lryc.cn/news/493681.html?action=onClick

一.部署YOLOV11过程

具体的数据集制作以及训练步骤不做过多解释,
首先下载代码:https://github.com/airockchip/ultralytics_yolo11
在这里插入图片描述
我试过用ultralytics官方代码没有问题的。

在这里插入图片描述
然后再下载一个权重文件,我下载的是yolo11n.pt文件。将权重文件放到代码中去,随意放会要指定路径的。
需要在./ultralytics/cfg/default.yaml中修改自己的权重模型文件路径,也就是之前yolo11n.pt。我是直接将训练好的权重文件放在上图中的文件夹内的。所以将default.yaml中第8行文件路径设置如下:
在这里插入图片描述
然后在以下路径中找到exporter.py文件,运行即可。
在这里插入图片描述
在这里插入图片描述
你就会得到yolo11n.onnx文件。

ONNX → RKNN,并在 PC 上验证
本文的安装交叉编译工具链、adbd服务、更新npu驱动、安装rknn-toolkit2转换环境可参考正点原子官方资料“开发板光盘A盘-基础资料->10、用户手册->01、测试文档->03【正点原子】ATK-DLRK3568_AI例程测试手册V1.0.pdf”。

转换 RKNN 模型
接下来不要用正点原子官方资料中的rknn_model_zoo他的版本太老了,里面没有测试yolov11模型。去官网下载rknn_model_zoo
在这里插入图片描述
文件进行解压,解压到software目录下。同时,根据官方手册的提示,将rknn_model_zoo-2.3.0的文件夹名称改为rknn_model_zoo,避免后续出现报错。打开虚拟机终端,进入modelzoo目录下,执行权限命令。

cd rknn_model_zoo 
chmod +x build-linux.sh

将上一节中得到的onnx模型拷贝至如下文件夹中,在命令行中输入指令,进入对应文件夹。

cd examples/yolo11/model 

在这里插入图片描述
后面那两张图片不用管是我测试生成,以及自己加的。

激活自己的环境,表示执行convert.py的代码,使用的模型为之前拷贝进model文件夹中的yolo11.onnx,对象为rk3568,i8指转换模型的量化精度

conda activate python3.10-tk2-2.0
python3 convert.py ../model/yolo11n.onnx rk3568 i8

在这里插入图片描述

成功生成yolo11.rknn。生成的模型在model文件夹中。在这里插入图片描述

PC 上验证 ONNX 和 RKNN(非常关键)
对于新手来讲,不知道自己生成的onnx和rknn模型是否正确,所以需要在虚拟机上对两个模型进行验证,使用项目自带的yolo11.py来验证:

首先,进入python目录下,打开命令行,进入python环境,在命令行中输入:

python3 yolo11.py --model_path ../model/yolo11n.onnx --img_folder ../model --img_show

在这里插入图片描述
运行后能得到正确的识别图片,说明onnx模型没问题。

接下来验证rknn模型,还是使用同样的代码进行验证。不过要注意的是,测试过程全部放在正点原子的RKNN3568开发板上了。后续再说。

编译 YOLO11 Demo
先查看build-linux.sh 用法,这个是将刚才我们的文件目录整个编译为可以传输到板子上的编译器。

在运行build-linux.sh之前,需要先设置编译链接,设置完成之后编译./build-linux.sh

export GCC_COMPILER=/opt/atk-dlrk356x-toolchain/usr/bin/aarch64-buildroot-linux-gnu
./build-linux.sh -t rk3568 -a aarch64 -d yolo11

在这里插入图片描述

在这里插入图片描述

编译完成之后上传至开发板。

alientek@alientek-virtual-machine:~/software/rknn_model_zoo$ adb push install/rk356x_linux_aarch64/rknn_yolo11_demo /userdata/aidemo
install/rk356x_linux_aarch64/rknn_yolo11_demo/: 7 files pushed, 0 skipped. 1.1 MB/s (14663105 bytes in 13.193s)

在这里插入图片描述
从这里大概明白了一个点就是yolo模型的部署只需要传输以上文件,主要是库和模型,那么以上库传输完成后那么我的应用程序也就可以随便写,不一定要按照main.cc格式,其实部署完成模型后你就可以把它当成一个库了,随时调用即可。这也会是后续QT屏幕显示加摄像头识别的突破口。

串口打开开发板,测试模型

./rknn_yolo11_demo model/yolo11.rknn model/bus.jpg

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

终端中拉取图片:

alientek@alientek-virtual-machine:~/software/aidemo$ adb pull /userdata/aidemo/rknn_yolo11_demo/out.png
/userdata/aidemo/rknn_yolo11_demo/out....ped. 1.1 MB/s (719262 bytes in 0.640s)

在这里插入图片描述
好的RK3568上模型测试没有问题,以上就是整个测试流程。

二.涉及知识细节讲解

build-linux.sh文件讲解

build-linux.sh是一个用于自动化交叉编译RKNN AI示例程序的智能构建脚本。它封装了复杂的交叉编译配置流程,使您只需指定目标平台和要构建的示例名称,就能自动完成整个编译过程。
这个脚本主要完成以下工作:
参数解析:解析用户输入的目标平台、架构、示例名称等参数
环境配置:自动设置交叉编译器和相关环境变量
路径查找:查找指定示例的源代码目录
构建配置:生成CMake构建配置
编译安装:执行编译并将结果安装到指定目录
结果验证:检查是否包含必要的模型文件

#!/bin/bash

set -e

echo "$0 $@"
while getopts ":t:a:d:b:m:r:j" opt; do
  case $opt in
    t)
      TARGET_SOC=$OPTARG
      ;;
    a)
      TARGET_ARCH=$OPTARG
      ;;
    b)
      BUILD_TYPE=$OPTARG
      ;;
    m)
      ENABLE_ASAN=ON
      export ENABLE_ASAN=TRUE
      ;;
    d)
      BUILD_DEMO_NAME=$OPTARG
      ;;
    r)
      DISABLE_RGA=ON
      ;;
    j)
      DISABLE_LIBJPEG=ON
      ;;
    :)
      echo "Option -$OPTARG requires an argument." 
      exit 1
      ;;
    ?)
      echo "Invalid option: -$OPTARG index:$OPTIND"
      ;;
  esac
done

if [ -z ${TARGET_SOC} ] || [ -z ${BUILD_DEMO_NAME} ]; then
  echo "$0 -t <target> -a <arch> -d <build_demo_name> [-b <build_type>] [-m] [-r] [-j]"
  echo ""
  echo "    -t : target (rk356x/rk3588/rk3576/rv1126b/rv1106/rk1808/rv1126)"
  echo "    -a : arch (aarch64/armhf)"
  echo "    -d : demo name"
  echo "    -b : build_type(Debug/Release)"
  echo "    -m : enable address sanitizer, build_type need set to Debug"
  echo "    -r : disable rga, use cpu resize image"
  echo "    -j : disable libjpeg to avoid conflicts between libjpeg and opencv"
  echo "such as: $0 -t rk3588 -a aarch64 -d mobilenet"
  echo "Note: 'rk356x' represents rk3562/rk3566/rk3568, 'rv1106' represents rv1103/rv1106, 'rv1126' represents rv1109/rv1126, 'rv1126b' is different from 'rv1126'"
  echo "Note: 'disable rga option is invalid for rv1103/rv1103b/rv1106"
  echo "Note: 'if you want to use opencv to read or save jpg files, use the '-j' option to disable libjpeg"
  echo ""
  exit -1
fi

if [[ -z ${GCC_COMPILER} ]];then
    if [[ ${TARGET_SOC} = "rv1106"  || ${TARGET_SOC} = "rv1103" ]];then
        echo "Please set GCC_COMPILER for $TARGET_SOC"
        echo "such as export GCC_COMPILER=~/opt/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf"
        exit
    elif [[ ${TARGET_SOC} = "rv1109" || ${TARGET_SOC} = "rv1126" ]];then
        GCC_COMPILER=arm-linux-gnueabihf
    else
        GCC_COMPILER=aarch64-linux-gnu
    fi
fi
echo "$GCC_COMPILER"
export CC=${GCC_COMPILER}-gcc
export CXX=${GCC_COMPILER}-g++

if command -v ${CC} >/dev/null 2>&1; then
    :
else
    echo "${CC} is not available"
    echo "Please set GCC_COMPILER for $TARGET_SOC"
    echo "such as export GCC_COMPILER=~/opt/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf"
    exit
fi

# Debug / Release
if [[ -z ${BUILD_TYPE} ]];then
    BUILD_TYPE=Release
fi

# Build with Address Sanitizer for memory check, BUILD_TYPE need set to Debug
if [[ -z ${ENABLE_ASAN} ]];then
    ENABLE_ASAN=OFF
fi

if [[ -z ${DISABLE_RGA} ]];then
    DISABLE_RGA=OFF
fi

if [[ -z ${DISABLE_LIBJPEG} ]];then
    DISABLE_LIBJPEG=OFF
fi

for demo_path in `find examples -name ${BUILD_DEMO_NAME}`
do
    if [ -d "$demo_path/cpp" ]
    then
        BUILD_DEMO_PATH="$demo_path/cpp"
        break;
    fi
done

if [[ -z "${BUILD_DEMO_PATH}" ]]
then
    echo "Cannot find demo: ${BUILD_DEMO_NAME}, only support:"

    for demo_path in `find examples -name cpp`
    do
        if [ -d "$demo_path" ]
        then
            dname=`dirname "$demo_path"`
            name=`basename $dname`
            echo "$name"
        fi
    done
    echo "rv1106_rv1103 only support: mobilenet and yolov5/6/7/8/x"
    exit
fi

case ${TARGET_SOC} in
    rk356x)
        ;;
    rk3588)
        ;;
    rv1106)
        ;;
    rv1103)
        TARGET_SOC="rv1106"
        ;;
    rk3566)
        TARGET_SOC="rk356x"
        ;;
    rk3568)
        TARGET_SOC="rk356x"
        ;;
    rk3562)
        TARGET_SOC="rk356x"
        ;;
    rk3576)
        TARGET_SOC="rk3576"
        ;;
    rk1808):
        TARGET_SOC="rk1808"
        ;;
    rv1109)
        ;;
    rv1126)
        TARGET_SOC="rv1126"
        ;;
    rv1126b)
        TARGET_SOC="rv1126b"
        ;;
    *)
        echo "Invalid target: ${TARGET_SOC}"
        echo "Valid target: rk3562,rk3566,rk3568,rk3588,rk3576,rv1106,rv1103,rk1808,rv1109,rv1126,rv1126b"
        exit -1
        ;;
esac

TARGET_SDK="rknn_${BUILD_DEMO_NAME}_demo"

TARGET_PLATFORM=${TARGET_SOC}_linux
if [[ -n ${TARGET_ARCH} ]];then
TARGET_PLATFORM=${TARGET_PLATFORM}_${TARGET_ARCH}
fi
ROOT_PWD=$( cd "$( dirname $0 )" && cd -P "$( dirname "$SOURCE" )" && pwd )
INSTALL_DIR=${ROOT_PWD}/install/${TARGET_PLATFORM}/${TARGET_SDK}
BUILD_DIR=${ROOT_PWD}/build/build_${TARGET_SDK}_${TARGET_PLATFORM}_${BUILD_TYPE}

echo "==================================="
echo "BUILD_DEMO_NAME=${BUILD_DEMO_NAME}"
echo "BUILD_DEMO_PATH=${BUILD_DEMO_PATH}"
echo "TARGET_SOC=${TARGET_SOC}"
echo "TARGET_ARCH=${TARGET_ARCH}"
echo "BUILD_TYPE=${BUILD_TYPE}"
echo "ENABLE_ASAN=${ENABLE_ASAN}"
echo "DISABLE_RGA=${DISABLE_RGA}"
echo "DISABLE_LIBJPEG=${DISABLE_LIBJPEG}"
echo "INSTALL_DIR=${INSTALL_DIR}"
echo "BUILD_DIR=${BUILD_DIR}"
echo "CC=${CC}"
echo "CXX=${CXX}"
echo "==================================="

if [[ ! -d "${BUILD_DIR}" ]]; then
  mkdir -p ${BUILD_DIR}
fi

if [[ -d "${INSTALL_DIR}" ]]; then
  rm -rf ${INSTALL_DIR}
fi

cd ${BUILD_DIR}
cmake ../../${BUILD_DEMO_PATH} \
    -DTARGET_SOC=${TARGET_SOC} \
    -DCMAKE_SYSTEM_NAME=Linux \
    -DCMAKE_SYSTEM_PROCESSOR=${TARGET_ARCH} \
    -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
    -DENABLE_ASAN=${ENABLE_ASAN} \
    -DDISABLE_RGA=${DISABLE_RGA} \
    -DDISABLE_LIBJPEG=${DISABLE_LIBJPEG} \
    -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}
make -j4
make install

# Check if there is a rknn model in the install directory
suffix=".rknn"
shopt -s nullglob
if [ -d "$INSTALL_DIR" ]; then
    files=("$INSTALL_DIR/model/"/*"$suffix")
    shopt -u nullglob

    if [ ${#files[@]} -le 0 ]; then
        echo -e "\e[91mThe RKNN model can not be found in \"$INSTALL_DIR/model\", please check!\e[0m"
    fi
else
    echo -e "\e[91mInstall directory \"$INSTALL_DIR\" does not exist, please check!\e[0m"
fi

生成的路径示例(以./build-linux.sh -t rk3568 -a aarch64 -d yolo11为例):
BUILD_DIR: build/build_rknn_yolo11_demo_rk356x_linux_aarch64_Release/
INSTALL_DIR: install/rk356x_linux_aarch64/rknn_yolo11_demo/

再然后就会自动调取进入构建目录,运行CMake配置项目,传递所有必要的参数。

Cmake文件讲解

build-linux.sh脚本确实会自动调用 CMake,但关键在于:它会根据您指定的 -d yolo11参数,自动找到并调用对应示例(yolo11)目录下的 CMakeLists.txt。

您执行的命令
↓
./build-linux.sh -t rk3568 -a aarch64 -d yolo11
    ↓
脚本自动查找对应示例
    ↓
找到 examples/yolo11/cpp/CMakeLists.txt  ← 您提供的这个文件
    ↓
脚本执行: cd build/... && cmake ../../examples/yolo11/cpp/
    ↓
CMake 读取您提供的 CMakeLists.txt
    ↓
生成 Makefile → 编译 → 安装
cmake_minimum_required(VERSION 3.10)

project(rknn_yolo11_demo)

if (ENABLE_ASAN)
	message(STATUS "BUILD WITH ADDRESS SANITIZER")
	set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
	set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
	set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
endif ()

set(rknpu_yolo11_file rknpu2/yolo11.cc)

if (TARGET_SOC STREQUAL "rv1106" OR TARGET_SOC STREQUAL "rv1103")
    add_definitions(-DRV1106_1103)
    set(rknpu_yolo11_file rknpu2/yolo11_rv1106_1103.cc)
    #dma
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/allocator/dma)
endif()

if(TARGET_SOC STREQUAL "rk1808" OR TARGET_SOC STREQUAL "rv1109" OR TARGET_SOC STREQUAL "rv1126")
    add_definitions(-DRKNPU1)
    set(rknpu_yolo11_file rknpu1/yolo11.cc)
endif()

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/ 3rdparty.out)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../utils/ utils.out)

set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")

file(GLOB SRCS ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)

add_executable(${PROJECT_NAME}
    main.cc
    postprocess.cc
    ${rknpu_yolo11_file}
)

target_link_libraries(${PROJECT_NAME}
    imageutils
    fileutils
    imagedrawing    
    ${LIBRKNNRT}
    dl
)

if (CMAKE_SYSTEM_NAME STREQUAL "Android")
    target_link_libraries(${PROJECT_NAME}
    log
)
endif()

message(STATUS "!!!!!!!!!!!CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
    set(THREADS_PREFER_PTHREAD_FLAG ON)
    find_package(Threads REQUIRED)
    target_link_libraries(${PROJECT_NAME} Threads::Threads)
endif()

target_include_directories(${PROJECT_NAME} PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${LIBRKNNRT_INCLUDES}
)


# Currently zero copy only supports rknpu2, v1103/rv1103b/rv1106 supports zero copy by default
if (NOT (TARGET_SOC STREQUAL "rv1106" OR TARGET_SOC STREQUAL "rv1103" OR TARGET_SOC STREQUAL "rk1808" 
    OR TARGET_SOC STREQUAL "rv1109" OR TARGET_SOC STREQUAL "rv1126" OR TARGET_SOC STREQUAL "rv1103b"))
    add_executable(${PROJECT_NAME}_zero_copy
        main.cc
        postprocess.cc
        rknpu2/yolo11_zero_copy.cc
    )

    target_compile_definitions(${PROJECT_NAME}_zero_copy PRIVATE ZERO_COPY)

    target_link_libraries(${PROJECT_NAME}_zero_copy
        imageutils
        fileutils
        imagedrawing    
        ${LIBRKNNRT}
        dl
    )

    if (CMAKE_SYSTEM_NAME STREQUAL "Android")
        target_link_libraries(${PROJECT_NAME}_zero_copy
        log
    )
    endif()

    if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
        set(THREADS_PREFER_PTHREAD_FLAG ON)
        find_package(Threads REQUIRED)
        target_link_libraries(${PROJECT_NAME}_zero_copy Threads::Threads)
    endif()

    target_include_directories(${PROJECT_NAME}_zero_copy PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${LIBRKNNRT_INCLUDES}
    )
    install(TARGETS ${PROJECT_NAME}_zero_copy DESTINATION .)
endif()

install(TARGETS ${PROJECT_NAME} DESTINATION .)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../model/bus.jpg DESTINATION model)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../model/coco_80_labels_list.txt DESTINATION model)
file(GLOB RKNN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/../model/*.rknn")
install(FILES ${RKNN_FILES} DESTINATION model)

使用yolo11.cc# 使用NPU1版本实现

再然后sh文件会自动安装
编译和安装
make -j4
make install
使用4个并行任务编译,然后安装到INSTALL_DIR。
在这里插入图片描述

最大的变化就是生成了这两个文件。

npu架构主要关注点是yolo.cc那么我改进算法的话是不是会报错呢?比如说加卷积了改特征融合层。

  1. yolo.cc的真正职责
    在rknn_model_zoo的框架中,yolo.cc(或yolo11.cc)文件主要负责:
    NPU运行时接口封装:调用librknnrt.so的API
    模型加载与卸载:通过RKNN API加载.rknn模型文件
    内存管理:为输入输出张量分配内存
    推理执行:执行前处理、调用NPU推理、获取输出
    与后处理模块的桥梁:将原始输出数据传递给postprocess.cc
    重要:yolo.cc不包含YOLO算法的网络结构定义,也不包含具体的后处理逻辑(如边界框解码、NMS等)。
  2. main.cc 关键应用程序,详细内容请看代码注释
// Copyright (c) 2024 by Rockchip Electronics Co., Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*-------------------------------------------
                Includes
-------------------------------------------*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "yolo11.h"
#include "image_utils.h"    // 图像处理工具
#include "file_utils.h"     // 文件操作工具
#include "image_drawing.h"  // 图像绘制功能

#if defined(RV1106_1103) 
    #include "dma_alloc.hpp"
#endif

/*-------------------------------------------
                  Main Function
-------------------------------------------*/
int main(int argc, char **argv)
{
    if (argc != 3)
    {
        printf("%s <model_path> <image_path>\n", argv[0]);
        return -1;
    }

    const char *model_path = argv[1];   // 第一个参数:模型文件路径
    const char *image_path = argv[2];   // 第二个参数:图片文件路径

    int ret;
    rknn_app_context_t rknn_app_ctx;    // 定义RKNN应用上下文结构体
    memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));

    init_post_process();

    ret = init_yolo11_model(model_path, &rknn_app_ctx);  // 初始化YOLOv11模型
    if (ret != 0)
    {
        printf("init_yolo11_model fail! ret=%d model_path=%s\n", ret, model_path);
        goto out;
    }

    image_buffer_t src_image;   // 定义图像缓冲区结构体
    memset(&src_image, 0, sizeof(image_buffer_t));
    ret = read_image(image_path, &src_image);  // 读取图片到缓冲区

#if defined(RV1106_1103) 
    //RV1106 rga requires that input and output bufs are memory allocated by dma
    ret = dma_buf_alloc(RV1106_CMA_HEAP_PATH, src_image.size, &rknn_app_ctx.img_dma_buf.dma_buf_fd, 
                       (void **) & (rknn_app_ctx.img_dma_buf.dma_buf_virt_addr));
    memcpy(rknn_app_ctx.img_dma_buf.dma_buf_virt_addr, src_image.virt_addr, src_image.size);
    dma_sync_cpu_to_device(rknn_app_ctx.img_dma_buf.dma_buf_fd);
    free(src_image.virt_addr);
    src_image.virt_addr = (unsigned char *)rknn_app_ctx.img_dma_buf.dma_buf_virt_addr;
    src_image.fd = rknn_app_ctx.img_dma_buf.dma_buf_fd;
    rknn_app_ctx.img_dma_buf.size = src_image.size;
#endif
    
    if (ret != 0)
    {
        printf("read image fail! ret=%d image_path=%s\n", ret, image_path);
        goto out;
    }

    object_detect_result_list od_results;

    ret = inference_yolo11_model(&rknn_app_ctx, &src_image, &od_results);
    if (ret != 0)
    {
        printf("init_yolo11_model fail! ret=%d\n", ret);
        goto out;
    }
//  以上的工作都是获取框的初始化工作,接下来才是使用框-----------------------------
    // 画框和概率
    char text[256];
    for (int i = 0; i < od_results.count; i++)   // 遍历所有检测结果
    {
        object_detect_result *det_result = &(od_results.results[i]);  // 获取单个结果
        printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
               det_result->box.left, det_result->box.top,
               det_result->box.right, det_result->box.bottom,
               det_result->prop);
        int x1 = det_result->box.left;  // 左
        int y1 = det_result->box.top;   // 上
        int x2 = det_result->box.right; // 右
        int y2 = det_result->box.bottom;  // 下
        // 确定一个点知道长和宽,所以这里是x1,y1为左上角坐标,x2-x1为宽,y2-y1为高
        draw_rectangle(&src_image, x1, y1, x2 - x1, y2 - y1, COLOR_BLUE, 3);  // 绘制蓝色矩形框
        // 绘制文本标签,显示类别名称和置信度百分比
        sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
        draw_text(&src_image, text, x1, y1 - 20, COLOR_RED, 10);  // 绘制红色文本标签
    }

    write_image("out.png", &src_image);    // 将结果图片保存为out.png

out:
    deinit_post_process();  // 释放后处理资源

    ret = release_yolo11_model(&rknn_app_ctx);  // 释放模型资源
    if (ret != 0)
    {
        printf("release_yolo11_model fail! ret=%d\n", ret);
    }

    if (src_image.virt_addr != NULL)
    {
#if defined(RV1106_1103) 
        dma_buf_free(rknn_app_ctx.img_dma_buf.size, &rknn_app_ctx.img_dma_buf.dma_buf_fd, 
                rknn_app_ctx.img_dma_buf.dma_buf_virt_addr);
#else
        free(src_image.virt_addr);
#endif
    }

    return 0;
}

  1. 算法改进的两种位置及其影响

在这里插入图片描述
后续会通过实验进一步去证明的。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐