硬件介绍
如上图所示为M5Stack UintV2的硬件框图,核心是SigmaStar公司出产的一颗高度集成的嵌入式SoC芯片。它基于ARM Cortex-A7双核1.2GHz内核,集成了硬件H.264/H.265视屏解码器,内置DDR,内置2D图形引擎,支持TTL/mipi屏显示驱动接口,内置以太网mac和phy。主要应用于智能楼宇室内机、智能家居中控、86盒家庭中控、电梯楼层显示器、IP网络广播设备等等。
在M5Stack UintV2中,硬件资源如下所示:
-
内置RAM 128MB -DDR3
-
256MB NAND FLASH
-
CPU: Dual Cortex-A7 1.2Ghz 双核
- Sensor:GC2145
-
无线(RTL8188FTV)
- TF卡(16GB)
-
mic
-
LED灯(红灯和蓝灯)
-
独立按键
实现功能
本次主要选择的是任务一:捕捉常见小动物的活动习惯,上传到PC端,生成报表。
不过具体的实现还是有一些差异:
- 识别结果一方面上传云服务器,进行记录,然后将结果推送到微信;
- 识别结果另一方面直接推送到微信。
实现思路与代码分析
如上图所示,为整个系统的一个结构图,涉及到代码编写的主要是两个部分:M5Stack UintV2以及云服务器上。
M5Stack UintV2
在M5Stack UintV2上面主要执行的任务有三个:
-
- 通过摄像头采集图像,并对其进行动物识别。
- 将识别结果通过企业微信服务推送到手机上。
- 将识别结果通过MQTT发送到云服务器上的MQTT服务器上。
微信推送的模块代码如下所示,依据企业微信API接口手册编写即可。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import requests
import json
class Wecom:
def __init__(self, agentid, accesstoken):
self.agentid = agentid
self.accesstoken = accesstoken
def send_msg(self, title, description, url, picurl):
post_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={}'.format(self.accesstoken)
data = {
"touser": "@all",
"msgtype": "news",
"agentid": self.agentid,
"news": {
"articles": [{
"title": title,
"description": description,
"url": url,
"picurl": picurl
}]
},
"enable_id_trans": 0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
r = requests.post(url=post_url, data=json.dumps(data))
r = r.json()
print(r)
def upload_image(self, image_path):
post_url = 'https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token={}'.format(self.accesstoken)
files = { 'media': open(image_path, 'rb') }
r = requests.post(url=post_url, files=files)
r = r.json()
print(r)
return r['url']
if __name__=='__main__':
AGENTId = ****
ACCESSTOKEN = '****'
IMAGE_PATH = 'image.jpg'
wecom = Wecom(AGENTId, ACCESSTOKEN)
image_url = wecom.upload_image(IMAGE_PATH)
title = "检测到动物"
description = "原来是只猫"
url = image_url
picurl = image_url
wecom.send_msg(title, description, url, picurl)
M5Stack UintV2上执行的主要逻辑如下所示,其主要逻辑就是获取当前识别的图像信息以及对应的识别结果,当识别结果连续10次为猫,且置信度大于0.98时,认为识别成功。此刻会依据识别结果在图片上画出识别目标以及标上识别目标以及置信度。这个数据最终通过企业微信接口推送到微信上。另外一方面,通过MQTT将识别的信息发送的MQTT服务器。
while True:
doc = json.loads(object_recognition_process.stdout.readline().decode('utf-8'))
if 'img' in doc:
image = bytes(base64.b64decode(doc["img"]))
elif 'num' in doc:
for obj in doc['obj']:
print('type:{} prob:{} x:{} y:{} w:{} h:{} num:{}'.format(obj['type'], obj['prob'], obj['x'], obj['y'], obj['w'], obj['h'], affirm_num))
if obj['type'] == 'cat' and obj['prob'] >= AFFIRM_PROB_MAX:
affirm_num = affirm_num + 1
else:
affirm_num = 0
if affirm_num >= AFFIRM_NUM_MAX:
affirm_num = 0
print('-----Save image {}'.format(IMAGE_PATH))
with open(IMAGE_PATH, 'wb') as f:
f.write(image)
print('-----OpenCV image {}'.format(CV_IMAGE_PATH))
img = cv2.imread(IMAGE_PATH)
x1 = round(1/2 * obj['x'])
y1 = round(1/2 * obj['y'])
x2 = x1 + round(1/2 * obj['w'])
y2 = y1 + round(1/2 * obj['h'])
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 3)
cv2.putText(img, '{}:{}'.format(obj['type'], obj['prob']), (x1, y2+10), cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.8, (0, 255, 0))
cv2.imwrite(CV_IMAGE_PATH, img)
print('-----Send MQTT message')
data = {
'target': 'cat',
'prob': obj['prob']
}
mqtt_client.publish(topic=MQTT_TOPIC, payload=json.dumps(data), qos=0, retain=False)
print('-----Upload file {}'.format(CV_IMAGE_PATH))
image_url = wecom.upload_image(CV_IMAGE_PATH)
print("-----Send wecom message")
title = "检测到动物"
description = "原来是一只猫, 大概有{}%像".format(str(round(obj['prob']*100, 2)))
url = image_url
picurl = image_url
wecom.send_msg(title, description, url, picurl)
time.sleep(10)
识别结果推送到手机展示如下所示:
识别结果推送到MQTT服务器示意如下:
云服务器
在云服务器上主要执行的任务为:接受来自M5Stack UintV2发送的图片识别结果,将其保存到Excel文件中,当保存的条目达到10条时,将Excel文件生成图片,然后通过企业微信的接口推送到手机上。
在云服务器上主要的代码逻辑如下所示,其主要的作用就是从MQTT接受来自M5STack UintV2发送的消息({"target":"xxx","prob":xxxx}),然后将其写入到Excel文件中。当文件中的条目数量达到预设值(EXCEL_MAX_ITEM)时,使用当前所有条目信息生成图片,然后调用企业微信的接口将数据推送到手机端。
def on_message(client, userdata, msg):
if msg.topic == MQTT_TOPIC:
time = current_time()
data = json.loads(msg.payload)
print("{} : {} : {}".format(time, data['target'], data['prob']))
excel.add_item(time, data['target'], data['prob'])
if excel.get_item_num() >= EXCEL_MAX_ITEM:
print("Create image {}".format(IMAGE_FILE_PATH))
excel.save_to_image(IMAGE_FILE_PATH)
excel.clean_item()
print("Compress the image to 1080")
image = Image.open(IMAGE_FILE_PATH)
image.thumbnail((1920, 1080))
image.save(IMAGE_FILE_PATH_1080)
print("Upload file {}".format(IMAGE_FILE_PATH_1080))
image_url = wecom.upload_image(IMAGE_FILE_PATH_1080)
title = "检测统计"
description = "记录过去{}次的检测记录".format(EXCEL_MAX_ITEM)
url = image_url
picurl = image_url
print("Send message")
wecom.send_msg(title, description, url, picurl)
手机上收到的推送结果如下图所示,内容包含:序号、消息接受时间、识别目标类型、置信度。
遇到的主要难题
这一次遇到的问题还是比较多,但是大部分都是解决了,对于自身的提升也是很大,遇到的问题主要集中在以下几个点:
- Python之前没用过,需要重新开始学习。
- 企业微信的推送方式也第一次接触,需要阅读文档以及测试。
- M5Stack提供的Demo,对于基础薄弱的我,看起来还是真的比较难。
心得以及建议
通过这一次的活动,体验了SSD202这颗芯片的强大之处,芯片的集成度高,价格便宜,很适合用在有边缘计算需求的设备上。同时通过这一次的活动,学习使用Python以及各种库、接口的使用,简直不要太容易,用于进行功能快速实现具有相当大的优势。
虽然M5Stack做了很多的封装便于上手使用,但是实际上这个芯片上当前能做的操作还是很有限的,希望后续能够提供更多的资料,使个人开发者也能使用这款芯片来完成更多的高阶操作。同时也希望电子森林后续能够推出更多的这类活动。