马上注册,结交更多好友,享用更多功能,让你轻松玩转小K网。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
蚊子雷达追踪打击系统-源码奇葩软件千千万,我的工具占一半
打包及程序介绍见原创发布区
蚊子雷达追踪打击系统-源码
- 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')
复制代码
|
|