2,856
社区成员




目录
测试手机型号:Redmi K60 Pro
处理器:第二代骁龙8移动--8gen2
运行内存:8.0GB ,LPDDR5X-8400,67.0 GB/s
摄像头:前置16MP+后置50MP+8MP+2MP
AI算力:NPU 48Tops INT8 && GPU 1536ALU x 2 x 680MHz = 2.089 TFLOPS
提示:任意手机均可以,性能越好的手机速度越快
APP:AidLux 2.0
系统环境:Ubuntu 20.04.3 LTS
提示:AidLux登录后代码运行更流畅,在代码运行时保持AidLux APP在前台运行,避免代码运行过程中被系统回收进程,另外屏幕保持常亮,一般息屏后一段时间,手机系统会进入休眠状态,如需长驻后台需要给APP权限。
这段代码实现了一个基于AidLite 框架的 3D 椅子检测应用,可通过摄像头实时识别并展示 3D 椅子的位置和姿态。以下是添加详细注释后的代码及功能分析:
这段代码是一个基于 AidLite 框架的 3D 椅子检测应用,主要功能包括:
模型结构:
使用的是单阶段 3D 检测模型,输出包括:
检测流程:
detect_peak
函数找到热图中的峰值点draw_box
函数在图像上绘制 3D 框,包括 8 个关键点和连接线性能优化:
aidlite.AccelerateType.TYPE_GPU
)摄像头适配:
这个应用可以实时检测场景中的椅子,并以 3D 方式展示其位置和姿态,适用于智能家居、机器人导航等场景。
import cv2
import time
from time import sleep
import subprocess
import sys
import numpy as np
import aidlite
import os
from scipy.ndimage.filters import maximum_filter
def get_cap_id():
"""
自动检测USB摄像头设备ID
返回可用摄像头的最小ID号,若未找到则返回None
"""
try:
# 通过系统命令查找所有USB视频设备
cmd = "ls -l /sys/class/video4linux | awk -F ' -> ' '/usb/{sub(/.*video/, \"\", $2); print $2}'"
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
output = result.stdout.strip().split()
# 转换所有捕获的编号为整数,找出最小值
video_numbers = list(map(int, output))
if video_numbers:
return min(video_numbers)
else:
return None
except Exception as e:
print(f"摄像头检测错误: {e}")
return None
def detect_peak(image, filter_size=5, order=0.5):
"""
检测热图中的峰值点(关键点)
参数:
image: 输入热图
filter_size: 最大值滤波核大小
order: 阈值比例(相对于最大值)
返回:
峰值点坐标
"""
# 使用最大值滤波找出局部最大值
local_max = maximum_filter(image, footprint=np.ones((filter_size, filter_size)), mode='constant')
detected_peaks = np.ma.array(image, mask=~(image == local_max))
# 过滤低于阈值的点
temp = np.ma.array(detected_peaks, mask=~(detected_peaks >= detected_peaks.max() * order))
peaks_index = np.where((temp.mask != True))
return peaks_index
def decode(hm, displacements, threshold=0.8):
"""
解码模型输出,提取3D关键点
参数:
hm: 热图(关键点置信度)
displacements: 偏移量场
threshold: 置信度阈值
返回:
检测到的物体列表,每个物体包含8个关键点坐标
"""
# 重塑输出张量形状
hm = hm.reshape(40, 30)
displacements = displacements.reshape(1, 40, 30, 16)
peaks = detect_peak(hm)
peakX = peaks[1]
peakY = peaks[0]
scaleX = hm.shape[1]
scaleY = hm.shape[0]
objs = []
# 遍历所有检测到的峰值点
for x, y in zip(peakX, peakY):
conf = hm[y, x]
if conf < threshold:
continue
# 提取每个关键点的偏移量,计算最终坐标
points = []
for i in range(8):
dx = displacements[0, y, x, i*2]
dy = displacements[0, y, x, i*2+1]
points.append((x/scaleX + dx, y/scaleY + dy))
objs.append(points)
return objs
def draw_box(image, pts):
"""
在图像上绘制3D框和关键点
参数:
image: 输入图像
pts: 8个关键点的归一化坐标
"""
scaleX = image.shape[1]
scaleY = image.shape[0]
# 定义3D框的连接线(边)
lines = [(0,1), (1,3), (0,2), (3,2), (1,5), (0,4), (2,6), (3,7), (5,7), (6,7), (6,4), (4,5)]
# 绘制连接线
for line in lines:
pt0 = pts[line[0]]
pt1 = pts[line[1]]
pt0 = (int(pt0[0]*scaleX), int(pt0[1]*scaleY))
pt1 = (int(pt1[0]*scaleX), int(pt1[1]*scaleY))
cv2.line(image, pt0, pt1, (255, 245, 0), 2)
# 绘制关键点
for i in range(8):
pt = pts[i]
pt = (int(pt[0]*scaleX), int(pt[1]*scaleY))
cv2.circle(image, pt, 3, (255, 245, 0), -1)
cv2.putText(image, str(i), pt, cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)
# --------------- 模型初始化部分 ---------------
# 模型路径和输入输出形状定义
model_path = 'models/object_detection_3d_chair_1stage.tflite'
inShape = [[1, 640, 480, 3]] # 输入张量形状: [批次, 高度, 宽度, 通道]
outShape = [[1, 40, 30, 1], [1, 40, 30, 16], [1, 160, 120, 4]] # 输出张量形状
# 创建AidLite模型实例并设置属性
model = aidlite.Model.create_instance(model_path)
if model is None:
print("模型创建失败!")
# 设置模型输入输出数据类型
model.set_model_properties(inShape, aidlite.DataType.TYPE_FLOAT32, outShape, aidlite.DataType.TYPE_FLOAT32)
# 配置推理参数
config = aidlite.Config.create_instance()
config.implement_type = aidlite.ImplementType.TYPE_FAST # 快速推理模式
config.framework_type = aidlite.FrameworkType.TYPE_TFLITE # TFLite框架
config.accelerate_type = aidlite.AccelerateType.TYPE_GPU # GPU加速
config.number_of_threads = 4 # 线程数
# 创建并初始化推理解释器
fast_interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
if fast_interpreter is None:
print("解释器创建失败!")
# 完成解释器初始化和模型加载
result = fast_interpreter.init()
if result != 0:
print("解释器初始化失败!")
result = fast_interpreter.load_model()
if result != 0:
print("模型加载失败!")
print("模型加载成功!")
# --------------- 摄像头设置部分 ---------------
aidlux_type = "basic" # AidLux设备类型
# 0-后置,1-前置
camId = 0
opened = False
# 尝试打开摄像头,失败时会重试
while not opened:
if aidlux_type == "basic":
cap = cv2.VideoCapture(camId, device='mipi') # 打开MIPI摄像头
else:
# 尝试检测USB摄像头
capId = get_cap_id()
print("USB摄像头ID: ", capId)
if capId is None:
print("未找到USB摄像头,使用默认MIPI摄像头")
cap = cv2.VideoCapture(1, device='mipi') # 打开前置MIPI摄像头
else:
camId = capId
cap = cv2.VideoCapture(camId)
cap.set(6, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G')) # 设置MJPG格式
if cap.isOpened():
opened = True
else:
print("摄像头打开失败,重试中...")
cap.release()
time.sleep(0.5)
# --------------- 主循环部分 ---------------
while True:
ret, img_ori = cap.read() # 读取一帧图像
if not ret:
continue
if img_ori is None:
continue
# 图像预处理
img = cv2.cvtColor(img_ori, cv2.COLOR_BGR2RGB) # BGR转RGB
img = cv2.resize(img, (480, 640)).astype(np.float32) # 调整大小并转换为浮点型
img = img / 128.0 - 1.0 # 归一化处理 [-1, 1]
img = img[None] # 添加批次维度
# 设置输入张量
result = fast_interpreter.set_input_tensor(0, img.data)
if result != 0:
print("设置输入张量失败")
# 记录推理开始时间
start_time = time.time()
# 执行推理
result = fast_interpreter.invoke()
if result != 0:
print("推理执行失败")
# 计算推理时间
gpuelapsed_ms = (time.time() - start_time) * 1000
print(f'推理耗时: {gpuelapsed_ms:.2f}ms')
# 获取模型输出
displacements = fast_interpreter.get_output_tensor(1) # 偏移量场
hm = fast_interpreter.get_output_tensor(0) # 热图(关键点置信度)
# 解码输出,提取3D关键点
objs = decode(hm, displacements, threshold=0.7)
# 在原图上绘制检测结果
for obj in objs:
draw_box(img_ori, obj)
# 显示结果图像
cv2.imshow("", img_ori)
# 按ESC键退出
key = cv2.waitKey(1)
if key == 27: # ESC键
break
# 释放资源
cap.release()
cv2.destroyAllWindows()