#e1.4 draw_circles

本文介绍如何使用Python的turtle模块绘制不同大小和方向的圆形。通过调整参数,可以实现顺时针向上、顺时针向下画圆的效果,为初学者提供了实践代码示例。
#e1.4 draw_circles
#coding = uft-8
import turtle
turtle.pensize(2)
turtle.circle(20)
turtle.circle(80)
#顺时针向上画圆
turtle.circle(-80)
#顺时针向下画圆

# K230 圆形检测滤波优化版 # 专为K230平台优化,使用兼容的API和滤波技术 # 加入高斯滤波和形态学滤波,减少资源消耗 from machine import Pin, FPIOA, PWM from media.sensor import * from media.display import * from media.media import * import time import math import gc print(">>> K230 圆形检测滤波优化版 <<<") print("🚀 专为K230优化,兼容API+滤波技术") # 硬件配置 X_SERVO_GPIO, Y_SERVO_GPIO = 42, 52 X_SERVO_PWM_ID, Y_SERVO_PWM_ID = 0, 4 SERVO_FREQ = 50 PULSE_CENTER = 1.6 PULSE_MIN = 0.5 PULSE_MAX = 2.5 # 停止按键 fpioa = FPIOA() fpioa.set_function(27, FPIOA.GPIO27) key1 = Pin(27, Pin.IN, Pin.PULL_UP) class K230FilteredCircleSystem: """K230滤波优化版圆形检测系统""" def __init__(self): # 🚀 优化的检测参数 self.BINARY_THRESHOLD = [(62, 32)] # 二值化阈值 self.CIRCLE_AREA_THRESHOLD = 1000 # 圆形面积阈值 self.MIN_RADIUS = 25 # 最小半径 self.MAX_RADIUS = 180 # 最大半径 self.DETECTION_THRESHOLD = 3500 # 检测阈值 # 🚀 滤波参数 self.GAUSSIAN_KERNEL_SIZE = 3 # 高斯滤波核大小 self.USE_MORPHOLOGICAL = True # 启用形态学滤波 self.ERODE_DILATE_SIZE = 1 # 腐蚀膨胀核大小 # 🚀 性能优化参数 self.FRAME_SKIP = 2 # 帧跳跃间隔 self.GC_INTERVAL = 20 # 垃圾回收间隔 self.STABLE_FRAMES_REQUIRED = 30 # 稳定帧数要求(减少) # 🚀 自适应参数 self.adaptive_enabled = True # 启用自适应调整 self.detection_failure_count = 0 # 检测失败计数 self.adaptive_threshold_step = 200 # 阈值调整步长 # 分辨率设置 self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT = 480, 800 self.saved_circle = None self.gimbal = None self.sensor = None self.frame_counter = 0 print("🚀 K230滤波优化参数:") print(" 显示分辨率: {}x{}".format(self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT)) print(" 高斯滤波核: {}x{}".format(self.GAUSSIAN_KERNEL_SIZE, self.GAUSSIAN_KERNEL_SIZE)) print(" 形态学滤波: {}".format("启用" if self.USE_MORPHOLOGICAL else "禁用")) print(" 检测阈值: {}".format(self.DETECTION_THRESHOLD)) print(" 帧跳跃间隔: {}".format(self.FRAME_SKIP)) print(" 自适应调整: {}".format("启用" if self.adaptive_enabled else "禁用")) def init_hardware(self): """初始化硬件""" print("🚀 初始化硬件...") self.gimbal = K230OptimizedGimbal() self.init_camera_and_display() print("✅ 硬件初始化完成") def init_camera_and_display(self): """摄像头和显示初始化""" print("📷 开始摄像头和显示初始化...") try: # 初始化Display print("🖥️ 初始化Display...") Display.init(Display.ST7701, width=self.DISPLAY_WIDTH, height=self.DISPLAY_HEIGHT, to_ide=True) print("✅ Display初始化成功") # 初始化MediaManager print("📺 初始化MediaManager...") MediaManager.init() print("✅ MediaManager初始化成功") # 初始化摄像头 print("📷 初始化摄像头传感器...") self.sensor = Sensor(id=2) self.sensor.reset() print("✅ 摄像头传感器重置完成") # 设置摄像头参数 print("⚙️ 设置摄像头参数...") self.sensor.set_framesize(width=self.DISPLAY_WIDTH, height=self.DISPLAY_HEIGHT) self.sensor.set_pixformat(Sensor.RGB565) print("✅ 摄像头参数设置完成") # 启动摄像头 print("🚀 启动摄像头...") self.sensor.run() print("✅ 摄像头启动成功") # 等待稳定 print("⏳ 等待摄像头稳定...") time.sleep(2) # 测试快照 print("📸 测试摄像头快照...") test_img = self.sensor.snapshot() if test_img: print("✅ 摄像头快照测试成功") print("📊 图像尺寸: {}x{}".format(test_img.width(), test_img.height())) else: raise RuntimeError("摄像头快照测试失败") print("🎉 摄像头和显示系统初始化完成") except Exception as e: print("❌ 初始化失败: {}".format(e)) self.cleanup_resources() raise e def cleanup_resources(self): """清理资源""" try: if self.sensor: self.sensor.stop() self.sensor = None Display.deinit() MediaManager.deinit() gc.collect() except: pass def deinit_camera(self): """安全关闭摄像头""" print("📷 正在关闭摄像头...") try: if self.sensor: self.sensor.stop() time.sleep(0.5) Display.deinit() MediaManager.deinit() self.sensor = None print("📷 摄像头已关闭") except Exception as e: print("⚠️ 摄像头关闭警告: {}".format(e)) def apply_filtering(self, img): """🚀 K230兼容的图像滤波处理""" try: # 转换为灰度图(就地操作,节省内存) img.to_grayscale(copy=False) # 高斯滤波降噪 img.gaussian(self.GAUSSIAN_KERNEL_SIZE, copy=False) # 二值化 img.binary(self.BINARY_THRESHOLD, copy=False) # 形态学滤波(如果启用) if self.USE_MORPHOLOGICAL: # 开运算:先腐蚀后膨胀,去除小噪声 img.erode(self.ERODE_DILATE_SIZE, threshold=1) img.dilate(self.ERODE_DILATE_SIZE, threshold=1) return img except Exception as e: print("⚠️ 滤波处理失败: {}".format(e)) return None def detect_filtered_circles(self, img): """🚀 K230兼容的滤波圆形检测""" try: # 应用滤波处理 filtered_img = self.apply_filtering(img.copy()) if not filtered_img: return None # 使用K230支持的find_circles方法 circles = filtered_img.find_circles(threshold=self.DETECTION_THRESHOLD, x_margin=15, y_margin=15, r_margin=15, r_min=self.MIN_RADIUS, r_max=self.MAX_RADIUS, r_step=3) del filtered_img # 立即释放内存 if not circles: return None print("🔍 滤波检测到 {} 个圆形".format(len(circles))) # 选择最佳圆形 best_circle = self.select_best_circle(circles) return best_circle except Exception as e: print("⚠️ 滤波检测失败: {}".format(e)) return None def select_best_circle(self, circles): """选择最佳圆形""" try: valid_circles = [] for circle in circles: area = math.pi * circle.r() * circle.r() # 基本过滤 if area < self.CIRCLE_AREA_THRESHOLD: continue # 位置检查 center_x, center_y = circle.x(), circle.y() radius = circle.r() margin = radius + 15 if (center_x < margin or center_x > (self.DISPLAY_WIDTH - margin) or center_y < margin or center_y > (self.DISPLAY_HEIGHT - margin)): continue # 计算评分 size_score = min(area / 2000.0, 1.0) center_score = 1.0 - abs(center_x - self.DISPLAY_WIDTH/2) / (self.DISPLAY_WIDTH/2) * 0.3 total_score = size_score * center_score valid_circles.append((circle, total_score, area)) print("✅ 滤波候选圆形: 中心({}, {}), 半径{}, 评分{:.2f}".format( center_x, center_y, radius, total_score)) if valid_circles: # 选择评分最高的圆形 best_circle, best_score, best_area = max(valid_circles, key=lambda x: x[1]) print("🎯 选择最佳滤波圆形: 中心({}, {}), 半径{}, 评分{:.2f}".format( best_circle.x(), best_circle.y(), best_circle.r(), best_score)) return (best_circle.x(), best_circle.y(), best_circle.r()) return None except Exception as e: print("⚠️ 圆形选择失败: {}".format(e)) return None def adaptive_adjust_parameters(self, detection_success): """🚀 自适应参数调整""" if not self.adaptive_enabled: return if detection_success: # 检测成功,重置失败计数 self.detection_failure_count = 0 else: # 检测失败,增加失败计数 self.detection_failure_count += 1 # 每连续失败8次,调整参数 if self.detection_failure_count >= 8: print("🔧 自适应调整: 连续{}次检测失败,调整参数".format(self.detection_failure_count)) # 降低检测阈值,提高检测敏感度 if self.DETECTION_THRESHOLD > 2000: self.DETECTION_THRESHOLD -= self.adaptive_threshold_step print("🔧 调整检测阈值: {}".format(self.DETECTION_THRESHOLD)) # 降低二值化阈值 current_threshold = self.BINARY_THRESHOLD[0][0] new_threshold = max(30, current_threshold - 5) if new_threshold != current_threshold: self.BINARY_THRESHOLD = [(new_threshold, 255)] print("🔧 调整二值化阈值: {} -> {}".format(current_threshold, new_threshold)) # 重置失败计数 self.detection_failure_count = 0 def auto_detection_phase(self): """🚀 自动检测阶段 - K230优化版""" print("🔍 开始K230滤波圆形检测...") frame_count = 0 stable_count = 0 detection_history = [] while True: if key1.value() == 0: return False try: img = self.sensor.snapshot() frame_count += 1 self.frame_counter += 1 # 🚀 帧跳跃优化 - 减少处理频率 if frame_count % self.FRAME_SKIP != 0: # 显示原始图像,但不进行检测 status = "K230滤波版 | 帧数: {} | 跳帧中...".format(frame_count) img.draw_string_advanced(10, self.DISPLAY_HEIGHT - 30, 16, status, color=(128, 128, 128)) Display.show_image(img) continue circle_info = self.detect_filtered_circles(img) stable_circle = None # 🚀 自适应参数调整 self.adaptive_adjust_parameters(circle_info is not None) if circle_info: detection_history.append(circle_info) if len(detection_history) > 6: # 减少历史记录长度 detection_history.pop(0) if len(detection_history) >= 3: # 减少稳定性要求 stable_circle = self.calculate_stable_circle(detection_history) if stable_circle: stable_count += 1 # 绘制检测结果 if circle_info: center_x, center_y, radius = circle_info img.draw_circle(int(center_x), int(center_y), int(radius), color=(255, 255, 0), thickness=2) if stable_circle: center_x, center_y, radius = stable_circle img.draw_circle(int(center_x), int(center_y), int(radius), color=(0, 255, 0), thickness=3) img.draw_cross(int(center_x), int(center_y), color=(255, 0, 0), size=15, thickness=3) if stable_circle and stable_count >= self.STABLE_FRAMES_REQUIRED: img.draw_string_advanced(100, 300, 28, "✅ 检测成功!", color=(0, 255, 0)) Display.show_image(img) self.saved_circle = stable_circle print("✅ 滤波圆形检测成功: 中心({}, {}), 半径{}".format( stable_circle[0], stable_circle[1], stable_circle[2])) time.sleep(1) return True elif stable_circle: progress = min(stable_count / self.STABLE_FRAMES_REQUIRED, 1.0) * 100 img.draw_string_advanced(10, 10, 22, "滤波检测中... {:.0f}%".format(progress), color=(0, 255, 255)) else: img.draw_string_advanced(10, 10, 22, "寻找稳定圆形...", color=(255, 255, 0)) else: stable_count = 0 img.draw_string_advanced(10, 10, 22, "滤波分析中...", color=(255, 255, 0)) # 状态显示 status = "K230滤波版 | 帧数: {} | 阈值: {} | 按KEY1停止".format(frame_count, self.DETECTION_THRESHOLD) img.draw_string_advanced(10, self.DISPLAY_HEIGHT - 30, 16, status, color=(255, 255, 255)) Display.show_image(img) # 🚀 优化的垃圾回收 if self.frame_counter % self.GC_INTERVAL == 0: gc.collect() except Exception as e: print("⚠️ 检测循环错误: {}".format(e)) time.sleep(0.1) def calculate_stable_circle(self, history): """计算稳定圆形""" if len(history) < 3: # 减少要求 return None try: # 计算最近检测的平均值 recent_detections = history[-3:] avg_center_x = sum(detection[0] for detection in recent_detections) / 3 avg_center_y = sum(detection[1] for detection in recent_detections) / 3 avg_radius = sum(detection[2] for detection in recent_detections) / 3 return (int(avg_center_x), int(avg_center_y), int(avg_radius)) except: return None def countdown_phase(self): """倒计时阶段""" print("⏰ 开始5秒倒计时...") for countdown in range(5, 0, -1): if key1.value() == 0: return False print("⏰ 倒计时: {}秒".format(countdown)) time.sleep(1) return True def run(self): """主运行流程""" try: self.init_hardware() print("\n" + "="*60) print("🚀 K230滤波优化版圆形检测系统启动") print("📋 特点: K230兼容API+滤波技术,优化资源使用") print("🛑 任何阶段按KEY1都可停止") print("="*60) if not self.auto_detection_phase(): return if not self.countdown_phase(): return print("🎯 检测完成!保存的圆形信息: {}".format(self.saved_circle)) except Exception as e: print("❌ 系统错误: {}".format(e)) import sys sys.print_exception(e) finally: self.cleanup() def cleanup(self): """清理资源""" print("🧹 清理系统资源...") if self.sensor: self.deinit_camera() if self.gimbal: self.gimbal.deinit() gc.collect() print("✅ 资源清理完成") class K230OptimizedGimbal: """K230优化版舵机控制类""" def __init__(self): fpioa = FPIOA() fpioa.set_function(X_SERVO_GPIO, getattr(FPIOA, f'PWM{X_SERVO_PWM_ID}')) fpioa.set_function(Y_SERVO_GPIO, getattr(FPIOA, f'PWM{Y_SERVO_PWM_ID}')) self.pwm_x = PWM(X_SERVO_PWM_ID, SERVO_FREQ, enable=True) self.pwm_y = PWM(Y_SERVO_PWM_ID, SERVO_FREQ, enable=True) self.period_ms = 1000 / SERVO_FREQ # 校准参数 self.SERVO_MAPPING_SCALE_X = 1.4 self.SERVO_MAPPING_SCALE_Y = 0.7 self.SERVO_OFFSET_X = 0.0 self.SERVO_OFFSET_Y = 3.0 self.BASE_ANGLE_MAPPING = 12.0 self.CAMERA_CENTER_X = 240 # 480/2 self.CAMERA_CENTER_Y = 400 # 800/2 self.reset() def reset(self): """复位到中心位置""" pulse_x = self.angle_to_pulse(0) pulse_y = self.angle_to_pulse(0) duty_x = (pulse_x / self.period_ms) * 100 duty_y = (pulse_y / self.period_ms) * 100 self.pwm_x.duty(duty_x) self.pwm_y.duty(duty_y) time.sleep(0.8) def angle_to_pulse(self, angle): """角度转脉宽""" angle = max(-40, min(40, angle)) if angle >= 0: pulse = PULSE_CENTER + (angle / 40) * (PULSE_MAX - PULSE_CENTER) else: pulse = PULSE_CENTER + (angle / 40) * (PULSE_CENTER - PULSE_MIN) return pulse def deinit(self): """释放资源""" self.reset() self.pwm_x.deinit() self.pwm_y.deinit() def main(): """主程序""" system = K230FilteredCircleSystem() system.run() if __name__ == "__main__": main()
07-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值