@uzbd 在特定于OPENMV Cam库中未找到返回的Homography矩阵相关信息,Homography矩阵包含什么参数,如需构建Homography矩阵该怎么构建?
an2l
@an2l
an2l 发布的帖子
-
RE: 利用AprilTag标记追踪功能通过标签实际尺寸与像素宽度比例测量移动距离,为什么误差时小时大,如何减小
-
RE: 利用AprilTag标记追踪功能通过标签实际尺寸与像素宽度比例测量移动距离,为什么误差时小时大,如何减小
@uzbd 使用标签的像素高度使用是否也会有随角度偏移出现梯形导致像素高度失真的现象呢?
-
RE: 利用AprilTag标记追踪功能通过标签实际尺寸与像素宽度比例测量移动距离,为什么误差时小时大,如何减小
1.透视畸变用畸变镜头或畸变矫正算法改善作用大吗?程序中已使用畸变矫正
2.标签尺寸与像素宽度之间是怎么样的关系?
3.以尝试将标签边沿黑色加深,可以减小像素宽度的误差 -
利用AprilTag3D标记追踪功能测量标签移动距离时如何减小计算量?
可以通过截取两帧或多帧图像,识别不同帧标的签位置计算而不是实时识别标签位置,H7 Plus可以实现吗?如何实现?
-
利用AprilTag标记追踪功能通过标签实际尺寸与像素宽度比例测量移动距离,为什么误差时小时大,如何减小
import sensor, image, time, math
初始化摄像头
sensor.reset() # 复位摄像头硬件
sensor.set_pixformat(sensor.RGB565) # 设置像素格式为RGB565
sensor.set_framesize(sensor.VGA) # 设置分辨率640x480
sensor.skip_frames(time=500) # 等待摄像头稳定(0.5秒)
sensor.set_auto_gain(False) # 关闭自动增益(防止图像过曝)
sensor.set_auto_whitebal(False) # 关闭自动白平衡相机内参设置(需根据实际镜头校准)
f_x = (2.8 / 3.6736) * 640 # X轴焦距:(焦距mm / 传感器宽度mm)*像素宽度
f_y = (2.8 / 2.7384) * 480 # Y轴焦距:(焦距mm / 传感器高度mm)*像素高度
c_x = 640 * 0.5 # 图像中心X坐标
c_y = 480 * 0.5 # 图像中心Y坐标系统状态变量
SETTING_BASE = 0
MEASURING = 1
system_state = SETTING_BASE # 初始状态为设置基准位置位置信息
base_x = None # 基准位置平移量(x)
base_y = None # 基准位置平移量(y)
base_w = None # 基准位置标签宽度filtered_w = None # 滤波后的标签宽度
filtered_position = None # 滤波后的当前位置
stroke_mm = 0 # 计算出的行程值(毫米)
base_samples = [] # 基准位置采样列表
current_samples = [] # 当前位置采样列表
INITIAL_SAMPLES = 10 # 基准位置采样次数
CURRENT_SAMPLES = 10 # 当前位置采样次数AprilTag参数
TAG_SIZE_MM = 29.5 # AprilTag实际物理尺寸(毫米)
计算实际距离的函数
def calculate_real_distance(pixel_distance, k_value):
"""
根据像素距离和标签宽度计算实际距离
pixel_distance: 像素距离
w: 标签宽度(像素)
返回: 实际距离(毫米)
"""
# 计算比例系数 K = 标签实际尺寸 / 标签像素尺寸
return pixel_distance * k_value计算二维空间欧氏距离
def euclidean_distance(pos1, pos2):
"""计算两个像素点之间的欧氏距离"""
if pos1 is None or pos2 is None:
return 0.0
dx = pos1[0] - pos2[0]
dy = pos1[1] - pos2[1]return math.sqrt((dx*dx + dy*dy))
卡尔曼滤波器类
class KalmanFilter:
def init(self, initial_value, process_variance=0.5, measurement_variance=0.5):
"""
一维卡尔曼滤波器
:param initial_value: 初始估计值
:param process_variance: 过程噪声方差 (Q)
:param measurement_variance: 测量噪声方差 (R)
"""
self.state_estimate = initial_value
self.estimate_variance = 5 # 初始估计方差 (P)
self.process_variance = process_variance
self.measurement_variance = measurement_variancedef update(self, measurement): """ 更新卡尔曼滤波器 :param measurement: 当前测量值 :return: 滤波后的估计值 """ # 预测步骤 prior_estimate = self.state_estimate prior_variance = self.estimate_variance + self.process_variance # 更新步骤 kalman_gain = prior_variance / (prior_variance + self.measurement_variance) self.state_estimate = prior_estimate + kalman_gain * (measurement - prior_estimate) self.estimate_variance = (1 - kalman_gain) * prior_variance return self.state_estimate
创建w值卡尔曼滤波器实例
w_kalman = KalmanFilter(initial_value=10000.0) # 初始值设为50像素
计算K值函数
def calculate_k_value(w):
"""根据标签宽度计算比例系数K"""
return TAG_SIZE_MM / w if w > 0 else 1.0加权平均位置计算
def weighted_average_position(positions):
"""使用加权平均计算位置(近期样本权重更高)"""
if not positions:
return Nonen = len(positions) total_weight = 0 weighted_x = 0 weighted_y = 0 # 使用线性权重:最近样本权重最高 for i, pos in enumerate(positions): # 权重 = (样本索引 + 1) 最近样本权重最高 weight = i + 1 total_weight += weight weighted_x += pos[0] * weight weighted_y += pos[1] * weight return ( weighted_x / total_weight, weighted_y / total_weight, )
clock = time.clock()
主循环
while(True):
clock.tick()
img = sensor.snapshot().lens_corr(1.6) # 捕获一帧图像
#img.draw_rectangle([70,160,50,50], color=(255, 0, 0))
# 检测AprilTag标签
tags = img.find_apriltags(fx=f_x, fy=f_y, cx=c_x, cy=c_y,
families=image.TAG36H11, tag_size=TAG_SIZE_MM)if tags: # 如果检测到标签 tag = tags[0] # 假设只检测一个标签 # 在图像上绘制标签轮廓 img.draw_rectangle(tag.rect, color=(255, 0, 0)) # 在图像上绘制标签中心十字 img.draw_cross(tag.cx, tag.cy, color=(0, 255, 0)) img.draw_string(0, 400, "ID:%d" % tag.id, color=(255, 0, 0)) # 获取标签坐标位置 x, y, w, h= tag.rect # 使用卡尔曼滤波处理w值 filtered_w = w_kalman.update(w) # 计算当前比例系数K k_value = calculate_k_value(filtered_w) # 记录当前二维空间位置 current_position = (x, y) if system_state == SETTING_BASE: # 设置基准位置阶段 base_samples.append((x,y)) # 存储平移量 #w_samples.append(w) # 存储宽度 # 显示设置进度 progress = len(base_samples) / INITIAL_SAMPLES * 100 img.draw_string(0, 10, "Setting base:%d%%" % progress, color=(255, 255, 0)) if len(base_samples) >= INITIAL_SAMPLES: # 计算加权平均平移量 avg_x = sum(sample[0] for sample in base_samples) / len(base_samples) avg_y = sum(sample[1] for sample in base_samples) / len(base_samples) # 存储基准位置和宽度 base_x, base_y = avg_x, avg_y # 计算基准位置 base_position = (avg_x, avg_y) print("Base position set: (%.1f, %.1f)mm" % base_position) print("Base translation: (%.2f, %.2f)" % (base_x, base_y)) print("Base width: %.1f pixels" % filtered_w) # 切换到测量状态 system_state = MEASURING base_samples = [] # 清空样本 current_samples = [] # 初始化当前位置采样列表 elif system_state == MEASURING: # 测量阶段 # 将当前位置添加到采样列表 current_samples.append((x, y)) # 保持采样列表长度不超过设定值 if len(current_samples) > CURRENT_SAMPLES: current_samples.pop(0) # 移除最旧的样本 # 计算加权平均平移量 if len(current_samples) >= 0: # 至少有0个样本 avg_x = sum(sample[0] for sample in current_samples) / len(current_samples) avg_y = sum(sample[1] for sample in current_samples) / len(current_samples) # 计算滤波后的位置 filtered_position = (avg_x, avg_y) # 计算基准位置(使用当前比例系数) base_position = (base_x, base_y) # 计算像素距离 pixel_distance = euclidean_distance((avg_x, avg_y), (base_x, base_y)) # 计算实际距离 stroke_mm = calculate_real_distance(pixel_distance, k_value) # 显示行程信息 if filtered_position: text = "Distance:%.1fmm" % stroke_mm img.draw_string(0, 430, text, color=(0, 255, 0)) # 显示当前位置 pos_text = "Pos:(%.1f,%.1f)mm" % filtered_position img.draw_string(0, 450, pos_text, color=(255, 255, 0)) # 显示标签宽度信息 w_text = "Width:%.1f (K=%.4f)" % (filtered_w, k_value) img.draw_string(0, 470, w_text, color=(255, 255, 0)) # 显示采样信息 sample_text = "Samples:%d/%d" % (len(current_samples), CURRENT_SAMPLES) img.draw_string(0, 420, sample_text, color=(255, 255, 0)) # 显示卡尔曼增益信息 kalman_gain = w_kalman.estimate_variance / (w_kalman.estimate_variance + w_kalman.measurement_variance) gain_text = "Kalman Gain: %.2f" % kalman_gain img.draw_string(0, 230, gain_text, color=(150, 150, 255)) print("%s | W:%.1fpx | K:%.4f | Gain:%.2f" % ( text, filtered_w, k_value, kalman_gain)) # 打印调试信息 print("%s | Filtered Pos: (%.1f,%.1f)mm" % ( text, filtered_position[0], filtered_position[1])) else: # 未检测到标签时的处理 if system_state == SETTING_BASE: img.draw_string(0, 10, "Place piston at base position", color=(255, 0, 0)) elif system_state == MEASURING: if filtered_position: img.draw_string(0, 430, "Distance:%.1fmm" % stroke_mm, color=(0, 255, 0)) img.draw_string(0, 420, "Tag lost!", color=(255, 0, 0)) # 显示系统状态 states = ["SETTING_BASE", "MEASURING"] img.draw_string(0, 440, "State:%s" % states[system_state], color=(255, 255, 255)) # 显示实时帧率 img.draw_string(0, 410, "FPS:%.1f" % clock.fps(), color=(255, 255, 255)) print(clock.fps()) # 显示基准位置 if system_state == MEASURING: base_text = "Base:(%.1f,%.1f)mm" % base_position img.draw_string(0, 460, base_text, color=(255, 255, 0))