Merge branch 'main-v2' of ssh://120.27.199.238:222/Havoc420mac/mi-task into main-v2

This commit is contained in:
hav 2025-08-21 18:21:56 +08:00
commit 93dd2d9089
10 changed files with 274 additions and 85 deletions

View File

@ -116,4 +116,91 @@ def run_task_1(ctrl, msg, time_sleep=5000):
# add
go_straight(ctrl, msg, distance=0.3, observe=observe)
# section
section('任务1-790度转弯', "旋转")
radius = res['radius'] * 2 + 0.1
info(f"任务1-7: 转弯半径: {radius}", "信息")
turn_success, res = arc_turn_around_hori_line(
ctrl=ctrl,
msg=msg,
radius=radius,
angle_deg=85 if direction else -85,
#
pass_align=True,
observe=observe,
no_end_reset=True,
)
section('任务1-8直线移动', "移动")
move_to_hori_line(ctrl, msg, target_distance=0.3, observe=observe)
section('任务1-990度旋转', "旋转")
turn_degree_v2(ctrl, msg, degree=0, absolute=True, precision=True)
section('任务1-10: y校准准备 task-2', "移动")
# TODO
success("任务1完成", "完成")
def run_task_1_back(ctrl, msg, time_sleep=5000):
section('任务1-11: 返回', "移动")
go_straight(ctrl, msg, distance=0.2, observe=observe)
turn_degree_v2(ctrl, msg, -90, absolute=True) # 不确定 odo 效果如何;
section('任务1-11: 直线移动', "移动")
move_to_hori_line(ctrl, msg, target_distance=0.2, observe=observe)
section('任务1-12: 180度旋转', "旋转")
turn_success, res = arc_turn_around_hori_line(
ctrl=ctrl,
msg=msg,
angle_deg=170 if direction else -170,
target_distance=0.6,
min_radius=0.3,
max_radius=0.4,
pass_align=True,
observe=observe,
no_end_reset=True,
)
turn_degree_v2(ctrl, msg, degree=90, absolute=True)
section('任务1-13: 直线移动', "移动")
move_distance = 0.5
go_straight(ctrl, msg, distance=move_distance, observe=observe)
section('任务1-14: 模拟装货', "停止")
info('机器人躺下,模拟装货过程', "信息")
start_time = time.time()
ctrl.base_msg.lie_down(wait_time=time_sleep)
elapsed = time.time() - start_time
timing("装货过程", elapsed)
section('任务1-15: 站起来', "移动")
ctrl.base_msg.stand_up()
section('任务1-16: 返回', "移动")
go_straight(ctrl, msg, distance=-(move_distance + res['radius']), observe=observe)
turn_degree_v2(ctrl, msg, degree=179, absolute=True)
section('任务1-17: 90度转弯', "旋转")
turn_success, res = arc_turn_around_hori_line(
ctrl=ctrl,
msg=msg,
angle_deg=-85 if direction else 85,
radius=res['radius'] * 2,
pass_align=True,
observe=observe,
)
section('任务1-18: 直线移动', "移动")
move_to_hori_line(ctrl, msg, target_distance=0.4, observe=observe)
section('任务1-19: 90度旋转', "旋转")
turn_degree_v2(ctrl, msg, degree=0, absolute=True)
go_straight(ctrl, msg, distance=-1.3, observe=observe)
# go_to_xy(ctrl, msg, target_x=-0.2, target_y=0, observe=observe) # TEST
success("任务1-back完成", "完成")

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

View File

@ -1,3 +1,2 @@
opencv-python>=4.5.0
numpy>=1.19.0
pathlib
opencv-python
numpy

View File

@ -1,89 +1,149 @@
import cv2
import numpy as np
import os
from pathlib import Path
def preprocess_image(image):
"""
预处理图像转换为HSV色彩空间检测白色区域
预处理图像转换为HSV色彩空间提取V通道明度通道中的低亮度区域
"""
# 转换为HSV色彩空间
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义白色的HSV范围 - 放宽范围
# 白色在HSV中饱和度低明度高
# 原来的范围lower_white = np.array([0, 0, 200]), upper_white = np.array([180, 30, 255])
# 放宽后的范围:
lower_white = np.array([0, 0, 150]) # 降低明度下限从200降到150
upper_white = np.array([180, 60, 255]) # 提高饱和度上限从30提高到60
# 提取V通道明度通道
v_channel = hsv[:, :, 2]
# 创建白色掩码
white_mask = cv2.inRange(hsv, lower_white, upper_white)
# 对V通道进行二值化提取低亮度区域蓝色部分
# 使用较低的阈值来提取暗色区域
_, binary = cv2.threshold(v_channel, 120, 255, cv2.THRESH_BINARY_INV)
# 形态学操作:开运算去除小噪点,闭运算填充小孔
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
cleaned = cv2.morphologyEx(white_mask, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
cleaned = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, kernel)
return cleaned
return cleaned, v_channel
def find_white_rectangles(binary_image):
def find_text_regions(binary_image):
"""
查找白色矩形区域
查找可能的文字区域
"""
contours, _ = cv2.findContours(
binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
# 筛选合适的矩形轮廓
valid_rectangles = []
# 筛选合适的文字区域轮廓
valid_text_regions = []
for contour in contours:
area = cv2.contourArea(contour)
if area > 200: # 过滤太小的区域从500降低到200
if area > 100: # 过滤太小的区域
# 计算轮廓的边界矩形
x, y, w, h = cv2.boundingRect(contour)
# 计算轮廓的近似多边形
epsilon = 0.02 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
# 计算宽高比
aspect_ratio = w / h
# 检查是否为四边形(矩形)
if len(approx) == 4:
# 计算宽高比
aspect_ratio = w / h
# 矩形应该有合理的宽高比(不是太细长)
if 0.3 < aspect_ratio < 3.0:
valid_rectangles.append((contour, (x, y, w, h), approx))
# 文字区域通常有合理的宽高比
if 0.1 < aspect_ratio < 10.0:
valid_text_regions.append((contour, (x, y, w, h)))
return valid_rectangles
return valid_text_regions
def analyze_white_region(roi, original_roi):
def analyze_text_region(roi, original_roi):
"""
分析白色区域的特征
分析文字区域的特征
"""
# 计算色像素比例
# 计算色像素比例
total_pixels = roi.shape[0] * roi.shape[1]
white_pixels = np.sum(roi == 255)
white_ratio = white_pixels / total_pixels
black_pixels = np.sum(roi == 255)
black_ratio = black_pixels / total_pixels
# 计算区域的形状特征
height, width = roi.shape
aspect_ratio = width / height
# 计算边缘强度(白色区域应该有清晰的边缘)
# 计算边缘强度
edges = cv2.Canny(original_roi, 50, 150)
edge_density = np.sum(edges > 0) / total_pixels
return {
'white_ratio': white_ratio,
'black_ratio': black_ratio,
'aspect_ratio': aspect_ratio,
'edge_density': edge_density,
'area': total_pixels
}
def detect_white_rectangles_in_image(image_path):
def classify_digit_1_or_2(roi):
"""
检测图片中的白色矩形区域
使用OpenCV基本方法判断是数字1还是2
"""
# 调整ROI大小到统一尺寸进行分析
roi_resized = cv2.resize(roi, (20, 20))
# 计算像素密度特征
total_pixels = roi_resized.shape[0] * roi_resized.shape[1]
black_pixels = np.sum(roi_resized == 255)
density = black_pixels / total_pixels
# 计算宽高比
aspect_ratio = roi_resized.shape[1] / roi_resized.shape[0]
# 计算水平投影(每行的黑色像素数)
horizontal_projection = np.sum(roi_resized == 255, axis=1)
# 计算垂直投影(每列的黑色像素数)
vertical_projection = np.sum(roi_resized == 255, axis=0)
# 计算中心区域的像素分布
center_region = roi_resized[5:15, 5:15]
center_density = np.sum(center_region == 255) / (10 * 10)
# 计算垂直投影的方差数字1方差较小数字2方差较大
vertical_variance = np.var(vertical_projection)
# 计算水平投影的方差
horizontal_variance = np.var(horizontal_projection)
# 基于多个特征的综合判断
digit1_score = 0
digit2_score = 0
# 数字1的判断条件
if vertical_variance < 15: # 垂直投影方差小
digit1_score += 2
if center_density < 0.3: # 中心区域密度较低
digit1_score += 1
if density < 0.4: # 整体密度较低
digit1_score += 1
if aspect_ratio < 0.8: # 数字1通常较细
digit1_score += 1
# 数字2的判断条件
if vertical_variance > 15: # 垂直投影方差大
digit2_score += 2
if center_density > 0.3: # 中心区域密度较高
digit2_score += 1
if density > 0.4: # 整体密度较高
digit2_score += 1
if horizontal_variance > 8: # 水平投影方差大
digit2_score += 1
if aspect_ratio > 0.8: # 数字2通常较宽
digit2_score += 1
# 返回得分更高的数字
if digit1_score > digit2_score:
return 1
elif digit2_score > digit1_score:
return 2
else:
# 如果得分相同,使用更复杂的判断
if vertical_variance < 12:
return 1
else:
return 2
def detect_text_in_image(image_path, show_process=True):
"""
检测图片中的文字区域
"""
# 读取图像
image = cv2.imread(image_path)
@ -92,87 +152,130 @@ def detect_white_rectangles_in_image(image_path):
return []
# 预处理
white_mask = preprocess_image(image)
binary, v_channel = preprocess_image(image)
# 查找白色矩形
valid_rectangles = find_white_rectangles(white_mask)
# 查找文字区域
valid_text_regions = find_text_regions(binary)
results = []
for contour, (x, y, w, h), approx in valid_rectangles:
for contour, (x, y, w, h) in valid_text_regions:
# 提取ROI
roi_mask = white_mask[y:y+h, x:x+w]
roi_binary = binary[y:y+h, x:x+w]
roi_original = image[y:y+h, x:x+w]
# 分析特征
features = analyze_white_region(roi_mask, roi_original)
features = analyze_text_region(roi_binary, roi_original)
# 判断是否为有效的白色矩形
is_valid_white_rectangle = (
features['white_ratio'] > 0.4 and # 白色像素比例要求降低从0.6降到0.4
features['edge_density'] > 0.005 # 边缘密度要求降低从0.01降到0.005
# 判断是否为有效的低亮度区域
is_valid_text_region = (
features['black_ratio'] > 0.05 and # 低亮度像素比例要求降低
features['edge_density'] > 0.003 # 边缘密度要求降低
)
if is_valid_white_rectangle:
if is_valid_text_region:
# 使用OpenCV方法识别数字1或2
predicted_digit = classify_digit_1_or_2(roi_binary)
results.append({
'type': 'white_rectangle',
'type': 'digit_region',
'position': (x, y, w, h),
'digit': predicted_digit,
'features': features,
'confidence': 'high' if features['white_ratio'] > 0.8 else 'medium'
'confidence': 'high' if features['black_ratio'] > 0.3 else 'medium'
})
# 在图像上绘制结果
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(image, f"白色矩形", (x, y - 10),
cv2.putText(image, f"数字{predicted_digit}", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
# 如果需要显示中间过程
if show_process:
# 创建过程图像
process_images = []
# 1. 原始图片
process_images.append(("原始图片", image.copy()))
# 2. HSV-V通道明度通道
v_display = cv2.applyColorMap(v_channel, cv2.COLORMAP_JET)
process_images.append(("HSV-V通道", v_display))
# 3. 二值化后的低亮度区域
process_images.append(("低亮度区域掩码", binary))
# 4. 轮廓检测结果
contour_image = image.copy()
for contour, (x, y, w, h) in valid_text_regions:
cv2.rectangle(contour_image, (x, y), (x + w, y + h), (0, 0, 255), 2)
process_images.append(("轮廓检测", contour_image))
# 5. 最终结果
process_images.append(("最终结果", image))
# 保存过程图像
img_dir = Path(image_path).parent
base_name = Path(image_path).stem
for i, (title, img) in enumerate(process_images):
if len(img.shape) == 2: # 如果是灰度图转换为BGR
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# 绘制轮廓点
cv2.drawContours(image, [approx], -1, (255, 0, 0), 2)
output_path = img_dir / f"{base_name}_process_{i+1}_{title}.jpg"
cv2.imwrite(str(output_path), img)
print(f"过程图像已保存: {output_path}")
return image, results
def main():
"""
主函数测试白色矩形检测
主函数测试文字区域检测
"""
# 图片路径
img_dir = Path("imgs")
img1_path = img_dir / "1.jpg"
img2_path = img_dir / "2.jpg"
print("开始检测图片中的白色矩形区域...")
print("开始检测图片中的文字区域...")
print("=" * 50)
# 检测第一张图片
if img1_path.exists():
print(f"\n检测图片: {img1_path}")
result_img1, results1 = detect_white_rectangles_in_image(str(img1_path))
print("检测过程包括以下步骤:")
print("1. 原始图片")
print("2. HSV色彩空间转换")
print("3. 明度通道提取")
print("4. 二值化(低亮度区域)")
print("5. 轮廓检测")
print("6. 特征分析")
print("7. 数字识别")
print("8. 最终结果")
print("-" * 30)
print("检测结果:")
for result in results1:
print(f" 类型: {result['type']}, 位置: {result['position']}, 置信度: {result['confidence']}")
print(f" 特征: 白色比例={result['features']['white_ratio']:.2f}, "
f"宽高比={result['features']['aspect_ratio']:.2f}")
result_img1, results1 = detect_text_in_image(str(img1_path), show_process=True)
print("\n检测结果:")
if results1:
for i, result in enumerate(results1):
print(f" 文字区域 {i+1}:")
print(f" 位置: {result['position']}")
print(f" 识别数字: {result['digit']}")
print(f" 置信度: {result['confidence']}")
print(f" 黑色比例: {result['features']['black_ratio']:.2f}")
print(f" 宽高比: {result['features']['aspect_ratio']:.2f}")
print(f" 边缘密度: {result['features']['edge_density']:.4f}")
print(f" 面积: {result['features']['area']}")
else:
print(" 未检测到文字区域")
# 保存结果图片
output_path1 = img_dir / "result_1.jpg"
cv2.imwrite(str(output_path1), result_img1)
print(f"结果图片已保存到: {output_path1}")
# 检测第二张图片
if img2_path.exists():
print(f"\n检测图片: {img2_path}")
result_img2, results2 = detect_white_rectangles_in_image(str(img2_path))
print("检测结果:")
for result in results2:
print(f" 类型: {result['type']}, 位置: {result['position']}, 置信度: {result['confidence']}")
print(f" 特征: 白色比例={result['features']['white_ratio']:.2f}, "
f"宽高比={result['features']['aspect_ratio']:.2f}")
# 保存结果图片
output_path2 = img_dir / "result_2.jpg"
cv2.imwrite(str(output_path2), result_img2)
print(f"结果图片已保存到: {output_path2}")
print(f"\n最终结果图片已保存到: {output_path1}")
print("中间过程图像也已保存到imgs目录")
else:
print(f"图片文件不存在: {img1_path}")
print("\n检测完成!")