## 环境准备
- 下载
- [rk linux 升级工具](https://files.luckfox.com/wiki/Core3566/upgrade_tool_v2.17.zip)
- [升级工具网盘](https://pan.baidu.com/s/1Mhf5JMpkFuZo_TuaGSxBYg?pwd=2sf8)
- linux下烧录
- `sudo ./upgrade_tool uf uckfox_pico_pro_max_image/update.img`
- 烧录完后发现系统uname -a是一样的……其实不用更新,出厂就是最新了
- SDK
- [luckfox-pico SDK](https://gitee.com/LuckfoxTECH/luckfox-pico/tree/main)
- gdbserver
- 一开始自己编译了一个 gdbserver ,结果运行不起来,然后在SDK里面一顿搜索,发现如下内容
```shell
# Enable build gdb and gdbserver debug tool
CONFIG_SYSDRV_ENABLE_GDB=y
$(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_GDB))
```
- 直接在终端运行 gdbserver ,发现果然自带了! 再一看,发现甚至自带了python3.11 !
## RKNN调用
### 寻找可用的识别例程序
- RKNN调用方式自然要从官方教程借鉴过来
> cv工程师当然要多用cv,程序员的事怎么能叫抄呢?
- 在 rknn-toolkit2 仓库有许多教程,但像yolo这种是面向识别和分割的,不太合适。其中 mobilenet 的demo同为分类任务:rknpu2/examples/rknn_mobilenet_demo/src/main.cc
- 修改 CMakeLists.txt 的 CMAKE_C_COMPILER 为你的GCC路径
- 直接使用该工程编译出来的程序其实可以直接运行,但必须把生成的lib库也一同拷下去,不然就要手动替换oem库,否则会报错,详见下方
```shell
mkdir build
cd build
cmake ..
make -j6
make install
cd ../rknn_mobilenet_demo
sshpass -p "luckfox" scp -r * root@10.37.49.129:/root
```
- 运行 ./rknn_mobilenet_demo model8.rknn pic/4.jpg
- 其中 4.jpg 是从上面转化 dataset 时从mnist数据集拷出来的测试集文件
## 分析例程、修改与封装
- RKNN初始化:`ret = rknn_init(&ctx, model_path, 0, 0, NULL);`
- 获取RKNN模型信息:`rknn_query`
1. RKNN_QUERY_SDK_VERSION
2. RKNN_QUERY_IN_OUT_NUM
3. RKNN_QUERY_INPUT_ATTR
4. RKNN_QUERY_NATIVE_OUTPUT_ATTR
- 其中后面两个是对输出输出数据体初始化,必须封装在推理函数中,上面两个只需要初始化一次即可。
- 将摄像头的数据转化为cv::Mat类型,再传入识别,进行函数封装:
- 获取摄像头数据流:`void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);`
- 转化为cv::Mat:`cv::Mat frame(height, width, CV_8UC3, data);`
- 自行封装RKNN推理函数:`int TiRknnForward(const cv::Mat frame, rknn_input_output_num io_num, std::vector
> &oresult)`
- 推理
- rknn_query RKNN_QUERY_INPUT_ATTR 初始化 input_attrs
- rknn_query RKNN_QUERY_NATIVE_OUTPUT_ATTR 初始化 output_attrs
- rknn_create_mem 开辟缓存
- rknn_set_io_mem 设置输入、输出缓存->NPU
- rknn_run 推理
- rknn_query RKNN_QUERY_OUTPUT_ATTR 获取结果
- 处理输出结果
- 解码结果数据 `rknn_GetTopN`
- 将结果保存到vector结构体里,返回:`oresult.push_back(std::make_pair(MaxClass[j], fMaxProb[j]));`
- rknn_destroy_mem 注销缓存
- 我移植后运行的效果,相关代码使用仓库readpic分支(或者回退到最初分支也可以):
-
## 性能优化
- 直接识别从mnist里面取出来的数据,效果还是可以的,说明模型和RKNN部分调用本身没有问题。但是使用摄像头直接传输数据的时候,基本无法识别。猜测可能是由于周边环境与训练时有差异。
- 训练的数据是中心白,周围全黑,于是我通过获取 advanced morphological transformations 找最大的白块轮廓,把其他区域置为全黑。具体操作如下:
1. 将图片转为灰度图
2. 设定阈值,将190以内的区域全黑。
3. 找到最大轮廓
4. 过滤满足条件的轮廓
5. 轮廓以外区域全黑
- 找到轮廓和全黑图后返回,把合适的区域切割出来,添加1.5倍黑边,然后进行RKNN推理。
- 在PC上测试一下效果:
-
- 转换后:
-
## 显示支持
### RTSP支持
- 参考 [luckfox_pico_rtsp_opencv](https://github.com/luckfox-eng29/luckfox_pico_rtsp_opencv.git) 工程,使用 rkmpi rtsp vi 等库实现,代码低耦合,无需赘述
### LCD支持
- 使用SPI进行用户态驱动 ili9341 屏幕
- ![引脚分布](https://wiki.luckfox.com/zh/assets/images/LUCKFOX-PICO-PROMAX-GPIO-6dbf2d0d09106289a1d07098e39504c2.jpg)
- LCD
- SPI连接 12~16
- RST连接 5 GPIO1_C6
- DC连接 4 GPIO1_C7
- LED使能找个3.3V上拉
- 程序仓库:见下,`读图测试`自带LCD现实,`RTSP流测试`如需LCD现实,需要回退一个提交
- 效果
## 程序仓库
- 读图测试(注意切换readpic分支):https://gitlink.org.cn/tinnu/mpu_rv1106_rknn/tree/readpic
- RTSP流测试(主分支):https://gitlink.org.cn/tinnu/mpu_rv1106_rknn
- 效果:[视频演示](https://v.youku.com/v_show/id_XNjM5MzcxNTM2NA==.html "视频演示")
rv1106神经网络测试_mnist+RKNN+RTSP+LCD.mp4
(4.83 MB, 下载次数: 2)
rv1106神经网络测试_mnist+RKNN+RTSP+LCD
## 问题处理: failed to decode config data!
- 板端运行报错。
- 这个问题是由于编译的库和板端库不兼容导致的
- 检查板端库大小
```shell
# ls /oem/usr/lib/librga.so -al
-rw-rw-r-- 1 1002 1002 154244 Nov 16 2023 /oem/usr/lib/librga.so
# ls /oem/usr/lib/librknnmrt.so -al
-rw-r--r-- 1 1002 1002 141048 Nov 16 2023 /oem/usr/lib/librknnmrt.so
```
- 检查编译使用库大小
- 两个位置都有这个库,看情况用的应该是 3rdparty 下面那个
./3rdparty/rknpu2/Linux/armhf-uclibc/librknnmrt.so
./tinnu-rv1106-rknn/lib/librknnmrt.so
- ls -al
```shell
-rwxr-xr-x 1 tinnu tinnu 166732 5月 26 19:18 librga.so
-rwxr-xr-x 1 tinnu tinnu 190368 5月 26 19:18 librknnmrt.so
```
- 把编译的这个库拷贝到板端 /oem/usr/lib/ 下替换掉原本库