蚊子雷达追踪打击系统-源码
奇葩软件千千万,我的工具占一半
打包及程序介绍见原创发布区
import cv2 import numpy as np import matplotlib import math from matplotlib import pyplot as plt from matplotlib import rcParams from matplotlib.animation import FuncAnimation from collections import deque from datetime import datetime import time import pygame import os import wave import struct # **添加以下两行设置后端** matplotlib.use('Qt5Agg') # 替换原有的'TkAgg' # 在独立线程中运行Matplotlib动画 import threading # 设置中文字体 rcParams['font.family'] = 'SimHei' rcParams['axes.unicode_minus'] = False # 生成驱蚊音频文件 def generate_anti_mosquito_sound(): sample_rate = 44100 # 采样率:每秒采集44100个音频样本 duration = 3.0 # 音频时长:3秒 freq = 22000 # 频率:22000Hz(超声波,接近蚊子能感知的上限) samples = [] for i in range(int(duration * sample_rate)): sample = 0.5 * math.sin(2 * math.pi * freq * i / sample_rate) samples.append(sample) filename = "mosquito_sound.wav" with wave.open(filename, 'w') as wf: wf.setnchannels(1) wf.setsampwidth(2) wf.setframerate(sample_rate) for sample in samples: data = struct.pack('<h', int(sample * 32767)) wf.writeframesraw(data) return filename # 初始化音频系统 try: pygame.mixer.init() sound_file = generate_anti_mosquito_sound() mosquito_sound = pygame.mixer.Sound(sound_file) print("已生成驱蚊音频文件") except Exception as e: print(f"音频初始化失败: {e}") mosquito_sound = None # 初始化雷达图 plt.style.use('dark_background') fig = plt.figure(figsize=(10, 8), facecolor='black') fig.suptitle('蚊子雷达追踪打击系统', color='lime', fontsize=16, fontweight='bold') # 创建雷达主界面 - 改进的潜水艇风格 ax_radar = fig.add_subplot(121, polar=True, facecolor=(0, 0.05, 0)) ax_info = fig.add_subplot(122, facecolor='black') ax_info.axis('off') # 雷达图美化设置 - 军用风格 ax_radar.set_theta_zero_location('N') ax_radar.set_theta_direction(-1) ax_radar.set_ylim(0, 500) ax_radar.set_yticklabels([]) ax_radar.grid(color='lime', alpha=0.2, linestyle='-') ax_radar.spines['polar'].set_visible(False) ax_radar.tick_params(axis='both', colors='lime') # 添加雷达背景效果 - 同心圆网格 background_circles = [] for r in [100, 200, 300, 400, 500]: circle = plt.Circle((0, 0), r, transform=ax_radar.transData._b, fill=False, color='lime', alpha=0.1, linewidth=0.5) ax_radar.add_artist(circle) background_circles.append(circle) ax_radar.text(0, r, f'{r}cm', color='lime', ha='center', va='center', fontsize=8, alpha=0.7) # 添加雷达中心点 center_point = ax_radar.scatter([0], [0], c='lime', s=50, alpha=0.8) # 初始化雷达元素 scan_line = ax_radar.plot([], [], color='lime', linestyle='-', linewidth=2, alpha=0.9)[0] scan_shadow = ax_radar.plot([], [], color='lime', linestyle='-', linewidth=8, alpha=0.1)[0] mosquito_dots = ax_radar.scatter([], [], c='red', s=80, alpha=0.9, edgecolors='yellow', linewidths=1.5, zorder=10) scan_arc = None scan_arc_fill = None trail_lines = [] # 初始化雷达数据 max_distance = 500 r = deque([0] * 360, maxlen=360) theta = np.linspace(0, 2 * np.pi, 360, endpoint=False) # 系统状态变量 class SystemState: def __init__(self): self.auto_sound = True # 默认开启声波攻击 self.sound_playing = False self.last_sound_time = 0 self.total_detected = 0 self.detected_today = 0 self.start_time = datetime.now() self.screenshot_count = 0 system_state = SystemState() # 初始化信息面板 def init_info_panel(): titles = ["系统状态", "检测统计", "蚊子信息", "追踪数据", "声波设置"] contents = [ [f"状态: 运行中", f"扫描中", f"摄像头: 开启", f"启动: {system_state.start_time.strftime('%H:%M:%S')}"], [f"当前: 0", f"今日: 0", f"最大: 0", f"平均: 0"], [f"速度: 0 cm/s", f"大小: 0 px", f"方向: -", f"距离: 0 cm"], [f"追踪: 0", f"历史: 0", f"误报: 0", f"准确率: 0%"], [f"声波驱蚊: 开启", f"按A键切换", f"截图: 按P键", ""] # 修改显示文本 ] title_y_positions = [0.92, 0.72, 0.52, 0.32, 0.12] content_line_height = 0.05 title_content_gap = 0.02 info_texts = [] for i, (title, content) in enumerate(zip(titles, contents)): ax_info.text(0.1, title_y_positions[i], title, color='cyan', fontsize=11, fontweight='bold', transform=ax_info.transAxes) for j, item in enumerate(content): text = ax_info.text(0.15, title_y_positions[i] - title_content_gap - j * content_line_height, item, color='lime', fontsize=9, transform=ax_info.transAxes) info_texts.append(text) ax_info.text(0.5, 0.02, "By:Killerzeno", color='white', ha='center', fontsize=14, fontweight='bold', style='italic', transform=ax_info.transAxes) return info_texts info_texts = init_info_panel() # 初始化摄像头 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 边缘检测参数(可调整) EDGE_THRESHOLD1 = 50 # Canny边缘检测低阈值 EDGE_THRESHOLD2 = 150 # Canny边缘检测高阈值 # 背景减法器用于运动检测 fgbg = cv2.createBackgroundSubtractorMOG2(history=100, varThreshold=16, detectShadows=False) # 用于扫描动画的变量 current_angle = 0 scan_speed = 5 mosquito_count = 0 max_mosquito_count = 0 false_positives = 0 true_positives = 0 # 蚊子轨迹类 class MosquitoTrack: def __init__(self, id, x, y, time): self.id = id self.positions = [(x, y, time)] self.speeds = [] self.directions = [] self.last_update = time self.active = True def update(self, x, y, time): dx = x - self.positions[-1][0] dy = y - self.positions[-1][1] dt = time - self.last_update if dt > 0: speed = np.sqrt(dx ** 2 + dy ** 2) / dt direction = np.degrees(np.arctan2(dy, dx)) self.speeds.append(speed) self.directions.append(direction) self.positions.append((x, y, time)) self.last_update = time self.active = True def get_current_speed(self): return np.mean(self.speeds[-3:]) if len(self.speeds) > 0 else 0 def get_current_direction(self): if len(self.directions) > 0: return self.directions[-1] return None tracks = [] next_id = 1 def play_anti_mosquito_sound(): if system_state.auto_sound and mosquito_sound: current_time = time.time() if current_time - system_state.last_sound_time > 5: try: mosquito_sound.play() system_state.last_sound_time = current_time system_state.sound_playing = True except Exception as e: print(f"播放音频失败: {e}") def take_screenshot(): screenshot_dir = "screenshots" if not os.path.exists(screenshot_dir): os.makedirs(screenshot_dir) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{screenshot_dir}/screenshot_{system_state.screenshot_count}_{timestamp}.png" plt.savefig(filename) system_state.screenshot_count += 1 print(f"截图已保存: {filename}") def update_radar(frame): global current_angle, r, mosquito_count, max_mosquito_count global false_positives, true_positives, tracks, next_id global scan_arc, scan_arc_fill, trail_lines current_time = time.time() # 转换为灰度图像 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 应用背景减法检测运动 fgmask = fgbg.apply(gray) # 形态学操作 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel) # 寻找轮廓 contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 检测到的蚊子位置 current_detections = [] mosquito_info = [] for contour in contours: area = cv2.contourArea(contour) perimeter = cv2.arcLength(contour, True) if 5 < area < 150 and perimeter > 10: (x, y), radius = cv2.minEnclosingCircle(contour) if 2 < radius < 20: circularity = 4 * np.pi * area / (perimeter ** 2) if perimeter > 0 else 0 if circularity > 0.5: center_x = x - frame.shape[1] // 2 center_y = y - frame.shape[0] // 2 angle = np.arctan2(center_y, center_x) % (2 * np.pi) distance = np.sqrt(center_x ** 2 + center_y ** 2) distance = min(distance, max_distance) current_detections.append((x, y, angle, distance, area, radius)) # 多目标跟踪 active_tracks = [t for t in tracks if t.active] matched = [False] * len(current_detections) for track in active_tracks: min_dist = float('inf') best_match = None for i, (x, y, _, _, _, _) in enumerate(current_detections): if not matched[i]: last_x, last_y, _ = track.positions[-1] dist = np.sqrt((x - last_x) ** 2 + (y - last_y) ** 2) if dist < 50 and dist < min_dist: min_dist = dist best_match = i if best_match is not None: x, y, angle, distance, area, radius = current_detections[best_match] track.update(x, y, current_time) matched[best_match] = True mosquito_info.append((angle, distance, track)) true_positives += 1 else: false_positives += 1 # 创建新轨迹 for i, (x, y, angle, distance, area, radius) in enumerate(current_detections): if not matched[i]: new_track = MosquitoTrack(next_id, x, y, current_time) tracks.append(new_track) mosquito_info.append((angle, distance, new_track)) next_id += 1 system_state.total_detected += 1 system_state.detected_today += 1 # 标记不活跃的轨迹 for track in active_tracks: if current_time - track.last_update > 0.5: track.active = False # 更新雷达数据 mosquito_count = len([t for t in tracks if t.active]) max_mosquito_count = max(max_mosquito_count, mosquito_count) # 播放驱蚊声 if mosquito_count > 0: play_anti_mosquito_sound() # 更新扫描线效果 current_angle = (current_angle + scan_speed * 2) % 360 # 加快扫描速度 scan_rad = np.radians(current_angle) # 主扫描线 scan_line.set_data([scan_rad, scan_rad], [0, max_distance]) # 扫描线尾迹 trail_length = 30 trail_angles = np.linspace(scan_rad - np.radians(trail_length), scan_rad, 10) scan_shadow.set_data(trail_angles, [max_distance] * 10) # 更新扇形扫描区域 if scan_arc is not None: scan_arc.remove() if scan_arc_fill is not None: scan_arc_fill.remove() scan_width = 30 scan_start = np.radians(current_angle - scan_width) % (2 * np.pi) scan_end = np.radians(current_angle + scan_width) % (2 * np.pi) # 扇形边框 scan_theta = np.linspace(scan_start, scan_end, 50) scan_arc = ax_radar.plot(scan_theta, [max_distance] * 50, color='lime', alpha=0.5, linewidth=1)[0] # 扇形填充(渐变效果) scan_r = np.linspace(0, max_distance, 50) scan_theta, scan_r = np.meshgrid(scan_theta, scan_r) scan_theta = scan_theta.flatten() scan_r = scan_r.flatten() angle_diff = np.abs((np.degrees(scan_theta) - current_angle + 180) % 360 - 180) alphas = np.where(angle_diff < scan_width, 1 - angle_diff / scan_width, 0) colors = np.zeros((len(scan_theta), 4)) colors[:, 1] = 1.0 colors[:, 3] = alphas * 0.1 scan_arc_fill = ax_radar.scatter(scan_theta, scan_r, c=colors, s=2, edgecolors='none', zorder=0) # 更新蚊子标记 if mosquito_info: angles, distances, tracks_info = zip(*mosquito_info) sizes = [50 + 30 * math.sin(time.time() * 10)] * len(angles) # 脉冲效果 colors = ['red' if t.active else 'orange' for t in tracks_info] mosquito_dots.set_offsets(np.column_stack([angles, distances])) mosquito_dots.set_sizes(sizes) mosquito_dots.set_color(colors) else: mosquito_dots.set_offsets(np.empty((0, 2))) # 更新轨迹线 for line in trail_lines: line.remove() trail_lines = [] if mosquito_info: for angle, distance, track in mosquito_info: if len(track.positions) > 1: # 主轨迹线 history_angles = [] history_distances = [] for i in range(max(0, len(track.positions) - 5), len(track.positions)): x, y, _ = track.positions[i] center_x = x - frame.shape[1] // 2 center_y = y - frame.shape[0] // 2 angle = np.arctan2(center_y, center_x) % (2 * np.pi) distance = np.sqrt(center_x ** 2 + center_y ** 2) history_angles.append(angle) history_distances.append(distance) if len(history_angles) > 1: # 主轨迹线 main_line = ax_radar.plot(history_angles, history_distances, color='cyan', alpha=0.7, linewidth=1.5, zorder=5)[0] trail_lines.append(main_line) # 轨迹尾迹 trail_alpha = 0.3 for i in range(1, 4): if len(history_angles) > i: trail_line = ax_radar.plot( history_angles[-i - 1:-i], history_distances[-i - 1:-i], color='white', alpha=trail_alpha, linewidth=2 + i, zorder=4 - i)[0] trail_lines.append(trail_line) trail_alpha *= 0.7 # 更新信息面板 accuracy = true_positives / (true_positives + false_positives) * 100 if ( true_positives + false_positives) > 0 else 0 info_texts[0].set_text(f"状态: 运行中") info_texts[1].set_text(f"扫描中") info_texts[2].set_text(f"摄像头: 开启") info_texts[3].set_text(f"启动: {system_state.start_time.strftime('%H:%M:%S')}") info_texts[4].set_text(f"当前: {mosquito_count}") info_texts[5].set_text(f"今日: {system_state.detected_today}") info_texts[6].set_text(f"最大: {max_mosquito_count}") info_texts[7].set_text( f"平均: {system_state.total_detected / ((time.time() - system_state.start_time.timestamp()) / 3600):.1f}/h") if mosquito_info: _, _, track = mosquito_info[0] speed = track.get_current_speed() direction = track.get_current_direction() dir_text = f"{direction:.1f}°" if direction is not None else "-" info_texts[8].set_text(f"速度: {speed:.1f} px/s") info_texts[9].set_text(f"大小: {track.positions[-1][2]:.1f} px") info_texts[10].set_text(f"方向: {dir_text}") info_texts[11].set_text(f"距离: {distance:.1f} cm") else: info_texts[8].set_text(f"速度: 0 px/s") info_texts[9].set_text(f"大小: 0 px") info_texts[10].set_text(f"方向: -") info_texts[11].set_text(f"距离: 0 cm") info_texts[12].set_text(f"追踪: {len(tracks)}") info_texts[13].set_text(f"历史: {system_state.total_detected}") info_texts[14].set_text(f"误报: {false_positives}") info_texts[15].set_text(f"准确率: {accuracy:.1f}%") sound_status = "开启" if system_state.auto_sound else "关闭" playing_status = "(播放中)" if system_state.sound_playing else "" info_texts[16].set_text(f"声波驱蚊: {sound_status} {playing_status}") info_texts[17].set_text(f"按A键切换") info_texts[18].set_text(f"截图: 按P键") return [scan_line, scan_shadow, mosquito_dots, scan_arc, scan_arc_fill, *trail_lines, *info_texts] # 创建动画 def update(frame): ret, frame = cap.read() if not ret: return [] frame = cv2.flip(frame, 1) # 灰度处理与边缘检测 gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray_frame, (5, 5), 0) edges = cv2.Canny(blurred, EDGE_THRESHOLD1, EDGE_THRESHOLD2) # 寻找轮廓 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 创建空白图像用于绘制轮廓 edge_display = np.zeros_like(frame) cv2.drawContours(edge_display, contours, -1, (0, 255, 0), 1) artists = update_radar(frame) # 显示窗口 cv2.imshow('Mosquito Tracking', cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) cv2.imshow('Edges', edge_display) # 显示轮廓绘制结果 key = cv2.waitKey(1) if key & 0xFF == ord('q'): ani.event_source.stop() cap.release() cv2.destroyAllWindows() plt.close('all') return [] elif key & 0xFF == ord('a'): system_state.auto_sound = not system_state.auto_sound elif key & 0xFF == ord('p'): take_screenshot() if system_state.sound_playing and not pygame.mixer.get_busy(): system_state.sound_playing = False return artists # 开始动画 try: # 启动时自动播放一次声波 if system_state.auto_sound and mosquito_sound: mosquito_sound.play() system_state.sound_playing = True system_state.last_sound_time = time.time() ani = FuncAnimation(fig, update, frames=None, interval=30, blit=True, cache_frame_data=False) plt.tight_layout() plt.show() except Exception as e: print(f"程序错误: {e}") finally: if 'cap' in locals() and cap.isOpened(): cap.release() cv2.destroyAllWindows() plt.close('all')
版权说明
文章采用: 《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权。版权声明:未标注转载均为本站原创,转载时请以链接形式注明文章出处。如有侵权、不妥之处,请联系站长删除。敬请谅解!