《计算机程序设计中ratio_abs函数的应用》

392 篇文章 ¥29.90 ¥99.00

《计算机程序设计中ratio_abs函数的应用》

C++11标准引入了ratio模板类,用来表示有理数。ratio_abs是ratio模板类中的一个成员函数,用来返回一个有理数的绝对值。

下面是一个使用ratio_abs函数的示例代码:

#include <iostream>
#include <ratio>

int main() {
    std::cout << "ratio_abs demonstration:" << std::endl;

    typedef std::ratio<-3, 2> R1;
    typedef std::ratio<5, -3> R2;
    typedef std::ratio<0> R3;

    std::cout << "std::ratio<-3, 2>: " << std::ratio_abs<R1>::num << '/' << std::ratio_abs<R1>::den << std::endl;
    std::cout << "std::ratio<5, -3>: " << std::ratio_abs<R2>::num << '/' << std::ratio_abs<R2>::den << std::endl;
    std::cout << "std::ratio<0>:
复杂几何的多球近似MATLAB类及多球模型的比较 MATLAB类Approxi提供了一个框架,用于使用具有迭代缩放的聚集球体模型来近似解剖体积模型,以适应目标体积和模型比较。专为骨科、生物力学和计算几何应用而开发。 MATLAB class for multi-sphere approximation of complex geometries and comparison of multi-sphere models 主要特点: 球体模型生成 1.多球体模型生成:与Sihaeri的聚集球体算法的接口 2.音量缩放 基于体素的球体模型和参考几何体的交集。 迭代缩放球体模型以匹配目标体积。 3.模型比较:不同模型体素占用率的频率分析(多个评分指标) 4.几何分析:原始曲面模型和球体模型之间的顶点到最近邻距离映射(带颜色编码结果)。 如何使用: 1.代码结构:Approxi类可以集成到相应的主脚本中。代码的关键部分被提取到单独的函数中以供重用。 2.导入:将STL(或网格)导入MATLAB,并确保所需的函数,如DEM clusteredSphere(populateSpheres)和inpolyhedron,已添加到MATLAB路径中 3.生成多球体模型:使用DEM clusteredSphere方法从输入网格创建多球体模型 4.运行体积交点:计算多球体模型和参考几何体之间的基于体素的交点,并调整多球体模型以匹配目标体积 5.比较和可视化模型:比较多个多球体模型的体素频率,并计算多球体模型与原始表面模型之间的距离,以进行2D/3D可视化 使用案例: 骨科和生物力学体积建模 复杂结构的多球模型形状近似 基于体素拟合度量的模型选择 基于距离的患者特定几何形状和近似值分析 优点: 复杂几何的多球体模型 可扩展模型(基于体素)-自动调整到目标体积 可视化就绪输出(距离图)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 智能车竞赛全自动最终版(修复未定义变量) 流程(严格顺序): 等待拆挡板 -> 发车计时(前轮过线)-> 巡线 + 避障(贯穿)-> 斑马线停 3s -> 变道 -> A/B 识别 -> 停车(黄线)-> 自动付费 -> 结束 摄像头索引 = 2(与你提供的一致) """ import os import time import datetime import cv2 import numpy as np import pigpio import onnxruntime from PIL import Image, ImageDraw, ImageFont import sys # ----------------------------- # 全局配置(严格沿用你提供的参数) # ----------------------------- CAM_INDEX = 2 W, H = 640, 480 FPS_TARGET = 20 DATA_SAVE_DIR = "/home/pi/smartcar_data" os.makedirs(DATA_SAVE_DIR, exist_ok=True) SAVE_INTERVAL = 30 # 每隔30秒拍照存数据 # 硬件(舵机/电机)参数 MOTOR_PIN = 13 NEUTRAL_PULSE = 1500 FORWARD_BASE = 1380 FORWARD_LOW = 1390 BACKWARD_PULSE = 1500 SERVO_PIN = 12 SERVO_MIN_ANGLE = 70 SERVO_MAX_ANGLE = 110 SERVO_MID_ANGLE = 90 SERVO_MIN_PULSE = 500 SERVO_MAX_PULSE = 2500 # PID 与控制参数 KP = 0.09 KD = 0.07 DEAD_ZONE = 5.0 TURN_DECAY = 0.85 MAX_TURN_DURATION = 8 TRACK_LOST_THRESH = 5 RECOVER_SPEED = FORWARD_LOW - 60 SINGLE_LINE_OFFSET = 80 # 白线 / Hough 参数 WHITE_THRESHOLD = 170 MIN_LINE_LENGTH = 20 MAX_LINE_GAP = 8 ANGLE_RANGE = (0, 55) ROI_RATIO = 2 / 3 # 蓝色锥桶(避障)参数(沿用) OBSTACLE_COLOR_LOWER = np.array([97, 154, 60]) OBSTACLE_COLOR_UPPER = np.array([117, 255, 255]) OBSTACLE_AREA_MIN = 600 OBSTACLE_AREA_MAX = 20000 ASPECT_RATIO_RANGE = (0.5, 1.4) EXTENT_THRESHOLD = 0.95 # 斑马线参数(只检测下半 ROI) ZEBRA_RATIO_THRESH = 0.3 CROSSWALK_STOP_DURATION = 3 CROSSWALK_SPEECH = "已到达斑马线,停车3秒后继续前行" # 变道 / 箭头识别参数(保持原路径) ARROW_MODEL_PATH = "/home/pi/arrow_best.onnx" ARROW_CLASS_NAMES = ["arrow_left", "arrow_right"] SIGN_COLOR_LOWER = np.array([100, 80, 50]) SIGN_COLOR_UPPER = np.array([130, 255, 255]) ARROW_BINARY_THRESH = 160 SIGN_AREA_MIN = 200 # <-- **已补定义**(之前缺失) CONF_THRESHOLD = 0.4 REQUIRED_CONSECUTIVE = 3 # A/B 识别 AB_MODEL_PATH = "/home/pi/ab_best.onnx" AB_CLASS_NAMES = ["A", "B"] # 黄线停车 YELLOW_COLOR_LOWER = np.array([20, 100, 100]) YELLOW_COLOR_UPPER = np.array([30, 255, 255]) YELLOW_LINE_MIN_LENGTH = 200 # 停车区分左右 PARK_AREA_LEFT = (0, W//2) PARK_AREA_RIGHT = (W//2, W) # 付费(自动模拟成功) PAY_DURATION = 30 PAY_AUTO_SUCCESS_AFTER = 5 # 自动模拟 5s 后付费成功(可改为集成真实接口) PAY_SCORE = 5 PAY_PROMPT = "请在30秒内扫码支付0.01元,自动模拟支付成功" # 字体 FONT_PATH = "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc" FONT_SIZE = 24 # 状态机(严格顺序) STATE_WAIT_START = "WAIT_START" STATE_START = "START" STATE_TRACK = "TRACK" # 巡线始终运行 STATE_CROSSWALK = "CROSSWALK" STATE_LANE_CHANGE = "LANE_CHANGE" STATE_AB_RECOG = "AB_RECOG" STATE_PARK = "PARK" STATE_PAY = "PAY" STATE_FINISH = "FINISH" # ----------------------------- # 硬件控制类(保留并简化接口) # ----------------------------- class HardwareController: def __init__(self): self.pi = pigpio.pi() if not self.pi.connected: raise RuntimeError("请启动 pigpio 服务: sudo pigpiod") self.last_error = 0.0 self.current_angle = SERVO_MID_ANGLE self.track_lost_count = 0 self.turn_duration = 0 self.last_turn_direction = 0 # unlock motor self.pi.set_servo_pulsewidth(MOTOR_PIN, NEUTRAL_PULSE) time.sleep(1.0) self.pi.set_servo_pulsewidth(MOTOR_PIN, NEUTRAL_PULSE) time.sleep(0.5) self.set_servo_angle(SERVO_MID_ANGLE) print("[HW] 初始化完成") def angle_to_pulse(self, angle): angle = np.clip(angle, SERVO_MIN_ANGLE, SERVO_MAX_ANGLE) return int(SERVO_MIN_PULSE + (angle / 180.0) * (SERVO_MAX_PULSE - SERVO_MIN_PULSE)) def set_servo_angle(self, angle): # 平滑舵机变化,防抖 smoothed = 0.6 * angle + 0.4 * self.current_angle pulse = self.angle_to_pulse(smoothed) self.pi.set_servo_pulsewidth(SERVO_PIN, pulse) self.current_angle = smoothed def set_motor_speed(self, pulse): pulse = int(np.clip(pulse, 1000, 2000)) self.pi.set_servo_pulsewidth(MOTOR_PIN, pulse) def pid_control(self, error): # 使用你给的完全反转误差映射逻辑 error = -error current_direction = 0 if error > DEAD_ZONE: current_direction = 2 elif error < -DEAD_ZONE: current_direction = 1 if current_direction != self.last_turn_direction: self.turn_duration = 0 self.last_turn_direction = current_direction else: self.turn_duration += 1 if self.turn_duration >= MAX_TURN_DURATION: error *= TURN_DECAY if abs(error) < DEAD_ZONE: error = 0.0 self.turn_duration = 0 p = KP * error d = KD * (error - self.last_error) self.last_error = error total_offset = p + d target_angle = SERVO_MID_ANGLE + total_offset self.set_servo_angle(target_angle) self.set_motor_speed(FORWARD_BASE) def stop(self): self.set_motor_speed(NEUTRAL_PULSE) def cleanup(self): try: self.stop() self.set_servo_angle(SERVO_MID_ANGLE) self.pi.stop() except: pass print("[HW] 清理完成") # ----------------------------- # 图像与模型工具函数(保留原逻辑) # ----------------------------- def draw_chinese(frame, text, pos=(10, 30), color=(255,255,0)): img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) pil = Image.fromarray(img_rgb) draw = ImageDraw.Draw(pil) try: font = ImageFont.truetype(FONT_PATH, FONT_SIZE) except: font = ImageFont.load_default() draw.text(pos, text, font=font, fill=tuple(int(c) for c in color)) return cv2.cvtColor(np.array(pil), cv2.COLOR_RGB2BGR) def detect_color_contours(frame, lower, upper, min_area=0): hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, lower, upper) mask = cv2.medianBlur(mask, 5) kernel = np.ones((5,5), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) return [c for c in contours if cv2.contourArea(c) >= min_area], mask def detect_blue_cone(frame): contours, mask = detect_color_contours(frame, OBSTACLE_COLOR_LOWER, OBSTACLE_COLOR_UPPER, OBSTACLE_AREA_MIN) valid = [] for c in contours: area = cv2.contourArea(c) if area < OBSTACLE_AREA_MIN or area > OBSTACLE_AREA_MAX: continue x,y,w,h = cv2.boundingRect(c) ar = w / float(h) if h>0 else 0 if not (ASPECT_RATIO_RANGE[0] <= ar <= ASPECT_RATIO_RANGE[1]): continue extent = area / float(w*h) if (w*h)>0 else 0 if extent >= EXTENT_THRESHOLD: continue valid.append((area,(x,y,w,h))) if not valid: return False, None, mask valid.sort(key=lambda x: x[0], reverse=True) return True, valid[0][1], mask def detect_crosswalk(frame): # 仅检测下半 ROI,避免误触发 roi = frame[int(H*ROI_RATIO):, :] gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY) ratio = cv2.countNonZero(binary) / float(roi.shape[0] * roi.shape[1]) return ratio >= ZEBRA_RATIO_THRESH def generate_black_text_mask(frame): hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) mask_blue = cv2.inRange(hsv, SIGN_COLOR_LOWER, SIGN_COLOR_UPPER) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) mask_blue = cv2.morphologyEx(mask_blue, cv2.MORPH_OPEN, kernel) mask_blue = cv2.morphologyEx(mask_blue, cv2.MORPH_CLOSE, kernel) contours, _ = cv2.findContours(mask_blue, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) mask_sym = None if contours: for cnt in contours: if cv2.contourArea(cnt) >= SIGN_AREA_MIN: x,y,w,h = cv2.boundingRect(cnt) pad = 3 x0,y0 = max(0,x-pad), max(0,y-pad) x1,y1 = min(frame.shape[1], x+w+pad), min(frame.shape[0], y+h+pad) roi = frame[y0:y1, x0:x1] gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) _, mask_sym = cv2.threshold(gray, ARROW_BINARY_THRESH, 255, cv2.THRESH_BINARY) mask_sym = cv2.morphologyEx(mask_sym, cv2.MORPH_OPEN, np.ones((2,2),np.uint8)) break original = mask_sym if mask_sym is not None else mask_blue return cv2.bitwise_not(original) def model_infer(mask, session, input_name, model_input_size, class_names): mask_resized = cv2.resize(mask, model_input_size) if len(mask_resized.shape) == 2: mask_resized = cv2.cvtColor(mask_resized, cv2.COLOR_GRAY2BGR) mask_input = mask_resized[:,:,::-1].transpose(2,0,1).astype(np.float32)/255.0 mask_input = np.expand_dims(mask_input, axis=0) outputs = session.run(None, {input_name: mask_input})[0] max_conf = -1.0 best_cls = "Waiting..." for det in outputs: conf = float(det[4]) cls = int(det[5]) if conf > max_conf and conf >= CONF_THRESHOLD and cls < len(class_names): max_conf = conf best_cls = class_names[cls] return best_cls, max_conf def get_lane_error(frame): height, width = frame.shape[:2] roi_y_start = int(height * ROI_RATIO) roi = frame[roi_y_start:height, :] roi_h = roi.shape[0] if roi.size == 0: return None, (None,None,None,[], None) gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(4,4)) enhanced = clahe.apply(gray_roi) blur = cv2.GaussianBlur(enhanced, (3,3), 0) _, binary = cv2.threshold(blur, WHITE_THRESHOLD, 255, cv2.THRESH_BINARY) kernel = np.ones((3,3),np.uint8) binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=2) lines = cv2.HoughLinesP(binary, 1, np.pi/180, 20, minLineLength=MIN_LINE_LENGTH, maxLineGap=MAX_LINE_GAP) left_lines, right_lines = [], [] if lines is not None: for line in lines: x1,y1,x2,y2 = line[0] dx = x2-x1 dy = y2-y1 if dx == 0: continue angle = abs(np.arctan(dy/dx)*180/np.pi) if not (ANGLE_RANGE[0] < angle < ANGLE_RANGE[1]): continue if y1 < y2: x1,y1,x2,y2 = x2,y2,x1,y1 if x1 < width/2: left_lines.append([x1,y1,x2,y2]) else: right_lines.append([x1,y1,x2,y2]) def fit_line(lines_list): if len(lines_list) < 2: return None points=[] for x1,y1,x2,y2 in lines_list: points.append((x1,y1,2)) points.append((x2,y2,1)) xs=np.array([p[0] for p in points]) ys=np.array([p[1] for p in points]) weights=np.array([p[2] for p in points]) try: coeff = np.polyfit(ys, xs, 1, w=weights) y_min, y_max = 0, roi_h-1 x_min = int(coeff[0]*y_min + coeff[1]) x_max = int(coeff[0]*y_max + coeff[1]) return [x_min, y_min, x_max, y_max] except: return None left_fit = fit_line(left_lines) right_fit = fit_line(right_lines) mid_points = [] error = None if left_fit and right_fit: for y_roi in range(0, roi_h, 10): left_coeff = np.polyfit([left_fit[1], left_fit[3]],[left_fit[0], left_fit[2]],1) right_coeff = np.polyfit([right_fit[1], right_fit[3]],[right_fit[0], right_fit[2]],1) left_x = left_coeff[0]*y_roi + left_coeff[1] right_x = right_coeff[0]*y_roi + right_coeff[1] mid_x = int((left_x + right_x)/2) mid_y = y_roi + roi_y_start mid_points.append((mid_x, mid_y)) image_center_x = width//2 current_mid_x = mid_points[-1][0] if mid_points else image_center_x error = current_mid_x - image_center_x elif left_fit and not right_fit: for y_roi in range(0, roi_h, 10): left_coeff = np.polyfit([left_fit[1], left_fit[3]],[left_fit[0], left_fit[2]],1) left_x = left_coeff[0]*y_roi + left_coeff[1] target_x = left_x + SINGLE_LINE_OFFSET mid_points.append((int(target_x), y_roi + roi_y_start)) image_center_x = width//2 current_target_x = mid_points[-1][0] if mid_points else image_center_x error = current_target_x - image_center_x elif right_fit and not left_fit: for y_roi in range(0, roi_h, 10): right_coeff = np.polyfit([right_fit[1], right_fit[3]],[right_fit[0], right_fit[2]],1) right_x = right_coeff[0]*y_roi + right_coeff[1] target_x = right_x - SINGLE_LINE_OFFSET mid_points.append((int(target_x), y_roi + roi_y_start)) image_center_x = width//2 current_target_x = mid_points[-1][0] if mid_points else image_center_x error = current_target_x - image_center_x return error, (left_fit, right_fit, roi_y_start, mid_points, binary) # ----------------------------- # 主控制逻辑 # ----------------------------- def main(): # 初始化摄像头 cap = cv2.VideoCapture(CAM_INDEX) cap.set(cv2.CAP_PROP_FRAME_WIDTH, W) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, H) cap.set(cv2.CAP_PROP_FPS, FPS_TARGET) time.sleep(1.0) if not cap.isOpened(): print("[ERR] 摄像头打开失败") return # 初始化硬件 try: hw = HardwareController() except Exception as e: print("[ERR] 硬件初始化失败:", e) cap.release() return # 加载模型(箭头 + AB) try: arrow_sess = onnxruntime.InferenceSession(ARROW_MODEL_PATH, providers=["CPUExecutionProvider"]) arrow_input = arrow_sess.get_inputs()[0].name arrow_size = (arrow_sess.get_inputs()[0].shape[3], arrow_sess.get_inputs()[0].shape[2]) print("[MODEL] Arrow loaded:", arrow_size) except Exception as e: print("[ERR] Arrow model load failed:", e) hw.cleanup(); cap.release(); return try: ab_sess = onnxruntime.InferenceSession(AB_MODEL_PATH, providers=["CPUExecutionProvider"]) ab_input = ab_sess.get_inputs()[0].name ab_size = (ab_sess.get_inputs()[0].shape[3], ab_sess.get_inputs()[0].shape[2]) print("[MODEL] AB loaded:", ab_size) except Exception as e: print("[ERR] AB model load failed:", e) hw.cleanup(); cap.release(); return # 状态 & 标志 state = STATE_WAIT_START start_time = None last_save_time = time.time() crosswalk_start = None lane_change_dir = None lane_change_confirm_count = 0 lane_change_done = False ab_result = None pay_start = None pay_done = False # 保证任务只执行一次的标志(除了 TRACK) done_flags = { STATE_START: False, STATE_CROSSWALK: False, STATE_LANE_CHANGE: False, STATE_AB_RECOG: False, STATE_PARK: False, STATE_PAY: False } print("[SYSTEM] 全自动系统就绪,自动检测拆挡板(蓝色标识)后发车") # 用于判断挡板是否存在:使用 SIGN_COLOR_LOWER/UPPER 掩码 def barrier_present(frame): cnts, _ = detect_color_contours(frame, SIGN_COLOR_LOWER, SIGN_COLOR_UPPER, SIGN_AREA_MIN) return len(cnts) > 0 # 自动付费(模拟)函数 def auto_pay_simulator(start_ts): return (time.time() - start_ts) >= PAY_AUTO_SUCCESS_AFTER # 主循环 try: while True: t0 = time.time() ret, frame = cap.read() if not ret: print("[ERR] 读帧失败") break display = frame.copy() # 始终进行循迹误差计算并调用 PID(自开始后贯穿) lane_error, lane_info = get_lane_error(frame) left_fit, right_fit, roi_y_start, mid_points, binary = (None, None, None, [], None) if lane_info is not None: left_fit, right_fit, roi_y_start, mid_points, binary = lane_info # 状态机 if state == STATE_WAIT_START: if barrier_present(frame): display = draw_chinese(display, "检测到蓝色挡板,等待移除...", (10, H//2 - 20), (0,0,255)) hw.stop() else: if start_time is None: start_time = time.time() print("[STATE] 挡板移除,开始发车计时") elif time.time() - start_time >= 0.5: state = STATE_START done_flags[STATE_START] = False start_time = time.time() print("[STATE] 切换 -> START") display = draw_chinese(display, "等待拆挡板...", (10,30), (255,0,0)) elif state == STATE_START: if lane_error is not None: hw.pid_control(lane_error) if left_fit and right_fit: if not done_flags[STATE_START]: print("[START] 前轮过线检测到,进入巡线避障") done_flags[STATE_START] = True last_save_time = time.time() state = STATE_TRACK print("[STATE] 切换 -> TRACK") else: display = draw_chinese(display, "发车等待:查找起跑线...", (10,60), (0,255,255)) elif state == STATE_TRACK: if time.time() - last_save_time >= SAVE_INTERVAL: ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") path = os.path.join(DATA_SAVE_DIR, f"track_{ts}.jpg") cv2.imwrite(path, frame) print("[DATA] 已保存:", path) last_save_time = time.time() if lane_error is not None: hw.pid_control(lane_error) else: hw.set_servo_angle(SERVO_MID_ANGLE) hw.set_motor_speed(FORWARD_LOW) cone_found, bbox, mask = detect_blue_cone(frame) if cone_found and bbox is not None: x,y,w,h = bbox center_x = x + w//2 bottom_y = y + h if bottom_y > int(H*0.5): display = draw_chinese(display, "近距离障碍,微调避障", (10,90), (0,255,255)) if center_x < W//2: hw.set_servo_angle(min(SERVO_MAX_ANGLE, hw.current_angle + 8)) else: hw.set_servo_angle(max(SERVO_MIN_ANGLE, hw.current_angle - 8)) hw.set_motor_speed(FORWARD_LOW) if detect_crosswalk(frame) and not done_flags[STATE_CROSSWALK]: print("[TRACK] 斑马线检测到,切换 -> CROSSWALK") state = STATE_CROSSWALK crosswalk_start = time.time() done_flags[STATE_CROSSWALK] = True hw.stop() display = draw_chinese(display, "阶段:巡线避障", (10,30), (0,255,0)) elif state == STATE_CROSSWALK: elapsed = time.time() - crosswalk_start display = draw_chinese(display, f"斑马线停车倒计时: {max(0, int(CROSSWALK_STOP_DURATION - elapsed))}s", (10,60), (0,255,255)) display = draw_chinese(display, CROSSWALK_SPEECH, (10, 100), (255,255,0)) hw.stop() if elapsed >= CROSSWALK_STOP_DURATION: print("[CROSSWALK] 停车完成,切换 -> LANE_CHANGE") state = STATE_LANE_CHANGE lane_change_dir = None lane_change_confirm_count = 0 lane_change_done = False done_flags[STATE_LANE_CHANGE] = False elif state == STATE_LANE_CHANGE: display = draw_chinese(display, "阶段:变道任务(识别箭头)", (10,30), (255,165,0)) if lane_error is not None: hw.pid_control(lane_error) # 识别箭头并连续确认 mask = generate_black_text_mask(frame) pred, conf = model_infer(mask, arrow_sess, arrow_input, arrow_size, ARROW_CLASS_NAMES) if pred != "Waiting...": # 连续确认逻辑:如果与上次相同则计数,否则重置为 1 if lane_change_dir is None: lane_change_dir = pred lane_change_confirm_count = 1 else: if pred == lane_change_dir: lane_change_confirm_count += 1 else: lane_change_dir = pred lane_change_confirm_count = 1 display = draw_chinese(display, f"箭头识别: {pred} ({conf:.2f}) 连续: {lane_change_confirm_count}/{REQUIRED_CONSECUTIVE}", (10,70), (255,255,0)) if lane_change_confirm_count >= REQUIRED_CONSECUTIVE: # 检查目标侧近障碍,若有则先避障再变道 target_is_left = (lane_change_dir == "arrow_left") cone_found2, bbox2, _ = detect_blue_cone(frame) need_delay = False if cone_found2 and bbox2: bx,by,bw,bh = bbox2 bcenter_x = bx + bw//2 by_bottom = by+bh if target_is_left and bcenter_x < W//2 and by_bottom > int(H*0.4): need_delay = True if (not target_is_left) and bcenter_x > W//2 and by_bottom > int(H*0.4): need_delay = True if need_delay: display = draw_chinese(display, "变道前方有近障碍,延迟并避障", (10,110), (0,255,255)) if target_is_left: hw.set_servo_angle(min(SERVO_MAX_ANGLE, hw.current_angle + 12)) else: hw.set_servo_angle(max(SERVO_MIN_ANGLE, hw.current_angle - 12)) hw.set_motor_speed(FORWARD_LOW) time.sleep(0.6) lane_change_dir = None lane_change_confirm_count = 0 continue # 执行变道微调(不切断 PID) print(f"[LANE_CHANGE] 执行变道:{lane_change_dir}") if lane_change_dir == "arrow_left": hw.set_servo_angle(max(SERVO_MIN_ANGLE, hw.current_angle - 18)) else: hw.set_servo_angle(min(SERVO_MAX_ANGLE, hw.current_angle + 18)) hw.set_motor_speed(FORWARD_BASE - 200) time.sleep(0.6) else: display = draw_chinese(display, "未检测到箭头,继续巡迹搜索...", (10,70), (255,255,255)) # 检测引导区蓝黄一排以判定变道完成 blue_cnts, _ = detect_color_contours(frame, OBSTACLE_COLOR_LOWER, OBSTACLE_COLOR_UPPER, OBSTACLE_AREA_MIN) yellow_cnts, _ = detect_color_contours(frame, YELLOW_COLOR_LOWER, YELLOW_COLOR_UPPER, OBSTACLE_AREA_MIN) if len(blue_cnts) > 0 and len(yellow_cnts) > 0: lane_change_done = True hw.set_servo_angle(SERVO_MID_ANGLE) print("[LANE_CHANGE] 引导区检测到,变道完成,切换 -> AB_RECOG") state = STATE_AB_RECOG done_flags[STATE_LANE_CHANGE] = True lane_change_dir = None lane_change_confirm_count = 0 else: if lane_error is not None: hw.pid_control(lane_error) elif state == STATE_AB_RECOG: display = draw_chinese(display, "阶段:A/B 识别", (10,30), (255,0,255)) if lane_error is not None: hw.pid_control(lane_error) mask = generate_black_text_mask(frame) pred, conf = model_infer(mask, ab_sess, ab_input, ab_size, AB_CLASS_NAMES) display = draw_chinese(display, f"A/B 识别: {pred} ({conf:.2f})", (10,70), (255,255,0)) if pred in AB_CLASS_NAMES and conf >= CONF_THRESHOLD: ab_result = pred print(f"[AB_RECOG] 识别到: {ab_result},切换 -> PARK") state = STATE_PARK done_flags[STATE_AB_RECOG] = True time.sleep(0.2) elif state == STATE_PARK: display = draw_chinese(display, "阶段:停车任务(寻找黄线)", (10,30), (0,165,255)) if lane_error is not None: hw.pid_control(lane_error) yellow_cnts, ymask = detect_color_contours(frame, YELLOW_COLOR_LOWER, YELLOW_COLOR_UPPER, 50) found = False if yellow_cnts: cnt = max(yellow_cnts, key=cv2.contourArea) x,y,w,h = cv2.boundingRect(cnt) cx = x + w//2 park_area = PARK_AREA_LEFT if ab_result == "A" else PARK_AREA_RIGHT if park_area[0] < cx < park_area[1]: hw.stop() print(f"[PARK] 进入 {ab_result} 区停车完成") state = STATE_PAY pay_start = time.time() done_flags[STATE_PARK] = True found = True else: target_cx = (park_area[0] + park_area[1]) // 2 e = target_cx - cx hw.pid_control(e) display = draw_chinese(display, f"调整进入{ab_result}区...", (10,70), (255,255,0)) if not found: display = draw_chinese(display, "搜索黄线停车线...", (10,70), (255,0,0)) elif state == STATE_PAY: display = draw_chinese(display, "阶段:扫码付费(自动模拟)", (10,30), (0,200,200)) display = draw_chinese(display, PAY_PROMPT, (10,70), (255,255,0)) elapsed = time.time() - pay_start if pay_start else 0 display = draw_chinese(display, f"付费倒计时: {max(0, int(PAY_DURATION - elapsed))}s", (10,110), (255,255,0)) if auto_pay_simulator(pay_start): pay_done = True print("[PAY] 模拟付费成功") state = STATE_FINISH done_flags[STATE_PAY] = True elif elapsed >= PAY_DURATION: print("[PAY] 付费超时(自动结束)") state = STATE_FINISH elif state == STATE_FINISH: display = draw_chinese(display, "任务完成!", (W//2 - 80, H//2 - 10), (0,255,0)) if pay_done: display = draw_chinese(display, f"付费成功,加分: {PAY_SCORE}", (W//2 - 120, H//2 + 30), (0,255,0)) else: display = draw_chinese(display, "未成功付费或超时", (W//2 - 120, H//2 + 30), (0,0,255)) cv2.imshow("SmartCar Final Auto", display) cv2.waitKey(2000) break # 绘制 debug 可视化(循迹线 / mask) if mid_points: for i in range(len(mid_points)-1): cv2.line(display, mid_points[i], mid_points[i+1], (0,0,255), 3) if binary is not None: try: thumb = cv2.resize(binary, (160, 120)) display[10:130, W-170:W-10] = cv2.cvtColor(thumb, cv2.COLOR_GRAY2BGR) except: pass display = draw_chinese(display, f"状态: {state}", (8, 8), (255,255,255)) display = draw_chinese(display, f"舵机: {int(hw.current_angle)}", (8, 36), (255,200,0)) cv2.imshow("SmartCar Final Auto", display) if cv2.waitKey(1) & 0xFF == ord('q'): print("[USER] 手动退出") break # 按 FPS 控制循环频率 elapsed_loop = time.time() - t0 time.sleep(max(0, 1.0 / FPS_TARGET - elapsed_loop)) except KeyboardInterrupt: print("[USER] KeyboardInterrupt") finally: cap.release() cv2.destroyAllWindows() if 'hw' in locals(): hw.cleanup() print("[SYSTEM] 退出,清理完成") if __name__ == "__main__": os.environ.pop("QT_QPA_PLATFORM_PLUGIN_PATH", None) main() 进一步优化代码,先是对已用的库添加注释,再把代码的控制速度角度的代码优化并且添加注释,方便根据循迹、避障等调整代码参数
11-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值