简单记录一下最近做的小项目,主要是记性不太好,以免下次用起,又忘了怎么做
总体思路
- 寻找公开数据集
- kaggle训练yolov5模型
- aidlux部署模型
- post识别结果到电脑
- 使用flask框架接收处理数据
- 使用pyqt5编写简单的数据展示页面
公开数据集
数据集是从kaggle中寻找到的,不得不说kaggle是一个非常良心的平台,不仅给稳定好用的服务器还有很多公开的项目,放一下数据集链接
教室场景数据集
原始数据集中大概有4000多张标注过的数据,经过roboflow平台数据增强之后,有一万张左右标注过的图片,需要注意的一点是从平台下载的数据集直接使用会报错,我们需要在data.yaml文件中添加数据所在路径,
kaggle训练yolov5
这一步其实很简单,yolov5的github主页给了很多详细的教程,简单说一下需要避的坑吧
首先第一个就是input,它的真实路径为/kaggle/input,在该目录下的文件,是只读格式,不能被修改,没有尝试过通过命令修改权限,下次可以尝试一下
第二个就是这个输出文件夹,输出文件夹中的文件刷新太慢了,刷新不出来,所以在训练模型的时候,我们运行好代码,将其保存为一个version,它就能自己在那炼丹了,也会自动保存输出结果
然后就是加速器的选择,P100炼丹的时候会提示内存不够,因为yolov5的默认设置应该是把数据读入内存,所以P100炼不了,建议选T4X2
aidlux部署模型
aidlux我觉得就是一个在手机上运行的程序,模拟出了一个linux的环境,在这个环境中我们能进行一些操作,可以说是一个非常大的应用,大到你能把这个应用当做系统用,但是很不好用,下面放一些部署的代码文件
aidlux部署文件
aidlux官网说可以进行gpu加速,这个还没有尝试,因为场景对实时性没有太高的要求,此外,aidlux中提供了opencv的环境,但opencv中的imshow不能直接显示图像,有点不太好用,其他功能也主要依赖于其提供的api文档,但是官网的文档说的并不清楚,只解释了怎么run模型那部分,不是很好用
比较好的是提供了远程访问的端口,ssh是另一个端口,这个是web访问,和vscode结合一下,生产力还是很高的
post识别结果到电脑
这一步走的还是挺崎岖的,主要使用request库post数据到电脑ip,大概思路是读取到图片数据,然后对其进行base64编码(图片是narry格式,json只能传str),此时类型为byte,再对其进行ascii编码,将其转为str格式,我们解码的时候,反过来操作就行
数据格式转换参考文章
request post数据参考文章
上图为数据传输内容,以及post请求,这里直接使用的是主机的ip地址加端口的形式,这也是卡了半天的地方,刚开始一直不知道把数据发给谁
使用flask框架接收处理数据
这一步主要是在电脑上运行flask框架,这个框架会监听端口,即可以是内网的,也可以是外网ip的端口,感觉可以用它搭个小网站,其实它也提供了这种能力
贴一下flask参考文档
比较重要的是这个,这个的意思是只有从这个字段下post的数据,它才会处理
这个run函数中用来定义host port 和debug 刚开始不知道怎么定义host,找了大半天,run中还有一个参数可以设置,这里就不细说了
数据处理
接下来也是比较关键的,就是处理从aidlux发出的数据
首先我们通过json.loads将其转为字典,(直接访问好像确实不太行)然后索引数据的方式就和python的字典用法相同,这里我把文本数据写入到了txt文件中,数据不多,这样处理比较简单
下面就是解码图片,这里需要注意的是base64解码调用的是base64.b64decode函数,倒也不是啥大问题,主要是自己手打的时候,多敲了个字母,一直报错,我还以为没有这个函数,下次还是直接复制吧;接下来比编码多一步的是使用cv2的编码函数将其转为opencv的形式
接下来还有对图片的展示,为了便于传输数据,这里将其保存为图片,也是为了省事
使用pyqt5编写简单的数据展示页面
先贴一下参考文档,这个教程非常的认真仔细,搜出来的其他文档跟粑粑一样
虽说pyqt5非常的简单好用,但是它的写法主流还是使用类的方式,小白看起来还是非常的脑袋发懵,这里就简单用其展示一下识别结果,数据统计,以及一个按钮
就跟上图一样,非常的简单,首先贴一下图片展示代码
文本展示代码
按钮
这个按钮看起来无足轻重但是非常的重要,由于像上面这样简单编写出来的页面并不能对数据进行刷新,所以,不能满足我们的项目需求,这个时候我们就需要掌握一下pyqt5中的多线程知识,这个按钮就是我们线程启动的一个开关
线程定义,简单定义一下发送数据,也可以理解为信号
调用线程,当有信号来的时候就会调用set_label_func函数,起名有点随意,主要是懒得改了
该函数实现的功能如下所示,主要实现了对三个数据的刷新
数据处理
这里面最难处理的数据应该就是区域的划分
def read_mark(self):
area = [0,0,0,0,0,0,0,0,0,0]
Note=open('G:\python-code\https-server\mark.txt',mode='r')
#逐行读取
line = Note.readline()
while line:
# print (line[26])
box_x1_multiple = line[14] #结果为str格式
box_y1_multiple = line[28]
box_x2_multiple = line[42]
box_y2_multiple = line[56]
# print(type(box_x1_multiple))
box_x1 = int(float(line[2:6])*pow(10,int(box_x1_multiple)))
box_y1 = int(float(line[16:20])*pow(10,int(box_y1_multiple)))
box_x2 = int(float(line[30:34])*pow(10,int(box_x2_multiple)))
box_y2 = int(float(line[44:48])*pow(10,int(box_y2_multiple)))
center_x = int(box_x1+(box_x2)/2)
center_y = int(box_y1+(box_y2)/2)
print(box_x1,box_x2 ,center_x ,box_y1 ,box_y2 ,center_y)
area_num =self.area_judge(center_x,center_y)
area[area_num]=int(area[area_num])+1
print(area)
line = Note.readline()
Note.close()
return area
def area_judge(self,x,y):
#print(x,y)
if x<213 and y<213:
return 1
elif 213<x<416 and y<213:
return 2
elif 416<x and y<213:
return 3
elif x<213 and 213<y<416:
return 4
elif 213<x<416 and 213<y<416:
return 5
elif 416<x and 213<y<416:
return 6
elif x<213 and 416<y:
return 7
elif 213<x<416 and 416<y:
return 8
elif 416<x and 416<y:
return 9
else:
return 0
上图为从aidlux中接收到的识别结果数据,每一行的数据分别为 左上角x y 识别框的宽度 长度 置信度 ,第一次处理数据时整错了,导致划分数据异常,其实str格式的数据可以转为numpy格式,这样索引就会非常的简单,这里就先简单的按照数组来处理
需要注意的是,提取出的x y和长宽值仍然为str格式,进行运算时,需要对其进行格式转换,然后对计算出的anchor中心点进行判断其落在哪个区域
展示排版
其实界面的展示排版还有点小问题,但也不影响使用,就没继续研究,界面的排版主要参考这篇文章,代码比较冗长,就不贴了