539|4

70

帖子

1

TA的资源

一粒金砂(高级)

楼主
 

#AI挑战营终点站#摸着石头过河,磕磕绊绊跑起来的手写数字识别 [复制链接]

本帖最后由 aramy 于 2024-5-27 08:58 编辑

  非常漂亮的小板子。非常喜欢,可惜板子上的机器学习使用的是C来完成的,自己只玩过python的,还玩的不好,有点崩溃了。记录一下这些日子,折腾的过程吧。

一、镜像烧写。

在官网https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-prepare提供了linux的镜像。提供的有ubuntu的镜像和buildroot镜像。

1镜像选择。Ubuntu的镜像,读取摄像头有问题,而且后续官方的例子都是基于buildroot镜像的,所以这里选择buildroot的镜像。手头板子是MAX版本的,所以选择对应的镜像。

 

2、镜像烧写。按官方文档,按下boot按键,再插入USB线。自己的win电脑始终无法通过SocToolKit工具烧写,这里我使用linux下的烧写方法烧写镜像。

 

这个镜像与收到板卡上自带的镜像文件是一致的。可以直接使用。使用ssh登录,登录账号:root;登录密码:luckfox;静态IP地址:172.32.0.93

 

二、开发环境搭建。

开发环境搭建,这里我是使用docker方式搭建。参考https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-SDK,使用docker还是比较简单的。

 

docker run -it --name luckfox -v /home/aramy/luckfoxtech:/home/luckfoxtech luckfoxtech/luckfox_pico:1.0 /bin/bash

首先尝试在这个环境下编译一下镜像文件。这一步超漫长(大概4小时+),制作镜像不是必要操作。但是下载luckfox-pico这个源码环境包是必须的,后边很多都依赖这里边的工具。

git clone https://gitee.com/LuckfoxTECH/luckfox-pico.git
cd luckfox-pico
git submodule update --init

#在本机上运行
cd tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/
source env_install_toolchain.sh

#进入docker的开发环境
./build.sh lunch
#选择8
 ./build.sh clean

尝试跑一下RKNN推理测试。

git clone https://github.com/rockchip-linux/rknn-toolkit2

先下载源码包,进入docker的环境,先配置一下 TOOLCHAIN交叉工具链环境变量。

#这里需要按自己搭建的环境进行修改。
export RK_RV1106_TOOLCHAIN=/home/luckfoxtech/luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf

cd /home/luckfoxtech/rknpu2/examples/RV1106_RV1103/rknn_yolov5_demo
chmod +x build-linux_RV1106.sh
./build-linux_RV1106.sh

 

编译完成后,生成一个install的文件夹。里边rknn_yolov5_demo为可执行文件。./model/RV1106/yolov5s-640-640.rknn为训练模型文件。将install文件夹下的所有文件 拷贝到RV1106的板子上,就可以跑例程了。拷贝文件我这里使用的是用ssh协议。在win下可以使用pscp,或者是ssh的图形化工具。

 

  

这里是使用自己的两张图片,进行识别,可以看出,第一张识别出两个cup,第二张识别出banana。官方提供的例程还是挺强大的。是一个分类例程,不过它只能识别coco_80_labels_list.txt文件定义了的80种物品。

三、尝试手写数字识别。

官方提供的例程是基于C语言的,而自己仅仅是在PC上使用Python跑过机器学习的例程。瞬间感觉差距太遥远了。

好在群里有老师,提供了例程,并且指导了如何实现,自己才磕磕碰碰地在RV1106上跑起来了手写数字识别。按自己的理解,整理了个处理流程图。

 

第一个学习的例程:https://github.com/luckfox-eng29/luckfox_pico_rtsp_opencv,这是一个获取摄像头图片,然后推流的项目。首先修改src下的main.cc文件,将摄像头的分辨率降低,然后在docker环境下编译该项目。

int width = 640;
int height = 480;
export LUCKFOX_SDK_PATH=/home/luckfoxtech/luckfox-pico/
mkdir build
cd build
cmake ..
make && make install

将编译完成的luckfox_rtsp_opencv_demo/luckfox_rtsp_opencv文件传到RV1106板子上。关闭RV1106上在运行的推流进程,然后给luckfox_rtsp_opencv添加可执行权限,并运行它。就可以是用VLC查看开发板的摄像头的图像了。

RkLunch-stop.sh
chmod 755 luckfox_rtsp_opencv
./luckfox_rtsp_opencv

第二个学习的例程:https://github.com/knva/luckfox_pico_rtsp_opencv

从这位老师的例程中,就可以看见整个手写识别的全流程实现。核心部分就是,从摄像头获取图片,然后寻找到数字部分的区域,截取该区域,转换为28X28灰度图,然后推理获得分类概率。在老师的指导下,终于在自己的电脑上完成了编译,并在RV1106开发板上跑了起来。

 

 

第三个学习的例程:https://gitee.com/luyism/luckfox_rtsp_mnist

从这个例程可以看出,核心思路还是没有变化。在处理上增加了许多处理。

// 在图像中找到数字的轮廓,同时减小找到轮廓时的抖动
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;
}

最终运行起来的结果,效果还是蛮赞的。

 

 

 

接下来,努力去读源代码,理解编程的思路和细节,去消化一下,在C环境下去实现机器学习的功能。

 

此帖出自编程基础论坛

最新回复

编译镜像这么久,是因为电脑性能不够吗?   详情 回复 发表于 2024-5-27 17:21
点赞 关注
 

回复
举报

6060

帖子

6

TA的资源

版主

沙发
 

编译一下镜像文件。这一步超漫长(大概4小时+)这应该是可以不做的吧

此帖出自编程基础论坛

点评

是的,可以不用。  详情 回复 发表于 2024-5-27 09:49
 
个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 
 

回复

70

帖子

1

TA的资源

一粒金砂(高级)

板凳
 
秦天qintian0303 发表于 2024-5-27 09:09 编译一下镜像文件。这一步超漫长(大概4小时+)这应该是可以不做的吧

是的,可以不用。

此帖出自编程基础论坛
 
 
 

回复

6773

帖子

2

TA的资源

版主

4
 

编译镜像这么久,是因为电脑性能不够吗?

此帖出自编程基础论坛

点评

嗯,电脑性能确实一般。笔记本是联想的T550。 不过用另外一个虚拟机,双核志强E5606  @ 2.13GHz 也差不多时间。  详情 回复 发表于 2024-5-28 08:52
 
 
 

回复

70

帖子

1

TA的资源

一粒金砂(高级)

5
 
wangerxian 发表于 2024-5-27 17:21 编译镜像这么久,是因为电脑性能不够吗?

嗯,电脑性能确实一般。笔记本是联想的T550。

不过用另外一个虚拟机,双核志强E5606  @ 2.13GHz 也差不多时间。

此帖出自编程基础论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表