3.3.1. OpenMV
嵌入式视觉主要是使用 openmv/k230/maxicam 来和控制部分作配合,三种都是轻量化的视觉模块,openmv 和 k230 主要使用 MV 库而非 CV 库进行图像处理,更加轻量化,而 k230 则可以跑模型(有官方的线上训练模型,也可以接入 yolov5/v8),通过训练模型来识别特定的较复杂的物体;
OpenMV 性能低于 K230,但 IDE 更好用也更容易上手:OpenMV - 从入门到实战!
官方文档:序言 · OpenMV 中文入门教程
3.3.2. K230
K230 性能优于 OpenMV 并且被嘉立创打下了价格更加便宜,确定就是 IDE 很难用很不方便,然后教程看嘉立创官方的或 K230 官方的文档:立创·庐山派 K230-CanMV 开发板【介绍】 | 立创开发板技术文档中心 CanMV-K230 快速入门指南 — CanMV K230
而线上训练模型则:在线 AI 模型训练 - 入门指南 - 勘智开发者社区
简单说下模型训练流程:拍数据集–> 打标–> 训练–> 导入模型
贴一份可用的导入模型代码:
python
# ======================== 人质检测模型 ========================= #
# ======================== 只需修改路径 ========================= #
# 显示相关参数
display_mode = "hdmi"
if display_mode == "lcd":
DISPLAY_WIDTH = ALIGN_UP(800, 16)
DISPLAY_HEIGHT = 480
else:
DISPLAY_WIDTH = ALIGN_UP(1920, 16)
DISPLAY_HEIGHT = 1080
OUT_RGB888P_WIDTH = ALIGN_UP(640, 16)
OUT_RGB888P_HEIGHT = 360
# 路径和配置
root_path = "/data/model/ThreeHostages/"
config_path = root_path + "deploy_config.json"
deploy_conf = {}
debug_mode = 0
# 人质检查模型初始化函数
def detection_init():
"""
初始化人质检测系统
包括加载模型、配置传感器和显示等
"""
global _detection_initialized, _kpu, _ai2d_builder, _osd_img
global _ai2d_output_tensor, _deploy_conf, _kmodel_frame_size, _frame_size
global _labels, _num_classes, _color_four, _confidence_threshold
global _nms_threshold, _anchors, _nms_option, _strides
if _detection_initialized:
print("[WARNING] Detection already initialized")
return
# 使用json读取内容初始化部署变量
_deploy_conf = _read_deploy_config(config_path)
kmodel_name = _deploy_conf["kmodel_path"]
_labels = _deploy_conf["categories"]
_confidence_threshold = _deploy_conf["confidence_threshold"]
_nms_threshold = _deploy_conf["nms_threshold"]
img_size = _deploy_conf["img_size"]
_num_classes = _deploy_conf["num_classes"]
_color_four = get_colors(_num_classes)
_nms_option = _deploy_conf["nms_option"]
model_type = _deploy_conf["model_type"]
if model_type == "AnchorBaseDet":
_anchors = _deploy_conf["anchors"][0] + _deploy_conf["anchors"][1] + _deploy_conf["anchors"][2]
_kmodel_frame_size = img_size
_frame_size = [OUT_RGB888P_WIDTH, OUT_RGB888P_HEIGHT]
_strides = [8, 16, 32]
# 计算padding值
top, bottom, left, right, ratio = _two_side_pad_param(_frame_size, _kmodel_frame_size)
# 初始化kpu
_kpu = nn.kpu()
_kpu.load_kmodel(root_path + kmodel_name)
# 初始化ai2d
ai2d = nn.ai2d()
ai2d.set_dtype(nn.ai2d_format.NCHW_FMT, nn.ai2d_format.NCHW_FMT, np.uint8, np.uint8)
ai2d.set_pad_param(True, [0, 0, 0, 0, top, bottom, left, right], 0, [114, 114, 114])
ai2d.set_resize_param(True, nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)
_ai2d_builder = ai2d.build(
[1, 3, OUT_RGB888P_HEIGHT, OUT_RGB888P_WIDTH],
[1, 3, _kmodel_frame_size[1], _kmodel_frame_size[0]]
)
# 创建OSD图像
_osd_img = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888)
# 准备ai2d输出tensor
data = np.ones((1, 3, _kmodel_frame_size[1], _kmodel_frame_size[0]), dtype=np.uint8)
_ai2d_output_tensor = nn.from_numpy(data)
_detection_initialized = True
# 人质检测运行函数
def detection_run(rgb888p_img):
"""
运行一次人质检测
返回检测到的目标列表
:param image.Image rgb888p_img: 输入的RGB888P格式图像
:return list: 检测结果列表, 每个元素为 (标签, 置信度, x, y, w, h)
"""
global _detection_initialized, _kpu, _ai2d_builder, _osd_img
global _ai2d_output_tensor, _kmodel_frame_size, _frame_size
global _labels, _num_classes, _color_four, _confidence_threshold
global _nms_threshold, _anchors, _nms_option, _strides
if not _detection_initialized:
print("[ERROR] Detection not initialized. Call detection_init() first")
return []
det_results = []
with ScopedTiming("total", debug_mode > 0):
if rgb888p_img.format() == image.RGBP888:
ai2d_input = rgb888p_img.to_numpy_ref()
ai2d_input_tensor = nn.from_numpy(ai2d_input)
# 使用ai2d进行预处理
_ai2d_builder.run(ai2d_input_tensor, _ai2d_output_tensor)
# 设置模型输入
_kpu.set_input_tensor(0, _ai2d_output_tensor)
# 模型推理
_kpu.run()
# 获取模型输出
results = []
for i in range(_kpu.outputs_size()):
out_data = _kpu.get_output_tensor(i)
result = out_data.to_numpy()
result = result.reshape((result.shape[0] * result.shape[1] * result.shape[2] * result.shape[3]))
del out_data
results.append(result)
# 使用aicube模块封装的接口进行后处理
det_boxes = aicube.anchorbasedet_post_process(
results[0],
results[1],
results[2],
_kmodel_frame_size,
_frame_size,
_strides,
_num_classes,
_confidence_threshold,
_nms_threshold,
_anchors,
_nms_option,
)
# 绘制结果
_osd_img.clear()
if det_boxes:
for det_boxe in det_boxes:
x1, y1, x2, y2 = det_boxe[2], det_boxe[3], det_boxe[4], det_boxe[5]
w = x2 - x1
h = y2 - y1
_osd_img.draw_rectangle(x1, y1, w, h, color=_color_four[det_boxe[0]][1:])
text = _labels[det_boxe[0]] + " " + str(round(det_boxe[1], 2))
_osd_img.draw_string_advanced(x1, y1 - 40, 32, text, color=_color_four[det_boxe[0]][1:])
# 保存检测结果
det_results.append({
"class": _labels[det_boxe[0]],
"confidence": det_boxe[1],
"x": x1,
"y": y1,
"w": w,
"h": h
})
Display.show_image(_osd_img, 0, 0, Display.LAYER_OSD3)
gc.collect()
return det_results
# 两侧填充参数计算函数
def _two_side_pad_param(input_size, output_size):
ratio_w = output_size[0] / input_size[0] # 宽度缩放比例
ratio_h = output_size[1] / input_size[1] # 高度缩放比例
ratio = min(ratio_w, ratio_h) # 取较小的缩放比例
new_w = int(ratio * input_size[0]) # 新宽度
new_h = int(ratio * input_size[1]) # 新高度
dw = (output_size[0] - new_w) / 2 # 宽度差
dh = (output_size[1] - new_h) / 2 # 高度差
top = int(round(dh - 0.1))
bottom = int(round(dh + 0.1))
left = int(round(dw - 0.1))
right = int(round(dw - 0.1))
return top, bottom, left, right, ratio
# 读取deploy_config.json配置文件
def _read_deploy_config(config_path):
# 打开JSON文件以进行读取deploy_config
with open(config_path, "r") as json_file:
try:
# 从文件中加载JSON数据
config = ujson.load(json_file)
except ValueError as e:
print("JSON 解析错误:", e)
return config
# 模型相关变量
_detection_initialized = False
_kpu = None
_ai2d_builder = None
_sensor = None
_osd_img = None
_ai2d_output_tensor = None
_deploy_conf = None
_kmodel_frame_size = None
_frame_size = None
_labels = None
_num_classes = None
_color_four = None
_confidence_threshold = None
_nms_threshold = None
_anchors = None
_nms_option = None
_strides = None这是关于赞助的一些描述
- 本文链接:https://kaede-rei.github.io/learning-path/electrical-control/3-3
- 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 许可协议。