import sensor
import time
import random
import math
# 全局状态变量
state = 0 # 0: 等待启动, 1: 第一轮测量, 2: 第二轮测量, 3: 编号输入测量, 4: 角度测量
remaining_targets = [1, 2, 3, 4] # 剩余目标物编号
current_target = None # 当前目标物
指定编号 = 0 # 用户输入的指定编号
# 设置VGA画面,并裁剪中间的画面
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.VGA)
sensor.set_windowing((200,240))
sensor.skip_frames(time=2000)
clock = time.clock() # Tracks FPS.
CENTER_X = 200//2
CENTER_Y = 240//2
# 边框的真实长度,单位mm
FRAME_WIDTH_MM = 176
# 校准的数据
# 例如: 当距离是1400mm时,边框宽度为82像素
# DISTANCE_MM_1 = 1100
# FRAME_WIDTH_PIXEL_1 = 104
DISTANCE_MM_2 = 1400
FRAME_WIDTH_PIXEL_2 = 82
# DISTANCE_MM_3 = 1800
# FRAME_WIDTH_PIXEL_3 = 64
# 目标物数据(假设)
目标物数据 = {
1: {"name": "目标物1", "color": (0, 150)},
2: {"name": "目标物2", "color": (0, 150)},
3: {"name": "目标物3", "color": (0, 150)},
4: {"name": "目标物4", "color": (0, 150)}
}
# 数字模板(简化版,实际应用中可能需要更复杂的模板匹配)
数字模板 = {
1: "1",
2: "2",
3: "3",
4: "4"
}
def find_center_min_blob(blobs):
# 找中间最小的色块
blob = None
min_area = 100000
for b in blobs:
if abs(b.cx()-CENTER_X)+ abs(b.cy()-CENTER_Y) > 50:
continue
if b.area() > min_area:
continue
blob = b
min_area = b.area()
return blob
def find_center_max_blob(blobs):
# 找中间最大的色块
blob = None
max_area = 0
for b in blobs:
if abs(b.cx()-CENTER_X)+ abs(b.cy()-CENTER_Y) > 50:
continue
if b.area() < max_area:
continue
blob = b
max_area = b.area()
return blob
def find_min_square(blobs):
# 找最小面积的正方形
min_square = None
min_area = float('inf') # 初始化为无穷大
# 调试信息:显示找到的色块数量
print(f"找到的色块数量: {len(blobs)}")
for b in blobs:
# 对于黑色正方形,降低面积过滤阈值
if b.area() < 5: # 进一步降低最小面积阈值
continue
# 假设正方形的宽高比接近1
aspect_ratio = max(b.w(), b.h()) / min(b.w(), b.h()) if min(b.w(), b.h()) > 0 else 0
# 对于小正方形,宽高比判断可以更宽松
if aspect_ratio > 1.3: # 稍微放宽宽高比限制
continue
if b.area() < min_area:
min_area = b.area()
min_square = b
print(f"临时最小正方形: 面积={b.area()}, 宽={b.w()}, 高={b.h()}, 宽高比={aspect_ratio:.2f}")
# 调试信息
if min_square:
print(f"最终最小正方形: 面积={min_square.area()}, 宽={min_square.w()}, 高={min_square.h()}")
else:
print("未找到符合条件的正方形")
return min_square
def recognize_number(img, roi):
# 识别数字(简化版)
# 实际应用中可能需要OCR或模板匹配
# 这里返回一个随机数作为示例
return random.randint(1, 4)
def calculate_angle(blob):
# 计算物体与轴线的夹角
# 假设通过宽高比来估算角度
aspect_ratio = blob.w() / blob.h() if blob.h() > 0 else 1
angle = math.atan(aspect_ratio) * 180 / math.pi
return min(max(angle, 30), 60) # 限制在30-60度之间
def start_measurement():
global state, current_target, remaining_targets
if state == 0:
# 第一轮测量:随机取一个目标物
if remaining_targets:
current_target = random.choice(remaining_targets)
remaining_targets.remove(current_target)
state = 1
print(f"第一轮测量:已选择目标物 {current_target}")
else:
print("没有可用目标物")
elif state == 1:
# 第二轮测量:从剩余目标物中再随机取一个
if remaining_targets:
current_target = random.choice(remaining_targets)
remaining_targets.remove(current_target)
state = 2
print(f"第二轮测量:已选择目标物 {current_target}")
else:
print("没有可用目标物")
elif state == 2:
# 第三轮测量:等待输入编号
state = 3
print("请输入要测量的正方形编号(1-4):")
elif state == 3:
# 第三轮测量:等待输入编号后的执行
if 指定编号 in 目标物数据:
current_target = 指定编号
state = 4
print(f"第三轮测量:已选择目标物 {current_target}")
else:
print("无效的编号,请重新输入")
elif state == 4:
# 第四轮测量:角度测量准备
state = 5
print("第四轮测量:准备角度测量")
elif state == 5:
# 第四轮测量:角度测量
state = 0
print("第四轮测量:角度测量完成")
# 主循环
while True:
clock.tick()
img = sensor.snapshot()
# 显示状态信息
img.draw_string(10, 10, f"状态: {state}", color=(255, 0, 0))
if current_target:
img.draw_string(10, 25, f"当前目标: {current_target}", color=(255, 0, 0))
img.draw_string(10, 40, "按任意键启动测量", color=(255, 0, 0))
# 检测按键(假设通过串口或其他方式输入)
# 这里简化为每5秒自动启动,实际应用中需替换为真实的输入检测
# if 检测到按键:
# start_measurement()
# 模拟按键输入(用于测试)
if time.time() % 5 < 0.1 and state == 0:
start_measurement()
# 找白色色块,黑色边框内部
frames = img.find_blobs([(150,256)])
frame_blob = find_center_min_blob(frames)
if not frame_blob:
print("NO FRAME")
continue
# 计算距离
distance = DISTANCE_MM_2*FRAME_WIDTH_PIXEL_2/frame_blob.w()
# 缩小roi,避免黑框的黑边
frame_roi = (frame_blob.x()+5, frame_blob.y()+5, frame_blob.w()-10, frame_blob.h()-10)
if frame_roi[2] <= 0 or frame_roi[3] <= 0:
print("ROI ERROR")
continue
# print(frame_roi)
# 找黑色色块,目标物体
objs = img.find_blobs([(0,150)], roi=frame_roi)
obj_blob = find_center_max_blob(objs)
if not obj_blob:
print("NO OBJS")
continue
# 根据状态执行不同的测量任务
if state == 1 or state == 2:
# 任务1和2:找最小面积正方形
# 调整色块检测参数,针对黑色正方形优化
# (0, 100) 更适合检测黑色
squares = img.find_blobs([(0, 100)], roi=frame_roi, pixels_threshold=2, area_threshold=2)
min_square = find_min_square(squares)
if min_square:
# 计算正方形的x(假设x为宽度)
square_x_mm = min_square.w()/frame_blob.w()*FRAME_WIDTH_MM
print(f"距离D: {distance:.2f}mm, 最小正方形x: {square_x_mm:.2f}mm")
img.draw_string(10, 60, f"D: {distance:.2f}mm", color=(255, 0, 0))
img.draw_string(10, 75, f"最小正方形x: {square_x_mm:.2f}mm", color=(255, 0, 0))
img.draw_rectangle(min_square.rect(), color=(0, 255, 0))
else:
# 如果没找到最小正方形,尝试极低阈值
squares = img.find_blobs([(0, 100)], roi=frame_roi, pixels_threshold=1, area_threshold=1)
min_square = find_min_square(squares)
if min_square:
square_x_mm = min_square.w()/frame_blob.w()*FRAME_WIDTH_MM
print(f"极低阈值下找到: 距离D: {distance:.2f}mm, 最小正方形x: {square_x_mm:.2f}mm")
img.draw_string(10, 60, f"D: {distance:.2f}mm", color=(255, 0, 0))
img.draw_string(10, 75, f"最小正方形x: {square_x_mm:.2f}mm", color=(255, 0, 0))
img.draw_rectangle(min_square.rect(), color=(0, 255, 0))
else:
print("未找到任何正方形色块")
elif state == 4:
# 任务3:指定编号正方形
# 使用优化的黑色正方形检测参数
squares = img.find_blobs([(0, 100)], roi=frame_roi, pixels_threshold=2, area_threshold=2)
# 找最小正方形
min_square = find_min_square(squares)
if min_square:
# 识别数字
number = recognize_number(img, min_square.rect())
print(f"识别到的编号: {number}")
if number == 指定编号:
# 计算指定编号正方形的x
square_x_mm = min_square.w()/frame_blob.w()*FRAME_WIDTH_MM
print(f"距离D: {distance:.2f}mm, 编号{指定编号}正方形x: {square_x_mm:.2f}mm")
img.draw_string(10, 60, f"D: {distance:.2f}mm", color=(255, 0, 0))
img.draw_string(10, 75, f"编号{指定编号}正方形x: {square_x_mm:.2f}mm", color=(255, 0, 0))
else:
print(f"识别到的编号{number}与指定编号{指定编号}不匹配")
else:
print("未找到正方形色块,无法识别编号")
elif state == 5:
# 任务4:角度测量
# 先找到最小正方形
squares = img.find_blobs([(0, 100)], roi=frame_roi, pixels_threshold=2, area_threshold=2)
min_square = find_min_square(squares)
if min_square:
angle = calculate_angle(min_square)
# 计算倾斜状态下的正方形x
square_x_mm = min_square.w()/frame_blob.w()*FRAME_WIDTH_MM / math.cos(math.radians(angle))
print(f"角度θ: {angle:.2f}度, 正方形x: {square_x_mm:.2f}mm")
img.draw_string(10, 60, f"角度θ: {angle:.2f}度", color=(255, 0, 0))
img.draw_string(10, 75, f"正方形x: {square_x_mm:.2f}mm", color=(255, 0, 0))
else:
print("未找到正方形色块,无法进行角度测量")
# 计算物体边长(原有功能)
obj_w_mm = obj_blob.w()/frame_blob.w()*FRAME_WIDTH_MM
# 原有形状识别功能
# print(frame_blob.w())
# print(obj_blob.density())
# if 0.9 < obj_blob.density() :
# print("矩形")
# elif 0.6 < obj_blob.density():
# print("圆形")
# elif 0.4 < obj_blob.density():
# print("三角形形")
# else:
# print("无法识别到形状")
# 绘制边框和目标
img.draw_rectangle(frame_blob.rect())
img.draw_rectangle(obj_blob.rect())
# 检测用户输入(假设通过串口接收)
# 这里简化处理,实际应用中需根据硬件情况实现
# 如果在状态3,接收用户输入的编号
if state == 3:
# 模拟用户输入(实际应用中替换为真实输入检测)
# 这里每2秒自动输入一个随机编号
if time.time() % 2 < 0.1:
指定编号 = random.randint(1, 4)
print(f"用户输入编号: {指定编号}")
start_measurement()
解释一下各个代码
最新发布