qiao---

  • 2024-06-15
  • 回复了主题帖: 【正点原子i.MX93开发板】1-开箱与开机测评

    chejm 发表于 2024-6-11 11:41 首先祝贺楼主获得的测评机会,希望楼主能分享自己的测试心得 好的,后面会注重心得和技术分享。

  • 2024-06-09
  • 发表了主题帖: 【正点原子i.MX93开发板】1-开箱与开机测评

    本帖最后由 qiao--- 于 2024-6-9 20:35 编辑 前言:         感谢eeworld与正点原子给我这个机会测评i.MX93开发板。i.MX93开发板采用NXP i.MX9352处理器,i.MX935属于中高端嵌入式Linux开发处理器,双核CortexA55@1.7GHz+M33@250MHz+0.5TNPU,支持Linux多任务、RTOS实时控制、轻量级AI应用场景。现在很多多核的芯片都可以异核通信,现在刚好借这个机会来学习一下多核通信。接下来有请我们的主角登场。   1.开箱测评 正点原子的包装依旧采用黑盒子包装,很有高级感,在保证美感的同时保护内部的开发板。   黑盒子主要两层,下面一层装着我们的开发板,上面一层装着板子的相关配件。   板子的相关配件主要以下,俩根数据传输线,一个信号接收天线,一个板子的供电器还有两根细长的杜邦线。如下所示:   作为正点原子的老粉,看到这些东西其实都知道,这些都是正点原子的基本操作。下面来给板子来个特写: 正面:   反面:   接下来来介绍一下板子的相关的资源,这款开发板在具备性能的同时接口也非常丰富,所以想学习Linux驱动开发和应用开发的小伙伴这块板子也是个不错的选择。具体板子的接口介绍如下图:   同时板子的资料也非常丰富,从开发软件,到板子硬件,再到教程文档和资料源码全部都有,可以说就我用过的开发板,正点原子的资料是做的最完整的。资料目录如下所示,光我下载这些资料都花费了好几个小时。           2.开机测评 正点原子的Linux开发板出厂都烧写了出厂系统,一般是他们自己适配的QT程序,但是我这里没有mipi接口的显示屏,就给大家演示不了了。只能能通过命令行的方式给大家演示系统。 用正点原子的电源连接开发板的右上角,同时用数据线连接USB_TTL口,如下所示:   用串口工具查看会有两个串口,其中较小的那个就可以登录到我们的系统终端。   系统的启动界面如下所示。   查看我们的Linux版本为6.1.55版本。   开机测评就只能给大家展示这么多了,接下来就是我们漫长的学习和开发过程。  

  • 2024-06-04
  • 回复了主题帖: 【Luckfox幸狐 RV1106 Linux 开发板】7-基于ffmpeg的视频播放测试

    八月长安ii 发表于 2024-6-4 10:47 编译完FFmpeg出现了一个warning, 然后后面make就失败了, 请问这是什么原因呢? WARNING: /root/pico_sdk/ ... 没有配置sdk,把编译环境配置好

  • 回复了主题帖: 测评入围名单: 正点原子i.MX93开发板

    个人信息无误,确认可以完成测评分享计划

  • 2024-05-26
  • 回复了主题帖: 有没有大佬能帮忙内推实习

    吾妻思萌 发表于 2024-5-23 11:39 别去boss,建议去对应官网找邮箱,自投。可以写写东西,show你的优势。建议应届生去考公务员,选调生,事业 ... 中肯的建议

  • 2024-05-25
  • 发表了主题帖: #AI挑战营终点站#数字识别模型部署

    本帖最后由 qiao--- 于 2024-5-25 14:50 编辑 前言: 经过前面两位贴友铺路,我的模型也是成功的部署。与前面两位贴友不同的是,我是将显示结果显示到屏幕上,所以多了一步驱动适配的过程。 因为我前面已经发布了st7735屏幕的适配过程,我这里就不在赘述了。有兴趣的贴友可以去看看我的这一篇帖子:【Luckfox幸狐 RV1106 Linux 开发板】4-SPI测试__驱动RGB_TFT正常显示 https://bbs.eeworld.com.cn/thread-1271812-1-1.html 然后模型的训练可以去看我之前的两个帖子: 模型训练:#AI挑战营第一站#MNIST手写数字识别模型训练 https://bbs.eeworld.com.cn/thread-1277782-1-1.html 模型转换:#AI挑战营第二站#Ubuntu22上将ONNX模型转换成RKNN模型 https://bbs.eeworld.com.cn/thread-1280156-1-1.html 如果有贴友对烧录过程和使用过程不熟悉的也可去看我之前的测评,这里我来个汇总: 【Luckfox幸狐 RV1106 Linux 开发板】1-开箱及上电测评 【Luckfox幸狐 RV1106 Linux 开发板】2-搭建开发环境和镜像烧录 【Luckfox幸狐 RV1106 Linux 开发板】3-PWM测试__控制舵机任意旋转 【Luckfox幸狐 RV1106 Linux 开发板】4-SPI测试__驱动RGB_TFT正常显示 【Luckfox幸狐 RV1106 Linux 开发板】5-给系统移植QT环境__显示电子时钟界面 【Luckfox幸狐 RV1106 Linux 开发板】6-ADC测试 【Luckfox幸狐 RV1106 Linux 开发板】7-基于ffmpeg的视频播放测试 【Luckfox幸狐 RV1106 Linux 开发板】8-opencv人脸识别测评 本次工程的代码我上传到了我的仓库,有需要可自取:tang/RV1106模型部署_yolo和mnist - 码云 - 开源中国 (gitee.com) 下面开始正题,如何将自己训练的手写模型部署到开发板上呢。 1.熟悉API 参考内容:RKNN 推理测试 | LUCKFOX WIKI 下面是模型部署的API使用流程图,我们可以参考这个来使用官方的API   2.实战操作 定义模型上下文 rknn_app_context_t rknn_app_ctx; memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t)); init_mnist_model(model_path, &rknn_app_ctx); 其中rknn_app_context_t结构体如下,存储rknn的上下文 typedef struct { rknn_context rknn_ctx; rknn_tensor_mem* max_mem; rknn_tensor_mem* net_mem; rknn_input_output_num io_num; rknn_tensor_attr* input_attrs; rknn_tensor_attr* output_attrs; rknn_tensor_mem* input_mems[3]; rknn_tensor_mem* output_mems[3]; int model_channel; int model_width; int model_height; bool is_quant; } rknn_app_context_t; 因为我们要把结果显示到屏幕上,所以我们还要初始化屏幕,代码如下 //Init fb int fb = open("/dev/fb0", O_RDWR); if(fb == -1) { close(fb); return -1; } size_t screensize = FB_WIDTH * FB_HEIGHT * 2; uint16_t* framebuffer = (uint16_t*)mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); 这里我们使用mmap函数将帧缓冲设备文件/dev/fb0映射到内存中的一段区域,这里我们就可以操作这块内存来进行显示了。 就下来我们要初始化摄像头,和帧数据,其中bgr565用于显示到我们屏幕上的帧数据。 //Init Opencv-mobile cv::VideoCapture cap; cv::Mat bgr(disp_height, disp_width, CV_8UC3); cv::Mat bgr565(disp_height, disp_width, CV_16UC1); cv::Mat bgr640(model_height, model_width, CV_8UC3, rknn_app_ctx.input_mems[0]->virt_addr); cap.set(cv::CAP_PROP_FRAME_WIDTH, disp_width); cap.set(cv::CAP_PROP_FRAME_HEIGHT, disp_height); cap.open(0); 下面为输入图像的操作,我们直接可以用>>进行输入图像,因为opencv-mobile库对这个操作符进行重载了。 start_time = clock(); cap >> bgr; cv::resize(bgr, bgr640, cv::Size(model_width, model_height), 0, 0, cv::INTER_LINEAR); 下面进行对输入的图片帧进行预处理,因为我们需要的灰度图像(训练模型是灰度),下面这部分参考的luyism兄弟的。这里代码写的一次只能对最大的轮廓的数字进行识别,因为返回了最大轮廓的区域。 // 在图像中找到数字的轮廓,同时减小找到轮廓时的抖动 cv::Rect find_digit_contour(const cv::Mat &image) { // 预处理图像 cv::Mat gray, blurred, edged; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0); cv::Canny(blurred, edged, 30, 150); // 应用形态学操作 cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)); cv::dilate(edged, edged, kernel); cv::erode(edged, edged, kernel); // 查找轮廓,声明一个变量来存储轮廓 std::vector<std::vector<cv::Point>> contours; cv::findContours(edged, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.empty()) { return cv::Rect(); } // 找到最大的轮廓 auto largest_contour = std::max_element(contours.begin(), contours.end(), [](const std::vector<cv::Point>& a, const std::vector<cv::Point>& b) { return cv::contourArea(a) < cv::contourArea(b); }); // **轮廓面积过滤**:在找到轮廓之后,可以排除那些面积过小的轮廓。这样可以减少不必要的小轮廓对整体结果的影响。 if (cv::contourArea(*largest_contour) < 10) { return cv::Rect(); } // **轮廓形状过滤**:除了面积外,还可以考虑其他形状特征,如轮廓宽高比。这样可以排除一些不规则的轮廓,从而提高准确性。 cv::Rect bounding_box = cv::boundingRect(*largest_contour); float aspect_ratio = static_cast<float>(bounding_box.width) / bounding_box.height; if (aspect_ratio < 0.2 || aspect_ratio > 3) { return cv::Rect(); } // **轮廓稳定性检测**: // 通过比较当前帧和之前几帧的轮廓位置来判断轮廓的稳定性。 // 如果多帧之间的轮廓位置变化较小,则可以认为轮廓比较稳定,不需要进行过多的调整。 static std::vector<cv::Rect> prev_bounding_boxes; if (prev_bounding_boxes.size() > 5) { prev_bounding_boxes.erase(prev_bounding_boxes.begin()); } prev_bounding_boxes.push_back(bounding_box); if (prev_bounding_boxes.size() == 5) { float avg_width = 0.0; float avg_height = 0.0; for (const auto& box : prev_bounding_boxes) { avg_width += box.width; avg_height += box.height; } avg_width /= prev_bounding_boxes.size(); avg_height /= prev_bounding_boxes.size(); float width_diff = std::abs(bounding_box.width - avg_width) / avg_width; float height_diff = std::abs(bounding_box.height - avg_height) / avg_height; if (width_diff > 0.1 || height_diff > 0.1) { return cv::Rect(); } } // 对图像边框每个方向扩大15个像素 bounding_box.x = std::max(0, bounding_box.x - 15); bounding_box.y = std::max(0, bounding_box.y - 15); bounding_box.width = std::min(image.cols - bounding_box.x, bounding_box.width + 30); bounding_box.height = std::min(image.rows - bounding_box.y, bounding_box.height + 30); // 返回最大轮廓的边界框 return bounding_box; } 这里对所选轮廓进行预处理,让这个帧变成28*28*1的图像 // 预处理数字区域 cv::Mat preprocess_digit_region(const cv::Mat region) { // 将图像转换为灰度图像,然后调整大小为28x28,最后将像素值归一化为0到1之间的浮点数 cv::Mat gray, resized, bitwized, normalized; cv::cvtColor(region, gray, cv::COLOR_BGR2GRAY); // 扩大图像中的数字轮廓,使其更容易识别 cv::threshold(gray, gray, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); // 调整图像颜色,将图像颜色中低于127的像素值设置为0,高于200的像素值设置为255 cv::threshold(gray, gray, 127, 255, cv::THRESH_BINARY_INV); // 对图像黑白进行反转,黑色变成白色,白色变成黑色 cv::bitwise_not(gray, bitwized); // 手动实现黑白反转 for (int i = 0; i < bitwized.rows; i++) { for (int j = 0; j < bitwized.cols; j++) { bitwized.at<uchar>(i, j) = 255 - bitwized.at<uchar>(i, j); } } // 将图片大小调整为28x28,图片形状不发生畸变,过短的部分使用黑色填充 cv::resize(bitwized, resized, cv::Size(28, 28), 0, 0, cv::INTER_AREA); //定义一个局部静态变量,让其只初始化一次,让其在等于200时将图片保存到本目录下 static int count = 0; if (count == 5) { cv::imwrite("pre.jpg", resized); } count++; printf("count=%d\n", count); return resized; } 紧接着开始对这个区域进行识别 if (digit_rect.area() > 0) { cv::Mat digit_region = bgr(digit_rect); cv::Mat preprocessed = preprocess_digit_region(digit_region); // 运行推理 run_inference(&rknn_app_ctx, preprocessed); // 从predictions_queue中获取预测到的数字和其对应的概率 if (!predictions_queue.empty()) { Prediction prediction = predictions_queue.back(); cv::rectangle(bgr, digit_rect, cv::Scalar(0, 255, 0), 2); // 在图像上显示预测结果,显示字号为1,颜色为红色,粗细为2 cv::putText(bgr, std::to_string(prediction.digit), cv::Point(digit_rect.x, digit_rect.y - 10), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0), 2); // 在图像上显示预测概率 cv::putText(bgr, std::to_string(prediction.probability), cv::Point(digit_rect.x+ 30, digit_rect.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(230, 0, 0), 2); // 打印预测到的数字和其对应的概率 // printf("****** Predicted digit: %d, Probability: %.2f ******\n", prediction.digit, prediction.probability); // 从predictions_queue中删除最旧的元素 predictions_queue.pop_back(); } } 打上帧率 sprintf(text,"fps=%.1f",fps); cv::putText(bgr,text,cv::Point(0, 20),cv::FONT_HERSHEY_SIMPLEX,0.5, cv::Scalar(0,255,0),1); 最后就是将我们结果帧显示到fb设备映射的内存区域就行了,如下: //LCD Show cv::cvtColor(bgr, bgr565, cv::COLOR_BGR2BGR565); memcpy(framebuffer, bgr565.data, disp_width * disp_height * 2); #if USE_DMA dma_sync_cpu_to_device(framebuffer_fd); #endif //Update Fps end_time = clock(); fps= (float) (CLOCKS_PER_SEC / (end_time - start_time)) ; memset(text,0,16); 在程序结尾记得释放资源,代码如下 deinit_post_process(); #if USE_DMA dma_buf_free(disp_width*disp_height*2, &framebuffer_fd, bgr.data); #endif ret = release_yolov5_model(&rknn_app_ctx); if (ret != 0) { printf("release_yolov5_model fail! ret=%d\n", ret); } 这样我们的主要代码部分就编写完了。 3.编译 工程目录是使用cmake进行管理的。 我们进入cpp目录,创建build目录存放编译结果。然后运行下面步骤进行编译。 cd build export LUCKFOX_SDK_PATH=<Your Luckfox-pico Sdk Path> cmake .. make && make install 最后就可以看到我们可执行和库文件就出现在下面这个目录   我们将上面这个目录打包scp到我们的板子上就OK了   4.运行与运行结果 装上摄像头,系统是有一个默认的rkipc进行占用了摄像头,我们可以运行关闭脚本,也可以暴力杀死这个进程。 我使用的是暴力法,先看看进程的 PID   然后用kill 终止这个进程就OK了   运行输入./luckfox_yolov5_demo_test model/mnist.rknn即可运行,如下   运行效果如下,我照了几张识别图片,然后拍了一个视频效果,如下所示。             视频效果如下所示 [localvideo]747c7ba4680ed44ead001a98911df515[/localvideo]   总结:从上面的效果来看准确率还是可以的,能达到70左右的准确率。代码在:tang/RV1106模型部署_yolo和mnist - 码云 - 开源中国 (gitee.com),其中也包含了我跑的yolo代码。  

  • 回复了主题帖: 有没有大佬能帮忙内推实习

    jinchy 发表于 2024-5-25 10:09 建议去对应官网投简历,找一个自己喜欢的专业工作,很多公司都比较喜欢实习生的。 确实是这样,建议很中肯。boss上必须对方回复了才能投,官网就直接可以投简历了。

  • 回复了主题帖: 【AI挑战营终点站】应用落地:部署手写数字识别应用到幸狐RV1106开发板

    本帖最后由 qiao--- 于 2024-5-25 14:48 编辑 完成打卡:#AI挑战营终点站#数字识别模型部署 https://bbs.eeworld.com.cn/thread-1282906-1-1.html

  • 2024-05-22
  • 回复了主题帖: 【Luckfox幸狐 RV1106 Linux 开发板】5-给系统移植QT环境__显示电子时钟界面

    splendor 发表于 2024-5-22 13:56 你好,按照你的配置,我的应用到板子上什么字也不能显示。英文,汉字都不行。 你配置应该是对的,字库没有可用内容,搞一个字体文件到字库目录下就行了

  • 2024-05-21
  • 回复了主题帖: 有没有大佬能帮忙内推实习

    y909334873 发表于 2024-5-20 10:14 你这个项目经验最好着重写一下你在里面负责什么,侧重点在什么上,你简历上描述好多都太笼统,就是这些技能 ... 好的,谢谢建议

  • 回复了主题帖: 有没有大佬能帮忙内推实习

    本帖最后由 qiao--- 于 2024-5-23 00:07 编辑    

  • 2024-05-20
  • 回复了主题帖: 有没有大佬能帮忙内推实习

    dql2016 发表于 2024-5-19 23:37 你这个写的会的太多了,显得浮夸,别人会觉得你都是点到为止,没有稍微深入熟悉的东西,才大三而已,只需要 ... 哦哦,感谢建议。干嵌入式软件。

  • 2024-05-19
  • 发表了主题帖: 有没有大佬能帮忙内推实习

    本帖最后由 qiao--- 于 2024-5-21 17:58 编辑 25届毕业生,想找一份实习工作,关键投简历boss上基本全是已读不回,有些焦虑。想问问论坛上有没有大佬能给个内推,希望能和大佬成为同事。实在找不到实习就打算考研续命了,毕竟大环境不好。大佬乐于帮助的私信我,感谢。

  • 2024-05-17
  • 回复了主题帖: 【ST B-L475E-IOT01A1蓝牙Wi-Fi开发板】有没有大佬知道怎么给开发板测功耗?

    本帖最后由 qiao--- 于 2024-5-17 11:45 编辑 破案了,兄弟们,我测得方法没有错,但是我的工具不行,经过我翻阅手册和查阅相关资料发现这里的功耗必须使用专门测功耗的仪器才可以。下面这个标识语也可以说明通过这里测功耗是没有问题的,有兴趣有能力的朋友可以自行测试,因为我这里没有工具就不测了。  

  • 2024-05-08
  • 回复了主题帖: 入围名单公布:嵌入式工程师AI挑战营(初阶),获RV1106 Linux 板+摄像头的名单

    个人信息已确认,领取板卡,可继续完成&分享挑战营第二站和第三站任务。

  • 2024-05-06
  • 回复了主题帖: 【ST B-L475E-IOT01A1蓝牙Wi-Fi开发板】6-用ISM43362连手机热点

    Jacktang 发表于 2024-4-24 07:21 看来用ISM43362连手机热点操作也很容易 前提是把相关的代码移植好

  • 2024-04-30
  • 回复了主题帖: 【ST B-L475E-IOT01A1蓝牙Wi-Fi开发板】有没有大佬知道怎么给开发板测功耗?

    chejm 发表于 2024-4-27 14:18 楼主提出的问题,也是我等初学者关系的问题,希望有这方面经验的大佬能提供答案,非常感谢 测功耗,用一些专门测功耗的工具应该要方便些

  • 回复了主题帖: #AI挑战营第二站# Ubuntu平台下ONNX模型转RKNN

    本帖最后由 qiao--- 于 2024-4-30 16:49 编辑 楼主有过这样的报错没  

  • 回复了主题帖: #AI挑战营第二站# 基于RV1106的ONNX到RKNN模型转换实践

    兄弟这个是要转化mnist的模型,不是yolo

  • 2024-04-29
  • 发表了主题帖: #AI挑战营第二站#Ubuntu22上将ONNX模型转换成RKNN模型

    本帖最后由 qiao--- 于 2024-4-30 17:18 编辑 1.转换环境搭建 我这里的Linux环境是Ubuntu22,如下   我选择的转换方式是用RKNN-Toolkit2 Conda 环境。 首先下载conda的安装包,用下面的命令 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-4.6.14-Linux-x86_64.sh 然后安装miniconda chmod 777 Miniconda3-4.6.14-Linux-x86_64.sh bash Miniconda3-4.6.14-Linux-x86_64.sh   安装的时候一路按enter键就可以了。 创建 RKNN-Toolkit2 开发 Conda 环境,-n参数表示环境名称,指定 python 版本为3.8(建议版本) conda create -n RKNN-Toolkit2 python=3.8 我这里已经创建好了,如下   然后获取 RKNN-Toolkit2 安装包,RKNN-Toolkit2 工具在 PC 平台上提供 C 或 Python 接口,简化模型的部署和运行。用户可以通过该工具轻松完成以下功能:模型转换、量化、推理、性能和内存评估、量化精度分析以及模型加密。RKNN 软件栈可以帮助用户快速的将 AI 模型部署到 Rockchip 芯片。 git clone https://github.com/rockchip-linux/rknn-toolkit2.git   接着安装 RKNN-Toolkit2 相关的依赖库,cp38为对应的 Conda 环境 python 版本,实验使用的版本为 3.8 所以使用后缀为cp38的依赖项 pip install tf-estimator-nightly==2.8.0.dev2021122109 pip install -r rknn-toolkit2/packages/requirements_cp38-1.6.0.txt -i https://pypi.mirrors.ustc.edu.cn/simple/ 安装 RKNN-Toolkit2 pip install rknn-toolkit2/packages/rknn_toolkit2-1.6.0+81f21f4d-cp38-cp38-linux_x86_64.whl 安装好后,可以验证是否安装成功,如果没有报错说明安装成功,我这里是安装成功了的如下   下载 rknn_model_zoo,这是瑞芯微官方的用于转换模型的工具,里面有很多转换示例,转换代码我们可以借鉴一下这里面的 git clone https://github.com/airockchip/rknn_model_zoo.git   2.转换模型 前面我们已经将基础环境搭建好了,接下来可以来转换模型了。 我们找到我们训练营第一站训练出来的ONNX模型,将他拷贝到我们自己创建的文件夹myModel内,如下所示   紧接着我们新建一个convert.py文件里面使我们的转换代码,这个可以参考examples文件下的内容 from rknn.api import RKNN # Create RKNN object rknn = RKNN(verbose=True) # pre-process config print('--> config model') rknn.config(target_platform='rv1106', mean_values=[[28]], std_values=[[28]]) print('done') # Load model print('--> Loading model') ret = rknn.load_onnx(model='./mnist.onnx') if ret != 0: print('Load model failed!') exit(ret) print('done') rknn.build(do_quantization=True, dataset='./data.txt') # 构建RKNN模型,可选参数量化 if ret != 0: print('Build model failed!') exit(ret) print('done') ret = rknn.export_rknn('./mnist.rknn') # 导出RKNN模型文件 if ret != 0: print('Export rknn model failed!') exit(ret) print('done') # 释放 RKNN 对象 rknn.release() 然后新建一个pic文件夹,里面装我们的dateset,如下   新建data.txt指定数据集,填一张照片就可以了   最后运行convert.py 效果如下:   成功转换!给大家看一下我现在转换成功的文件目录    

最近访客

< 1/6 >

统计信息

已有366人来访过

  • 芯积分:724
  • 好友:4
  • 主题:54
  • 回复:154

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言