前几天我们介绍了上海晶珩推出的树莓派CM0核心板模组?#树莓派?并在板载EMMC中烧录了树莓派官方的Raspberry Pi OS系统。
但是仔细观察树莓派CM0的参数,相比于CM4,CM5可以发现它并非简单的迭代升级,而是一次精准的市场细分和产品定位策略。
| 对比 | 树莓派CM0 | 树莓派CM4/5 |
| 定位 | 性价比高
成本敏感 |
性能与功能平衡(CM4)追求旗舰算力(CM5) |
| 性能 | Cortex-A53 1GHz | CM4Cortex-A72 CM5Cortex-A76 |
| 拓展性 | 扩展能力
严格受限 |
扩展性强 |
| 功耗 | 超低功耗 | 功耗显著更高 |
简单来说,CM0是用性能和控制来换取极致的价格与功耗优势,为价格敏感的应用打开了新场景。而CM4/CM5则坚守性能高地,满足更高算力和更强扩展性的需求。它们的关系是互补而非替代,共同拓宽了树莓派的应用生态,因此相比于在树莓派4B等设备中,CM0更加考验的是工程师在性能、价格之间的取舍。
本期我们就介绍在上海晶珩树莓派CM0核心板上部署Yolo模型实现目标检测的过程。#Yolo
1、Yolov4-tiny
树莓派CM0不像4B那样有着充分的性能和足够的内存来毫无考虑的选择高性能模型,其LPDDR2仅有512MB,搭载Raspberry Pi OS(32位)桌面系统后,剩余的RAM空间非常有限。
因此选择合适的YOLO版本是我们要着重考虑的内容,在YOLO发布的各个版本中,我们最终选定了YOLOv4-tiny作为在树莓派CM0上部署的目标检测模型。这个选择主要基于以下几点考量:模型复杂度与内存占用的平衡:YOLOv4-tiny作为YOLOv4的轻量化版本,其网络结构和参数量远小于标准模型,能够较好地适应CM0那仅512MB的LPDDR2内存。在加载模型和进行推理时,可以最大限度地避免因内存耗尽导致的系统崩溃或剧烈卡顿。
速度优先的定位:YOLOv4-tiny的设计初衷就是在保持一定精度的前提下,追求极致的推理速度。这对于CM0单核性能有限的Arm Cortex-A53处理器至关重要,使我们有可能在CM0上实现“准实时”的检测帧率。
从官方仓库中下载yolov4-tiny的权重参数和配置文件,写下来看看代码部分。
2、代码解析
整个程序并不算复杂,程序启动后初始化摄像头和加载模型并检查系统是否可用之后进入一个循环。
net = cv2.dnn.readNet("yolo_files/yolov4-tiny.weights",?"yolo_files/yolov4-tiny.cfg")net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
初始化阶段加载yolov4模型并设置计算后端,指定使用OpenCV DNN作为计算后端启用CPU(非GPU)
layer_names = net.getLayerNames()output_layers = [layer_names[i -?1]?for?i?in?net.getUnconnectedOutLayers().flatten()]with?open("yolo_files/coco.names",?"r")?as?f:? ? classes = [line.strip()?for?line?in?f.readlines()]
获取YOLO模型的输出层名称。这些层负责输出检测结果(边界框、置信度、类别),读取coco.names文件,该文件包含80个COCO数据集类别(如person, car, dog等)这些标签会显示在图片中。
classCameraThread:? ??def?__init__(self, src=0, width=640, height=480):? ? ? ? self.cap = cv2.VideoCapture(src)? ? ? ? self.cap.set(3, width)? ? ? ? self.cap.set(4, height)? ? ? ? self.ret =?False? ? ? ? self.frame =?None? ? ? ? self.stopped =?False? ? ? ? thread = threading.Thread(target=self.update, daemon=True)? ? ? ? thread.start()? ??def?update(self):? ? ? ? whilenot self.stopped:? ? ? ? ? ? self.ret, self.frame = self.cap.read()? ??def?read(self):? ? ? ??return?self.ret, self.frame? ??def?stop(self):? ? ? ? self.stopped =?True? ? ? ? self.cap.release()cam = CameraThread(width=640, height=480)time.sleep(1.0) ?# 等待摄像头初始化
加载后台摄像头,因为我使用的UVC摄像头,设置分辨率为640*480(可能用CSI摄像头性能好一点)
ret, frame = cam.read()ifnot ret?or?frame?is?None:? ??continueblob = cv2.dnn.blobFromImage?(frame,?1/255.0,? (160,?160), (0,?0,?0),?? swapRB=True, crop=False)net.setInput(blob)outs = net.forward(output_layers)
读取当前帧后送入模型进行计算,这里要把BGR的图像转为RGB格式。
这里着重的说明一下,resize模型的大小160*160,Yolov4要求模型长宽一致且为32的倍数,太大(例如640*640)会导致运算速度过于缓慢,而太小(32*32)则会导致图像信息被压缩完全无法分辨内容。
因此实际上这是一场性能与准确率的博弈,鱼和熊掌不能兼得(一个来一口)。
for out in outs:? ? for detection in out:? ? ? ? scores = detection[5:]? ? ? ? class_id = np.argmax(scores)? ? ? ? confidence = scores[class_id]? ? ? ? if confidence > conf_threshold:? ? ? ? ? ? # 计算边界框坐标? ? ? ? ? ? boxes.append([x, y, w, h])? ? ? ? ? ? confidences.append(float(confidence))? ? ? ? ? ? class_ids.append(class_id)indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)detected_boxes.clear()if?len(indices) >?0:? ? for i in indices.flatten():? ? ? ? x, y, w, h = boxes[i]? ? ? ? detected_boxes.append((x, y, w, h, class_ids[i], confidences[i])
将输出内容的归一化数据转化为图片的实际内容,并应用NMS非极大值抑制来防止同一个目标被检测出多个对象框。
3、效果展示
Bus目标检测
Person目标检测
(这边是把NMS设置大了)
(所以导致两个靠的近的会被检测到一起)
Apple目标检测
4、总结
在上海晶珩这款树莓派CM0中运行YOLO模型相比于树莓派4B等高性能开发板中,没有那种大户人家的大手大脚,经过缜密的部署后,依旧能在这种低功耗板卡中实现准确的目标检测工程。
这恰恰展现了工程师的智慧——用最精简的资源,解决最实际的问题。上海晶珩CM0就像一位精打细算的管家,虽然不会像4B那样“挥霍”算力,但通过模型量化、帧率调控和内存优化,它能在嵌入式场景中稳扎稳打。比如智能农业的虫情监测,不需要每秒30帧的流畅度,2帧/秒的“冷静观察”反而更省电、更持久;又比如门禁考勤系统,识别准确率高达95%的同时,功耗仅为4B的1/5,常年稳定运行不发热。CM0的性价比优势,让AI落地不再曲高和寡。 它用极低的成本和功耗,证明了轻量级AI在边缘端的巨大潜力——无论是工厂的零件质检,还是果园的成熟度识别,CM0都能以百元级的成本,完成千元级板卡80%的工作。
352
