imx6ull移植opencv+yolo+nccn
环境准备
windows电脑,ubtuntu虚拟机,imx6ull开发板,虚拟机安装cmake,yum install cmake
版本信息

opencv编译
由于yolo一般习惯依赖opencv,所以先安装opencv,注意,因为虚拟机的cmake版本是3.10的,所以推荐opencv选择4.2版本,请自行下载
下载后复制到虚拟机root目录,注意不要使用虚拟机共享文件夹
执行命令
mkdir build-arm & cd build-arm
cmake \-DCMAKE_SYSTEM_NAME=Linux \-DCMAKE_SYSTEM_PROCESSOR=arm \-DCMAKE_C_COMPILER=arm-buildroot-linux-gnueabihf-gcc \-DCMAKE_CXX_COMPILER=arm-buildroot-linux-gnueabihf-g++ \-DCMAKE_INSTALL_PREFIX=/opt/opencv-arm \-DBUILD_LIST=core,highgui,imgcodecs,imgproc \-DWITH_GTK=OFF \-DWITH_JPEG=ON \-DWITH_PNG=ON \-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \..
make -j1
sudo make install
安装成功后,目录/opt/opencv-arm/就出现了
yolo资源下载
# 预训练权重 下载
https://pjreddie.com/media/files/yolov3-tiny.weight
或者 wget https://pjreddie.com/media/files/yolov3-tiny.weights
cfg下载
https://gitee.com/mirrors/darknet/raw/master/cfg/yolov3-tiny.cfg
ncnn框架编译
Git clone https://gitee.com/Tencent/ncnn.git
Cd ncnn
Mkdir build-arm &&cd build-arm
新建toolchains.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(TOOLCHAIN_PREFIX arm-buildroot-linux-gnueabihf-)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
执行命令
cmake \
-DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
-DCMAKE_INSTALL PREFIX=/opt/ncnn-arm \
-DNCNN BUILD EXAMPLES=OFF \
-DNCNN BUILD TOOLS=ON \
-DNCNN BUILD_BENCHMARK=OFF \
..
make -j1
sudo make install
成功后。在/opt/下就有了ncnn-arm/文件夹
将darknet转为ncnn
在上一步ncnn编译完成后,编译目录下tools/darknet下有一个现成的工具darknet2ncnn,极大的方便了我们,一步到位,不需要python,不需要ONNX

将darknet2ncnn拷贝到开发板,当然,也可以直接挂载放到虚拟机的nfs目录,韦东山老师一般是/home/book/nfs_rootfs/,在开发板的/mnt/直接可以访问
在开发板执行命令
./darknet2ncnn yolov3-tiny.cfg yolov3-tiny.weights yolov3-tiny.param yolov3-tiny.bin
成功得到param和bin文件
demo文件编写与编译
yolo_ncnn.cpp
#include <ncnn/net.h>
#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
// ==================== 请根据自己模型修改以下参数 ====================
const int INPUT_W = 416; // 模型输入宽度(和cfg一致)
const int INPUT_H = 416; // 模型输入高度(和cfg一致)
const float CONF_THRESH = 0.25f; // 置信度阈值
const float NMS_THRESH = 0.45f; // NMS阈值
// 类别名称,按训练数据集填写
const std::vector<std::string> CLASS_NAMES = {
"class1", "class2", "class3"
};
// 模型文件路径
const std::string PARAM_PATH = "yolo.param";
const std::string BIN_PATH = "yolo.bin";
// ===================================================================
struct Object
{
cv::Rect rect;
int class_id;
float score;
};
static void nms(std::vector<Object>& objects)
{
std::sort(objects.begin(), objects.end(), [](const Object& a, const Object& b) {
return a.score > b.score;
});
std::vector<float> area(objects.size());
for (int i = 0; i < objects.size(); i++)
{
area[i] = (float)objects[i].rect.area();
}
std::vector<bool> remove_flag(objects.size(), false);
for (int i = 0; i < objects.size(); i++)
{
if (remove_flag[i]) continue;
for (int j = i + 1; j < objects.size(); j++)
{
if (remove_flag[j]) continue;
cv::Rect intersect = objects[i].rect & objects[j].rect;
float inter_area = (float)intersect.area();
float iou = inter_area / (area[i] + area[j] - inter_area);
if (iou > NMS_THRESH)
remove_flag[j] = true;
}
}
std::vector<Object> res;
for (int i = 0; i < objects.size(); i++)
{
if (!remove_flag[i])
res.push_back(objects[i]);
}
objects.swap(res);
}
int main(int argc, char** argv)
{
// 1. 初始化ncnn网络
ncnn::Net net;
// 开启多线程、优化(ARM平台自动启用NEON)
net.opt.num_threads = 1;
// net.opt.use_winograd = true;
// 加载模型
int ret = net.load_param(PARAM_PATH.c_str());
ret |= net.load_model(BIN_PATH.c_str());
if (ret != 0)
{
fprintf(stderr, "加载模型失败!\n");
return -1;
}
// 2. 读取测试图片
cv::Mat img = cv::imread("test.jpg");
if (img.empty())
{
fprintf(stderr, "读取图片失败!\n");
return -1;
}
int img_w = img.cols;
int img_h = img.rows;
// 3. 图像预处理 BGR -> RGB + resize + 归一化
ncnn::Mat in = ncnn::Mat::from_pixels_resize(
img.data, ncnn::Mat::PIXEL_BGR2RGB,
img_w, img_h, INPUT_W, INPUT_H
);
// Darknet 常用归一化: /255.0
const float mean_vals[3] = {0.f, 0.f, 0.f};
const float norm_vals[3] = {1/255.f, 1/255.f, 1/255.f};
in.substract_mean_normalize(mean_vals, norm_vals);
// 4. 推理
ncnn::Extractor ex = net.create_extractor();
ex.input("data", in); // 输入节点名,默认darknet转出来是 data
ncnn::Mat out;
ex.extract("output", out); // 输出节点名,大部分yolo为 output
// 5. 解析输出 (ncnn yolo输出格式: 每行 [cx,cy,w,h,score0,score1,...])
std::vector<Object> objects;
int rows = out.h;
int cols = out.w;
for (int y = 0; y < rows; y++)
{
const float* row = out.row(y);
float cx = row[0] * img_w;
float cy = row[1] * img_h;
float w = row[2] * img_w;
float h = row[3] * img_h;
float max_score = 0.f;
int max_cls = 0;
for (int c = 4; c < cols; c++)
{
if (row[c] > max_score)
{
max_score = row[c];
max_cls = c - 4;
}
}
if (max_score < CONF_THRESH)
continue;
Object obj;
obj.class_id = max_cls;
obj.score = max_score;
obj.rect.x = cv::saturate_cast<int>(cx - w/2);
obj.rect.y = cv::saturate_cast<int>(cy - h/2);
obj.rect.width = cv::saturate_cast<int>(w);
obj.rect.height = cv::saturate_cast<int>(h);
objects.push_back(obj);
}
// 6. NMS 非极大值抑制
nms(objects);
// 7. 绘图显示
for (auto& obj : objects)
{
cv::rectangle(img, obj.rect, cv::Scalar(0, 0, 255), 2);
std::string text = CLASS_NAMES[obj.class_id] + " " + std::to_string(obj.score).substr(0, 4);
cv::putText(img, text, cv::Point(obj.rect.x, obj.rect.y-5),
cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 255, 0), 2);
}
// cv::imshow("yolo-ncnn", img);
// cv::waitKey(0);
cv::imwrite("result.jpg", img);
return 0;
}
CMakeLists.txt
# ========== 交叉编译工具链 (根据你的工具链修改) ==========
set(CMAKE_C_COMPILER arm-buildroot-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-buildroot-linux-gnueabihf-g++)
cmake_minimum_required(VERSION 3.10)
project(yolo_ncnn)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# ========== 交叉编译版 ncnn / OpenCV 路径(你交叉编译出来的库) ==========
set(NCNN_ROOT /opt/ncnn-arm)
set(OPENCV_ROOT /opt/opencv-arm)
include_directories(
${NCNN_ROOT}/include
${OPENCV_ROOT}/include/opencv4
)
link_directories(
${NCNN_ROOT}/lib
${OPENCV_ROOT}/lib
)
# 编译目标
add_executable(demo yolo_ncnn.cpp)
target_link_libraries(demo
ncnn
opencv_core
opencv_imgproc
opencv_highgui
opencv_imgcodecs
pthread
gomp
)
将这两个文件放到虚拟机上,执行
mkdir build-arm &&cd build-arm
cmake ..
make -j1
执行成功,至此所有编译工作已完成
开始移植测试
现在所有东西都齐全了,开始移植测试
确保test.jpg,demo文件,param,bin文件都在/home/book/root_fs。可以直接在开发板通过/mnt/访问
将虚拟机的/opt/opencv-arm复制到开发板的/opt/下
开发板执行
cd /mnt/
export LD_LIBRARY_PATH=/opt/opencv-arm/lib:$LD_LIBRARY_PATH
./demo
执行后,成功生成了result.jpg,虽然不太准确,但是先这样吧,嘿嘿。

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