用tensorflow实现cv2.blur

import cv2 import numpy as np import time import logging import argparse # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger('OpticalTweezerVideoTester') class OpticalTweezerVideoTester: def __init__(self, video_path, output_path=None): # 视频文件路径 self.video_path = video_path # 输出设置 self.output_path = output_path self.video_writer = None # 处理参数 self.min_radius = 10 self.max_radius = 70 self.blur_size = (9, 9) self.pixel_to_micron = 0.1 # 分析结果存储 self.trajectories = {} # {track_id: [(frame_idx, x, y, radius), ...]} self.next_track_id = 1 self.current_frame_idx = 0 # 性能监控 self.frame_count = 0 self.start_time = time.time() self.processing_times = [] # 创建调参窗口 cv2.namedWindow('Parameters') cv2.createTrackbar('Min Radius', 'Parameters', self.min_radius, 100, self.on_trackbar) cv2.createTrackbar('Max Radius', 'Parameters', self.max_radius, 200, self.on_trackbar) cv2.createTrackbar('Blur Size', 'Parameters', self.blur_size[0], 30, self.on_trackbar) def initialize_video(self): """初始化视频捕获""" self.cap = cv2.VideoCapture(self.video_path) if not self.cap.isOpened(): logger.error(f"无法打开视频文件: {self.video_path}") raise RuntimeError("视频初始化失败") # 获取视频属性 self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) self.fps = self.cap.get(cv2.CAP_PROP_FPS) self.frame_count = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) logger.info(f"视频属性: {self.width}x{self.height} @ {self.fps:.1f} FPS, 总帧数: {self.frame_count}") # 初始化视频写入器 if self.output_path: fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 使用MP4V编解码器 self.video_writer = cv2.VideoWriter( self.output_path, fourcc, self.fps, (self.width, self.height) ) if not self.video_writer.isOpened(): logger.warning("无法创建输出视频文件") return True def on_trackbar(self, value): """实时参数调整的回调函数""" self.min_radius = cv2.getTrackbarPos('Min Radius', 'Parameters') self.max_radius = cv2.getTrackbarPos('Max Radius', 'Parameters') blur_value = cv2.getTrackbarPos('Blur Size', 'Parameters') self.blur_size = (blur_value if blur_value % 2 != 0 else blur_value + 1, blur_value if blur_value % 2 != 0 else blur_value + 1) def detect_spheres(self, frame): """优化的小球检测算法""" # 转为灰度图并应用CLAHE增强对比度 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) enhanced = clahe.apply(gray) # 高斯模糊降噪 blurred = cv2.GaussianBlur(enhanced, self.blur_size, 0) # 使用自适应阈值 thresh = cv2.adaptiveThreshold( blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # 形态学操作优化 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) cleaned = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) # 轮廓检测 contours, _ = cv2.findContours(cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) positions = [] for cnt in contours: area = cv2.contourArea(cnt) # 跳过过小的区域 if area < 30: continue # 最小包围圆检测 (x, y), radius = cv2.minEnclosingCircle(cnt) radius = int(radius) # 半径过滤 if self.min_radius <= radius <= self.max_radius: positions.append((int(x), int(y), radius)) return positions def track_spheres(self, positions): """简单的小球追踪""" if not hasattr(self, 'previous_positions'): # 第一帧,初始化所有轨迹 self.previous_positions = {} for pos in positions: track_id = self.next_track_id self.next_track_id += 1 self.trajectories[track_id] = [(self.current_frame_idx, pos[0], pos[1], pos[2])] self.previous_positions[track_id] = (pos[0], pos[1]) return # 创建当前帧的跟踪列表 current_tracks = {} # 为每个检测点寻找最近的已有轨迹 for pos in positions: min_dist = float('inf') matched_id = None for track_id, prev_pos in self.previous_positions.items(): dist = np.sqrt((pos[0] - prev_pos[0])**2 + (pos[1] - prev_pos[1])**2) # 最大移动距离阈值(像素) if dist < 50 and dist < min_dist: min_dist = dist matched_id = track_id if matched_id: # 更新现有轨迹 self.trajectories[matched_id].append((self.current_frame_idx, pos[0], pos[1], pos[2])) current_tracks[matched_id] = (pos[0], pos[1]) else: # 创建新轨迹 track_id = self.next_track_id self.next_track_id += 1 self.trajectories[track_id] = [(self.current_frame_idx, pos[0], pos[1], pos[2])] current_tracks[track_id] = (pos[0], pos[1]) # 更新上一帧位置 self.previous_positions = current_tracks def visualize(self, frame, positions): """增强可视化功能""" display_frame = frame.copy() # 绘制检测到的小球 for (x, y, r) in positions: # 绘制小球和中心点 cv2.circle(display_frame, (x, y), r, (0, 255, 0), 2) cv2.circle(display_frame, (x, y), 2, (0, 0, 255), 3) # 显示物理尺寸 phys_x = x * self.pixel_to_micron phys_y = y * self.pixel_to_micron txt = f"({phys_x:.1f}μm, {phys_y:.1f}μm)" cv2.putText(display_frame, txt, (x + 10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1) # 显示当前帧信息 elapsed_time = time.time() - self.start_time fps = self.frame_count / elapsed_time if elapsed_time > 0 else 0 avg_time = np.mean(self.processing_times) * 1000 if self.processing_times else 0 info_y = 30 cv2.putText(display_frame, f"Frame: {self.current_frame_idx}/{self.frame_count}", (10, info_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) cv2.putText(display_frame, f"FPS: {fps:.1f}", (10, info_y+30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) cv2.putText(display_frame, f"Spheres: {len(positions)}", (10, info_y+60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) cv2.putText(display_frame, f"Proc Time: {avg_time:.1f}ms", (10, info_y+90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) # 添加进度条 progress = int(self.current_frame_idx / self.frame_count * self.width) cv2.rectangle(display_frame, (0, self.height-15), (progress, self.height), (0, 255, 0), -1) return display_frame def save_analysis_results(self): """保存分析结果到文件""" if not self.trajectories: logger.warning("没有检测到轨迹,跳过保存") return timestamp = time.strftime("%Y%m%d_%H%M%S") filename = f"analysis_{timestamp}.csv" with open(filename, 'w') as f: # 写入CSV文件头 f.write("TrackID,Frame,X(px),Y(px),Radius(px),X(um),Y(um),Radius(um)\n") for track_id, positions in self.trajectories.items(): for frame_idx, x, y, r in positions: # 转换为物理单位 phys_x = x * self.pixel_to_micron phys_y = y * self.pixel_to_micron phys_r = r * self.pixel_to_micron f.write(f"{track_id},{frame_idx},{x},{y},{r},{phys_x:.2f},{phys_y:.2f},{phys_r:.2f}\n") logger.info(f"分析结果已保存到 {filename}") def run(self): """视频处理主循环""" try: self.initialize_video() logger.info("开始视频分析...") pause = False while self.cap.isOpened(): if not pause: start_time = time.time() # 读取帧 ret, frame = self.cap.read() if not ret: logger.info("视频处理完成") break # 处理当前帧 positions = self.detect_spheres(frame) self.track_spheres(positions) # 可视化 display_frame = self.visualize(frame, positions) # 记录处理时间 proc_time = time.time() - start_time self.processing_times.append(proc_time) # 保存处理后的帧 if self.video_writer: self.video_writer.write(display_frame) # 显示处理后的帧 cv2.imshow("Optical Tweezer Video Analysis", display_frame) # 更新帧计数 self.current_frame_idx += 1 # 按键处理 key = cv2.waitKey(1) & 0xFF if key == 27: # ESC键 - 退出 break elif key == ord(' '): # 空格键 - 暂停/继续 pause = not pause elif key == ord('s'): # 保存当前帧 cv2.imwrite(f"frame_{self.current_frame_idx}.png", frame) logger.info(f"保存第 {self.current_frame_idx} 帧") elif key == ord('a'): # 单步前进 pause = True # 人工单步前进 ret, frame = self.cap.read() if ret: positions = self.detect_spheres(frame) self.track_spheres(positions) display_frame = self.visualize(frame, positions) cv2.imshow("Optical Tweezer Video Analysis", display_frame) self.current_frame_idx += 1 elif key == ord('r'): # 重置视频 self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0) self.current_frame_idx = 0 self.trajectories = {} self.next_track_id = 1 logger.info("重置视频分析") # 保存分析结果 self.save_analysis_results() except Exception as e: logger.exception("发生未预期错误:") finally: self.cleanup() def cleanup(self): """资源清理""" if hasattr(self, 'cap'): self.cap.release() if self.video_writer: self.video_writer.release() cv2.destroyAllWindows() logger.info("系统资源已释放") def main(): # 设置命令行参数 parser = argparse.ArgumentParser(description='光学镊子系统视频测试工具') parser.add_argument('input', help='输入视频文件路径') parser.add_argument('-o', '--output', help='输出视频文件路径') args = parser.parse_args() try: logger.info("启动光学镊子系统视频测试...") tester = OpticalTweezerVideoTester( video_path=args.input, output_path=args.output ) tester.run() except Exception as e: logger.error(f"系统启动失败: {e}") if __name__ == "__main__": main() 加上机器学习,改写代码
最新发布
10-10
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值