Upload first version
This commit is contained in:
parent
f95d5a63b0
commit
3bdf2003ec
898 changed files with 1405811 additions and 1 deletions
0
examples/yolov11/README.md
Normal file
0
examples/yolov11/README.md
Normal file
0
examples/yolov11/cpp/.gitkeep
Normal file
0
examples/yolov11/cpp/.gitkeep
Normal file
77
examples/yolov11/cpp/build-android.sh
Executable file
77
examples/yolov11/cpp/build-android.sh
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
#
|
||||
# Copyright (C) 2024–2025 Amlogic, Inc. 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.
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [-a <target_abi>]"
|
||||
echo " -a <target_abi> : Target ABI (default: arm64-v8a)"
|
||||
echo " -h : Show this help message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Default values
|
||||
TARGET_ABI=arm64-v8a
|
||||
|
||||
# Parse arguments
|
||||
while getopts 'a:h' opt; do
|
||||
case "$opt" in
|
||||
a)
|
||||
TARGET_ABI=$OPTARG
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${ANDROID_NDK_PATH}" ]; then
|
||||
if [ -n "${ANDROID_NDK}" ]; then
|
||||
ANDROID_NDK_PATH=${ANDROID_NDK}
|
||||
elif [ -n "${ANDROID_NDK_HOME}" ]; then
|
||||
ANDROID_NDK_PATH=${ANDROID_NDK_HOME}
|
||||
else
|
||||
echo "Error: ANDROID_NDK_PATH is not set."
|
||||
echo "Please set ANDROID_NDK_PATH to your Android NDK directory."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
ROOT_PWD=$(cd "$(dirname $0)" && pwd)
|
||||
BUILD_DIR=${ROOT_PWD}/build/android
|
||||
|
||||
echo "Building for Android..."
|
||||
echo "NDK_PATH: ${ANDROID_NDK_PATH}"
|
||||
echo "TARGET_ABI: ${TARGET_ABI}"
|
||||
echo "BUILD_DIR: ${BUILD_DIR}"
|
||||
|
||||
mkdir -p ${BUILD_DIR}
|
||||
cd ${BUILD_DIR}
|
||||
|
||||
cmake ../../src \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=${TARGET_ABI} \
|
||||
-DANDROID_PLATFORM=android-24 \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DOpenCV_DIR=${ROOT_PWD}/../../../dependency/opencv/opencv-android-sdk-build/sdk/native/jni/abi-${TARGET_ABI}
|
||||
|
||||
make -j4
|
||||
|
||||
echo "Build complete. Executable in ${BUILD_DIR}/yolo11_demo"
|
||||
65
examples/yolov11/cpp/build-linux.sh
Executable file
65
examples/yolov11/cpp/build-linux.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#TODO
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [-a <target_arch>]"
|
||||
echo " -a <target_arch> : Target architecture (default: aarch64)"
|
||||
echo " -h : Show this help message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Default values
|
||||
TARGET_ARCH=aarch64
|
||||
|
||||
# Parse arguments
|
||||
while getopts 'a:h' opt; do
|
||||
case "$opt" in
|
||||
a)
|
||||
TARGET_ARCH=$OPTARG
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Default to aarch64-linux-gnu if GCC_COMPILER is not set
|
||||
GCC_COMPILER=${GCC_COMPILER:-aarch64-linux-gnu}
|
||||
|
||||
# Set compilers
|
||||
export CC=${GCC_COMPILER}-gcc
|
||||
export CXX=${GCC_COMPILER}-g++
|
||||
|
||||
# Validate compiler
|
||||
if ! command -v ${CC} &> /dev/null; then
|
||||
echo "Error: Compiler ${CC} not found."
|
||||
echo "Please set GCC_COMPILER environment variable to your cross-compiler path prefix."
|
||||
echo "Example: export GCC_COMPILER=/path/to/toolchain/bin/aarch64-linux-gnu"
|
||||
# Proceeding anyway as user might have custom env setup
|
||||
else
|
||||
echo "Using compiler: ${CC}"
|
||||
fi
|
||||
|
||||
ROOT_PWD=$(cd "$(dirname $0)" && pwd)
|
||||
BUILD_DIR=${ROOT_PWD}/build/linux
|
||||
|
||||
echo "Building for Linux..."
|
||||
echo "COMPILER: ${CC}"
|
||||
echo "TARGET_ARCH: ${TARGET_ARCH}"
|
||||
echo "BUILD_DIR: ${BUILD_DIR}"
|
||||
|
||||
mkdir -p ${BUILD_DIR}
|
||||
cd ${BUILD_DIR}
|
||||
|
||||
cmake ../../src \
|
||||
-DCMAKE_SYSTEM_NAME=Linux \
|
||||
-DCMAKE_SYSTEM_PROCESSOR=${TARGET_ARCH} \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DOpenCV_DIR=${ROOT_PWD}/../../../dependency/opencv/opencv-linux-aarch64/share/OpenCV
|
||||
make -j4
|
||||
|
||||
echo "Build complete. Executable in ${BUILD_DIR}/yolo11_demo"
|
||||
41
examples/yolov11/cpp/src/CMakeLists.txt
Executable file
41
examples/yolov11/cpp/src/CMakeLists.txt
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(yolo11_demo)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Set NNSDK path
|
||||
set(NNSDK_ROOT "${CMAKE_SOURCE_DIR}/../../../../dependency/nnsdk")
|
||||
include_directories(${NNSDK_ROOT}/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/../../../../common)
|
||||
|
||||
# Set dependency path
|
||||
set(3RDPARTY_DIR "${CMAKE_SOURCE_DIR}/../../../../dependency")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
if (ANDROID_ABI STREQUAL "arm64-v8a")
|
||||
link_directories(${NNSDK_ROOT}/lib/android/arm64-v8a)
|
||||
else()
|
||||
link_directories(${NNSDK_ROOT}/lib/android/armeabi-v7a)
|
||||
endif()
|
||||
# Android needs log
|
||||
link_libraries(log)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
link_directories(${NNSDK_ROOT}/lib/linux/lib64_yocto)
|
||||
endif()
|
||||
|
||||
# Find OpenCV
|
||||
message(STATUS "OpenCV_DIR: ${OpenCV_DIR}")
|
||||
find_package(OpenCV REQUIRED)
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
|
||||
|
||||
add_executable(yolo11_demo
|
||||
main.cpp
|
||||
postprocess.cpp
|
||||
${CMAKE_SOURCE_DIR}/../../../../common/model_loader.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(yolo11_demo
|
||||
${OpenCV_LIBS}
|
||||
nnsdk
|
||||
)
|
||||
111
examples/yolov11/cpp/src/main.cpp
Executable file
111
examples/yolov11/cpp/src/main.cpp
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <float.h>
|
||||
#include "nn_sdk.h"
|
||||
#include "postprocess.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static void hwc_to_chw(const cv::Mat& src, float* dst) {
|
||||
int h = src.rows, w = src.cols;
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int i = 0; i < h; ++i) {
|
||||
for (int j = 0; j < w; ++j) {
|
||||
dst[k * h * w + i * w + j] = src.at<cv::Vec3f>(i, j)[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) { std::cout << "Usage: " << argv[0] << " <model.adla> <image_dir>\n"; return 0; }
|
||||
|
||||
aml_config cfg{};
|
||||
cfg.typeSize = sizeof(cfg); cfg.modelType = ADLA_LOADABLE; cfg.nbgType = NN_ADLA_FILE; cfg.path = argv[1];
|
||||
void* ctx = aml_module_create(&cfg);
|
||||
if (!ctx) return -1;
|
||||
|
||||
std::vector<float> chw_buffer(kInputW * kInputH * 3);
|
||||
fs::create_directory("yolo11_result");
|
||||
|
||||
for (auto& it : fs::directory_iterator(argv[2])) {
|
||||
cv::Mat img = cv::imread(it.path().string());
|
||||
if (img.empty()) continue;
|
||||
|
||||
std::cout << "============================================================" << std::endl;
|
||||
std::cout << "Processing image: \"" << it.path().filename().string() << "\"" << std::endl;
|
||||
std::cout << "============================================================" << std::endl;
|
||||
|
||||
float scale = std::min((float)kInputW / img.cols, (float)kInputH / img.rows);
|
||||
int nw = img.cols * scale, nh = img.rows * scale;
|
||||
int px = (kInputW - nw) / 2, py = (kInputH - nh) / 2;
|
||||
cv::Mat res, canvas = cv::Mat::zeros(kInputH, kInputW, CV_32FC3);
|
||||
canvas.setTo(cv::Scalar(114.0/255.0, 114.0/255.0, 114.0/255.0));
|
||||
cv::resize(img, res, {nw, nh});
|
||||
res.convertTo(res, CV_32FC3, 1.0 / 255.0);
|
||||
res.copyTo(canvas(cv::Rect(px, py, nw, nh)));
|
||||
hwc_to_chw(canvas, chw_buffer.data());
|
||||
|
||||
nn_input in{}; in.typeSize = sizeof(in); in.input_type = BINARY_RAW_DATA;
|
||||
in.input = (unsigned char*)chw_buffer.data(); in.size = chw_buffer.size() * 4;
|
||||
in.info.valid = 1; in.info.input_format = AML_INPUT_MODEL_NCHW; in.info.input_data_type = AML_INPUT_FP32;
|
||||
aml_module_input_set(ctx, &in);
|
||||
|
||||
aml_output_config_t outcfg{}; outcfg.typeSize = sizeof(outcfg); outcfg.format = AML_OUTDATA_FLOAT32;
|
||||
nn_output* out = (nn_output*)aml_module_output_get(ctx, outcfg);
|
||||
if (!out) continue;
|
||||
|
||||
std::vector<cv::Rect> bboxes;
|
||||
std::vector<float> confs;
|
||||
std::vector<int> class_ids;
|
||||
std::vector<int> strides = {32, 16, 8};
|
||||
|
||||
for (int i = 0; i < out->num; i++) {
|
||||
float* data = (float*)out->out[i].buf;
|
||||
int stride = strides[i], grid_h = kInputH / stride, grid_w = kInputW / stride;
|
||||
for (int g = 0; g < grid_h * grid_w; g++) {
|
||||
float* feat = data + g * kTotalChannels;
|
||||
float max_score = -1.0f; int cls_id = -1;
|
||||
for (int c = 0; c < kNumClasses; c++) {
|
||||
float score = 1.0f / (1.0f + std::exp(-feat[64 + c]));
|
||||
if (score > max_score) { max_score = score; cls_id = c; }
|
||||
}
|
||||
if (max_score > 0.3f) {
|
||||
float d_l = decode_dfl(feat + 0), d_t = decode_dfl(feat + 16);
|
||||
float d_r = decode_dfl(feat + 32), d_b = decode_dfl(feat + 48);
|
||||
float cx = (g % grid_w) + 0.5f, cy = (g / grid_w) + 0.5f;
|
||||
int rx1 = std::max(0, (int)(((cx - d_l) * stride - px) / scale));
|
||||
int ry1 = std::max(0, (int)(((cy - d_t) * stride - py) / scale));
|
||||
int rx2 = std::min(img.cols, (int)(((cx + d_r) * stride - px) / scale));
|
||||
int ry2 = std::min(img.rows, (int)(((cy + d_b) * stride - py) / scale));
|
||||
bboxes.push_back(cv::Rect(rx1, ry1, rx2 - rx1, ry2 - ry1));
|
||||
confs.push_back(max_score); class_ids.push_back(cls_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> indices = manual_nms(bboxes, confs, 0.45f);
|
||||
if (!indices.empty()) {
|
||||
std::cout << "Detected " << indices.size() << " objects:" << std::endl;
|
||||
for (size_t i = 0; i < indices.size(); i++) {
|
||||
int idx = indices[i];
|
||||
printf(" %zu. %s (%.2f)\n", i + 1, kClassNames[class_ids[idx]].c_str(), confs[idx]);
|
||||
|
||||
cv::rectangle(img, bboxes[idx], {0, 255, 0}, 2);
|
||||
char text[256]; std::sprintf(text, "%s %.2f", kClassNames[class_ids[idx]].c_str(), confs[idx]);
|
||||
cv::putText(img, text, {bboxes[idx].x, bboxes[idx].y - 5}, cv::FONT_HERSHEY_SIMPLEX, 0.5, {0, 255, 0}, 1);
|
||||
}
|
||||
} else {
|
||||
std::cout << "No objects detected." << std::endl;
|
||||
}
|
||||
|
||||
std::string out_path = "yolo11_result/" + it.path().filename().string();
|
||||
cv::imwrite(out_path, img);
|
||||
std::cout << "Result saved to: " << out_path << std::endl;
|
||||
std::cout << "============================================================" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
aml_module_destroy(ctx); return 0;
|
||||
}
|
||||
66
examples/yolov11/cpp/src/postprocess.cpp
Executable file
66
examples/yolov11/cpp/src/postprocess.cpp
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
#include "postprocess.h"
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <float.h>
|
||||
|
||||
const std::vector<std::string> kClassNames = {
|
||||
"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"
|
||||
};
|
||||
|
||||
float decode_dfl(const float* dfl_ptr) {
|
||||
float max_val = -FLT_MAX;
|
||||
for (int i = 0; i < kDflChannels; i++) {
|
||||
if (dfl_ptr[i] > max_val) max_val = dfl_ptr[i];
|
||||
}
|
||||
float exp_sum = 0;
|
||||
float exp_vals[kDflChannels];
|
||||
for (int i = 0; i < kDflChannels; i++) {
|
||||
exp_vals[i] = std::exp(dfl_ptr[i] - max_val);
|
||||
exp_sum += exp_vals[i];
|
||||
}
|
||||
float res = 0;
|
||||
for (int i = 0; i < kDflChannels; i++) {
|
||||
res += (exp_vals[i] / exp_sum) * i;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
float calculate_iou(const cv::Rect& a, const cv::Rect& b) {
|
||||
int xx1 = std::max(a.x, b.x);
|
||||
int yy1 = std::max(a.y, b.y);
|
||||
int xx2 = std::min(a.x + a.width, b.x + b.width);
|
||||
int yy2 = std::min(a.y + a.height, b.y + b.height);
|
||||
int w = std::max(0, xx2 - xx1);
|
||||
int h = std::max(0, yy2 - yy1);
|
||||
float inter = (float)w * h;
|
||||
float areaA = (float)a.width * a.height;
|
||||
float areaB = (float)b.width * b.height;
|
||||
return inter / (areaA + areaB - inter);
|
||||
}
|
||||
|
||||
std::vector<int> manual_nms(const std::vector<cv::Rect>& boxes, const std::vector<float>& scores, float thresh) {
|
||||
std::vector<int> order(boxes.size());
|
||||
std::iota(order.begin(), order.end(), 0);
|
||||
std::stable_sort(order.begin(), order.end(), [&](int a, int b) {
|
||||
return scores[a] > scores[b];
|
||||
});
|
||||
std::vector<int> keep;
|
||||
while (!order.empty()) {
|
||||
int i = order[0];
|
||||
keep.push_back(i);
|
||||
order.erase(order.begin());
|
||||
order.erase(std::remove_if(order.begin(), order.end(), [&](int j) {
|
||||
return calculate_iou(boxes[i], boxes[j]) > thresh;
|
||||
}), order.end());
|
||||
}
|
||||
return keep;
|
||||
}
|
||||
26
examples/yolov11/cpp/src/postprocess.h
Executable file
26
examples/yolov11/cpp/src/postprocess.h
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef YOLO11_POSTPROCESS_H
|
||||
#define YOLO11_POSTPROCESS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
static constexpr int kInputW = 640;
|
||||
static constexpr int kInputH = 640;
|
||||
static constexpr int kNumClasses = 80;
|
||||
static constexpr int kDflChannels = 16;
|
||||
static constexpr int kTotalChannels = 144;
|
||||
|
||||
extern const std::vector<std::string> kClassNames;
|
||||
|
||||
struct Detection {
|
||||
cv::Rect box;
|
||||
float confidence;
|
||||
int class_id;
|
||||
};
|
||||
|
||||
float decode_dfl(const float* dfl_ptr);
|
||||
float calculate_iou(const cv::Rect& a, const cv::Rect& b);
|
||||
std::vector<int> manual_nms(const std::vector<cv::Rect>& boxes, const std::vector<float>& scores, float thresh);
|
||||
|
||||
#endif
|
||||
0
examples/yolov11/model/.gitkeep
Normal file
0
examples/yolov11/model/.gitkeep
Normal file
0
examples/yolov11/py/.gitkeep
Normal file
0
examples/yolov11/py/.gitkeep
Normal file
Loading…
Add table
Add a link
Reference in a new issue