import time
import os
import sys
import ustruct
import ustruct
from machine import UART
from machine import FPIOA
import os,sys
import time
from machine import UART
from media.sensor import *
from media.display import *
from media.media import *
# 初始化FPIOA和UART
fpioa = FPIOA()
fpioa.set_function(3, FPIOA.UART1_TXD)
fpioa.set_function(4, FPIOA.UART1_RXD)
uart = UART(UART.UART1, baudrate=115200)
def create_packet(x, y, z):
# 创建10字节缓冲区
packet = bytearray(10)
mv = memoryview(packet)
# 帧头 (2字节)
mv[0:2] = b'\x2C\x12'
# 数据部分:3个16位整数 (6字节)
ustruct.pack_into('>HHH', mv, 2, x, y, z)
# 计算校验和 (索引2-7的异或值)
checksum = 0
for i in range(2, 8):
checksum ^= mv[i]
mv[8] = checksum
# 帧尾 (1字节)
mv[9] = 0x5B
return packet
sensor = None
try:
print("camera_test")
# 初始化摄像头
sensor = Sensor(width=640, height=640)
sensor.reset()
sensor.set_framesize(width=1280, height=720)
sensor.set_pixformat(Sensor.RGB565)
# 初始化显示
Display.init(Display.LT9611, to_ide=True)
MediaManager.init()
sensor.run()
# 红色检测阈值
red_thresholds = [
(30, 100, 15, 127, 15, 127),
(30, 100, -127, -15, -127, -15)
]
# 方框定义 (x, y, w, h)
boxes = {
"B": (490, 0, 300, 720), # 蓝色方框
"R": (100, 210, 300, 300), # 红色方框
"Y": (880, 210, 300, 300) # 黄色方框
}
# 颜色定义
colors = {
"B": (0, 0, 255),
"R": (255, 0, 0),
"Y": (255, 255, 0)
}
clock = time.clock()
while True:
clock.tick()
os.exitpoint()
img = sensor.snapshot(chn=CAM_CHN_ID_0)
# 1. 绘制方框
for name, box in boxes.items():
img.draw_rectangle(box[0], box[1], box[2], box[3], color=colors[name], thickness=2)
# 2. 检测红色目标
detections = {name: False for name in boxes}
blue_coord = None
red_in_blue = None
status_val = 0 # 初始化状态值
for name, box in boxes.items():
blobs = img.find_blobs(
red_thresholds,
False,
box,
x_stride=5,
y_stride=5,
pixels_threshold=1000,
area_threshold=1000,
merge=True,
margin=10
)
if blobs:
detections[name] = True
if name == "B": # 蓝色方框
blob = blobs[0]
blue_coord = (blob.cx(), blob.cy())
img.draw_cross(blue_coord[0], blue_coord[1], color=(0, 255, 255), size=8, thickness=2)
# 在蓝色方框中查找红色目标
red_blobs = img.find_blobs(
red_thresholds,
False,
box,
x_stride=5,
y_stride=5,
pixels_threshold=100,
area_threshold=100,
merge=True,
margin=10
)
if red_blobs:
largest_blob = max(red_blobs, key=lambda b: b.pixels())
red_in_blue = (largest_blob.cx(), largest_blob.cy())
img.draw_cross(red_in_blue[0], red_in_blue[1], color=(255, 0, 0), size=8, thickness=2)
img.draw_string_advanced(
box[0] + 5, box[1] + 5, 10,
f"Red: {red_in_blue[0]},{red_in_blue[1]}",
color=(255, 0, 0),
bg_color=(0, 0, 0)
)
# 3. 计算状态值
total = sum(detections.values())
status_val = total # 保存为整数
status = f"{total}" # 显示用的字符串
# 4. 创建并发送数据包
if red_in_blue:
x_val = red_in_blue[0]
y_val = red_in_blue[1]
else:
# 未检测到时发送默认值
x_val, y_val = 0, 0
packet = create_packet(x_val, y_val, status_val)
uart.write(packet) # 发送数据包
# 显示信息
img.draw_string_advanced(10, 10, 10, status, color=(255, 255, 0), bg_color=(0, 0, 0))
if blue_coord:
coord = f"{blue_coord[0]},{blue_coord[1]}"
img.draw_string_advanced(10, 40, 10, coord, color=(0, 255, 255), bg_color=(0, 0, 0))
img.draw_string_advanced(550, 10, 10, f"{clock.fps():.1f}", color=(255, 255, 0), bg_color=(0, 0, 0))
img.compressed_for_ide()
Display.show_image(img)
# 控制台输出
if red_in_blue:
print(f"蓝色方框内红色目标坐标: ({red_in_blue[0]}, {red_in_blue[1]})")
else:
print("蓝色方框内未检测到红色目标")
print(f"状态: {status_val}")
except KeyboardInterrupt:
print("程序已停止")
except Exception as e:
print(f"错误: {e}")
finally:
if sensor:
sensor.stop()
Display.deinit()
MediaManager.deinit()
import os
import time
import ujson
import nncase_runtime as nn
import ulab.numpy as np
from media.sensor import *
from media.display import *
from media.media import *
# 显示模式配置
display_mode = "lcd" # "lcd" 或 "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(1280, 16)
OUT_RGB888P_HEIGHT = 720
NUM_CLASSIFY_PATH = "/sdcard/num_classify/"
CONFIG_PATH = NUM_CLASSIFY_PATH + "deploy_config.json"
# 红色检测配置
RED_THRESHOLDS = [
(30, 100, 15, 127, 15, 127),
(30, 100, -127, -15, -127, -15)
]
BOXES = {
"B": (490, 0, 300, 720), # 蓝色方框
"R": (100, 210, 300, 300), # 红色方框
"Y": (880, 210, 300, 300) # 黄色方框
}
COLORS = {
"B": (0, 0, 255),
"R": (255, 0, 0),
"Y": (255, 255, 0)
}
class ScopedTiming:
"""性能计时工具类"""
def __init__(self, info="", enable_profile=True):
self.info = info
self.enable_profile = enable_profile
def __enter__(self):
if self.enable_profile:
self.start_time = time.time_ns()
return self
def __exit__(self, exc_type, exc_value, traceback):
if self.enable_profile:
elapsed_time = time.time_ns() - self.start_time
print(f"{self.info} took {elapsed_time / 1000000:.2f} ms")
def read_deploy_config(config_path):
"""读取部署配置文件"""
with open(config_path, 'r') as json_file:
return ujson.load(json_file)
def softmax(x):
"""Softmax函数"""
exp_x = np.exp(x - np.max(x))
return exp_x / np.sum(exp_x)
def sigmoid(x):
"""Sigmoid函数"""
return 1 / (1 + np.exp(-x))
def main():
"""主函数"""
# 读取数字分类配置
deploy_conf = read_deploy_config(CONFIG_PATH)
kmodel_name = deploy_conf["kmodel_path"]
labels = deploy_conf["categories"]
confidence_threshold = deploy_conf["confidence_threshold"]
img_size = deploy_conf["img_size"]
num_classes = deploy_conf["num_classes"]
# 初始化KPU
kpu = nn.kpu()
kpu.load_kmodel(NUM_CLASSIFY_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_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, img_size[0], img_size[1]])
# 初始化传感器
sensor = Sensor()
sensor.reset()
sensor.set_hmirror(False)
sensor.set_vflip(False)
# 设置多路输出
sensor.set_framesize(width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT) # 通道0: 显示
sensor.set_pixformat(PIXEL_FORMAT_YUV_SEMIPLANAR_420, chn=CAM_CHN_ID_0)
sensor.set_framesize(width=OUT_RGB888P_WIDTH, height=OUT_RGB888P_HEIGHT, chn=CAM_CHN_ID_1) # 通道1: 红色检测
sensor.set_pixformat(PIXEL_FORMAT_RGB_565, chn=CAM_CHN_ID_1)
sensor.set_framesize(width=OUT_RGB888P_WIDTH, height=OUT_RGB888P_HEIGHT, chn=CAM_CHN_ID_2) # 通道2: 数字分类
sensor.set_pixformat(PIXEL_FORMAT_RGB_888_PLANAR, chn=CAM_CHN_ID_2)
# 绑定显示
sensor_bind_info = sensor.bind_info(x=0, y=0, chn=CAM_CHN_ID_0)
if display_mode == "lcd":
Display.init(Display.ST7701, to_ide=True)
else:
Display.init(Display.LT9611, to_ide=True)
Display.bind_layer(**sensor_bind_info, layer=Display.LAYER_VIDEO1)
# 创建OSD层用于绘制结果
osd_img = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888)
# 初始化媒体
MediaManager.init()
sensor.run()
# 初始化AI2D输入输出张量
data = np.ones((1, 3, img_size[0], img_size[1]), dtype=np.uint8)
ai2d_output_tensor = nn.from_numpy(data)
# 主循环
clock = time.clock()
try:
while True:
clock.tick()
os.exitpoint()
# === 红色目标检测任务 ===
rgb565_img = sensor.snapshot(chn=CAM_CHN_ID_1)
if rgb565_img == -1:
continue
detections = {name: False for name in BOXES}
red_in_blue = None
red_count = 0
for name, box in BOXES.items():
blobs = rgb565_img.find_blobs(
RED_THRESHOLDS,
False,
box,
x_stride=5,
y_stride=5,
pixels_threshold=1000,
area_threshold=1000,
merge=True,
margin=10
)
if blobs:
detections[name] = True
red_count += 1
if name == "B": # 蓝色方框
blob = blobs[0]
# 在蓝色方框中查找红色目标
red_blobs = rgb565_img.find_blobs(
RED_THRESHOLDS,
False,
box,
x_stride=5,
y_stride=5,
pixels_threshold=100,
area_threshold=100,
merge=True,
margin=10
)
if red_blobs:
largest_blob = max(red_blobs, key=lambda b: b.pixels())
red_in_blue = (largest_blob.cx(), largest_blob.cy())
# === 数字分类任务 ===
rgb888p_img = sensor.snapshot(chn=CAM_CHN_ID_2)
if rgb888p_img == -1:
continue
cls_idx = -1
score = 0.0
digit_label = "N/A"
if rgb888p_img.format() == image.RGBP888:
ai2d_input = rgb888p_img.to_numpy_ref()
ai2d_input_tensor = nn.from_numpy(ai2d_input)
# 预处理并推理
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()):
output_data = kpu.get_output_tensor(i)
result = output_data.to_numpy()
results.append(result)
# 处理分类结果
if num_classes > 2:
softmax_res = softmax(results[0][0])
cls_idx = np.argmax(softmax_res)
if softmax_res[cls_idx] > confidence_threshold:
score = softmax_res[cls_idx]
digit_label = labels[cls_idx]
else:
sigmoid_res = sigmoid(results[0][0][0])
if sigmoid_res > confidence_threshold:
cls_idx = 1
score = sigmoid_res
digit_label = labels[1]
else:
cls_idx = 0
score = 1 - sigmoid_res
digit_label = labels[0]
# === 控制台输出(简化版) ===
print(f"识别数字: {digit_label}")
print(f"红色目标数量: {red_count}")
if red_in_blue:
print(f"蓝色框内红色坐标: ({red_in_blue[0]}, {red_in_blue[1]})")
else:
print("蓝色框内红色坐标: 无")
# === 屏幕显示 ===
osd_img.clear()
# 绘制方框
for name, box in BOXES.items():
osd_img.draw_rectangle(box[0], box[1], box[2], box[3],
color=COLORS[name], thickness=2)
# 绘制红色目标坐标
if red_in_blue:
osd_img.draw_cross(red_in_blue[0], red_in_blue[1],
color=(255, 0, 0), size=8, thickness=2)
osd_img.draw_string_advanced(
BOXES["B"][0] + 5, BOXES["B"][1] + 5, 10,
f"Red: {red_in_blue[0]},{red_in_blue[1]}",
color=(255, 0, 0),
bg_color=(0, 0, 0)
)
# 显示红色目标数量
osd_img.draw_string_advanced(10, 10, 10, f"Red Count: {red_count}",
color=(255, 255, 0), bg_color=(0, 0, 0))
# 显示数字分类结果
if cls_idx >= 0:
osd_img.draw_string_advanced(
10, 40, 10,
f"Digit: {digit_label} ({score:.2f})",
color=(0, 255, 0),
bg_color=(0, 0, 0)
)
# 显示帧率
osd_img.draw_string_advanced(550, 10, 10, f"FPS: {clock.fps():.1f}",
color=(255, 255, 0), bg_color=(0, 0, 0))
Display.show_image(osd_img, 0, 0, Display.LAYER_OSD3)
except KeyboardInterrupt:
print("程序已停止")
except Exception as e:
print(f"错误: {e}")
finally:
# 清理资源
sensor.stop()
Display.deinit()
MediaManager.deinit()
del ai2d_output_tensor
nn.shrink_memory_pool()
print("资源已释放")
if __name__ == "__main__":
main()
将两个代码合成到一起,保证核心功能不变