欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

一个简单的网络摄像头应用程序 6

最编程 2024-10-06 19:24:18
...
import cv2 import os import numpy as np from PIL import Image, ImageDraw, ImageFont import datetime import webbrowser import logging import concurrent.futures import queue # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # 检查并创建保存照片和视频的文件夹 def create_folder(folder_name): if not os.path.exists(folder_name): os.makedirs(folder_name) return folder_name # 获取文件夹中的最大编号 def get_next_file_number(folder_name, file_extension): files = os.listdir(folder_name) files = [f for f in files if f.endswith(file_extension)] if files: numbers = [int(f.split('.')[0]) for f in files] return max(numbers) + 1 else: return 1 # 将PIL图像转换为OpenCV图像 def pil_to_cv(image): return cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) # 自动曝光调整 def auto_exposure(frame, exposure_value): frame = cv2.convertScaleAbs(frame, alpha=exposure_value, beta=0) return frame # 自动对焦 def auto_focus(frame): gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) laplacian = cv2.Laplacian(gray, cv2.CV_64F).var() if laplacian < 100: # 如果图像模糊,进行对焦 frame = cv2.fastNlMeansDenoisingColored(frame, None, 10, 10, 7, 21) return frame # 鼠标回调函数 def mouse_callback(event, x, y, flags, param): global next_photo_number, next_video_number, running, recording, out, frame, scale_factor, cam_index, roi, button_hints, show_buttons, show_help, frame_width, frame_height button_width = int(frame_width * 0.05) # 按钮区域宽度占界面宽度的1/20 button_height = 40 # 每个按钮的高度 if event == cv2.EVENT_LBUTTONDOWN: if 10 <= x <= button_width and 10 <= y <= 50: # 关闭按钮区域 running = False elif 10 <= x <= button_width and 70 <= y <= 70 + button_height: # 拍照按钮区域 threading.Thread(target=save_photo, args=(frame.copy(), next_photo_number)).start() next_photo_number += 1 elif 10 <= x <= button_width and 120 <= y <= 120 + button_height: # 开始/停止录像按钮区域 if not recording: start_recording() else: stop_recording() elif 10 <= x <= button_width and 170 <= y <= 170 + button_height: # 放大按钮区域 scale_factor = min(3.0, scale_factor * 2) elif 10 <= x <= button_width and 220 <= y <= 220 + button_height: # 缩小按钮区域 scale_factor = max(1.0, scale_factor / 2) elif 10 <= x <= button_width and 270 <= y <= 270 + button_height: # 切换摄像头按钮区域 switch_camera() elif 10 <= x <= button_width and 320 <= y <= 320 + button_height: # 查看照片按钮区域 open_photo_folder() elif 10 <= x <= button_width and 370 <= y <= 370 + button_height: # 查看视频按钮区域 open_video_folder() elif 10 <= x <= button_width and 420 <= y <= 420 + button_height: # 去除噪点按钮区域 apply_denoise() elif 10 <= x <= button_width and 470 <= y <= 470 + button_height: # 功能菜单按钮区域 show_buttons = not show_buttons elif 10 <= x <= button_width and 520 <= y <= 520 + button_height: # 功能说明按钮区域 show_help = not show_help elif event == cv2.EVENT_RBUTTONDOWN: roi[0], roi[1] = x, y elif event == cv2.EVENT_RBUTTONUP: roi[2], roi[3] = x - roi[0], y - roi[1] if roi[2] < 0: roi[0] += roi[2] roi[2] = -roi[2] if roi[3] < 0: roi[1] += roi[3] roi[3] = -roi[3] elif event == cv2.EVENT_MOUSEMOVE: button_hints = [] button_width = int(frame_width * 0.05) # 按钮区域宽度占界面宽度的1/20 button_height = 40 # 每个按钮的高度 if 10 <= x <= button_width and 10 <= y <= 50: button_hints.append("关闭") elif 10 <= x <= button_width and 70 <= y <= 70 + button_height: button_hints.append("拍照") elif 10 <= x <= button_width and 120 <= y <= 120 + button_height: button_hints.append("录像") elif 10 <= x <= button_width and 170 <= y <= 170 + button_height: button_hints.append("放大") elif 10 <= x <= button_width and 220 <= y <= 220 + button_height: button_hints.append("缩小") elif 10 <= x <= button_width and 270 <= y <= 270 + button_height: button_hints.append("切换摄像头") elif 10 <= x <= button_width and 320 <= y <= 320 + button_height: button_hints.append("查看照片") elif 10 <= x <= button_width and 370 <= y <= 370 + button_height: button_hints.append("查看视频") elif 10 <= x <= button_width and 420 <= y <= 420 + button_height: button_hints.append("去除噪点") elif 10 <= x <= button_width and 470 <= y <= 470 + button_height: button_hints.append("功能菜单") elif 10 <= x <= button_width and 520 <= y <= 520 + button_height: button_hints.append("功能说明") # 保存照片 def save_photo(frame, photo_number): file_path = os.path.join(photo_folder, f"{photo_number}.jpg") # 去除界面上的按钮 clean_frame = remove_buttons(frame) # 裁剪区域 clean_frame = clean_frame[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2]] # 添加时间戳 clean_frame = add_timestamp(clean_frame) try: cv2.imwrite(file_path, clean_frame) logging.info(f"照片已保存为 {file_path}") except Exception as e: logging.error(f"保存照片时出错: {e}") # 去除界面上的按钮 def remove_buttons(frame): pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_image) button_width = int(frame_width * 0.05) # 按钮区域宽度占界面宽度的1/20 draw.rectangle((0, 0, button_width, frame_height), fill=(0, 0, 0, 0)) # 透明填充 return pil_to_cv(pil_image) # 添加时间戳 def add_timestamp(image): now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_image) draw.text((10, 10), now, font=font, fill=(255, 255, 255)) return pil_to_cv(pil_image) # 开始录像 def start_recording(): global out, recording, frame file_path = os.path.join(video_folder, f"{next_video_number}.mp4") fourcc = cv2.VideoWriter_fourcc(*'XVID') out = cv2.VideoWriter(file_path, fourcc, 20.0, (roi[2], roi[3])) recording = True logging.info(f"开始录像: {file_path}") # 停止录像 def stop_recording(): global out, recording try: out.release() recording = False logging.info("录像已保存") except Exception as e: logging.error(f"停止录像时出错: {e}") # 切换摄像头 def switch_camera(): global cap, cam_index cap.release() cam_index = (cam_index + 1) % 2 # 切换到下一个摄像头 cap = cv2.VideoCapture(cam_index) if not cap.isOpened(): logging.error("无法打开摄像头") running = False # 打开照片文件夹 def open_photo_folder(): folder_path = os.path.abspath(photo_folder) webbrowser.open(folder_path) # 打开视频文件夹 def open_video_folder(): folder_path = os.path.abspath(video_folder) webbrowser.open(folder_path) # 应用去噪点滤镜 def apply_denoise(): global filter_type filter_type = "denoise" # 绘制按钮 def draw_buttons(pil_image, font, show_buttons): draw = ImageDraw.Draw(pil_image) button_width = int(frame_width * 0.05) # 按钮区域宽度占界面宽度的1/20 button_height = 40 # 每个按钮的高度 buttons = [ ((10, 10, button_width, 50), "关闭", (0, 0, 255)), ((10, 70, button_width, 70 + button_height), "拍照", (255, 0, 0)), ((10, 120, button_width, 120 + button_height), "录像", (0, 255, 0)), ((10, 170, button_width, 170 + button_height), "放大", (0, 255, 255)), ((10, 220, button_width, 220 + button_height), "缩小", (0, 255, 255)), ((10, 270, button_width, 270 + button_height), "切换摄像头", (255, 255, 0)), ((10, 320, button_width, 320 + button_height), "查看照片", (255, 165, 0)), ((10, 370, button_width, 370 + button_height), "查看视频", (255, 165, 0)), ((10, 420, button_width, 420 + button_height), "去除噪点", (255, 165, 0)), ((10, 470, button_width, 470 + button_height), "功能菜单", (255, 165, 0)), ((10, 520, button_width, 520 + button_height), "功能说明", (255, 165, 0)) ] for (x1, y1, x2, y2), text, color in buttons: if show_buttons or y1 >= 470: draw.rectangle((x1, y1, x2, y2), fill=color) draw.text((x1 + 10, y1 + 10), text, font=font, fill=(255, 255, 255)) # 绘制提示信息 def draw_hints(pil_image, hints, font): draw = ImageDraw.Draw(pil_image) button_width = int(frame_width * 0.05) # 按钮区域宽度占界面宽度的1/20 for i, hint in enumerate(hints): draw.text((10, frame_height - 10 - (i + 1) * 30), hint, font=font, fill=(0, 255, 0)) # 绘制功能说明 def draw_help(pil_image, font): draw = ImageDraw.Draw(pil_image) help_text = [ "功能说明:", "q: 退出程序", "g: 应用灰度滤镜", "b: 应用模糊滤镜", "r: 恢复原图", "功能菜单: 显示/隐藏功能按钮", "功能说明: 显示/隐藏功能说明" ] for i, text in enumerate(help_text): draw.text((10, 10 + i * 30), text, font=font, fill=(255, 255, 255)) # 应用图像滤镜 def apply_filter(image, filter_type): if filter_type == "grayscale": return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) elif filter_type == "blur": return cv2.GaussianBlur(image, (15, 15), 0) elif filter_type == "denoise": return cv2.fastNlMeansDenoisingColored(image, None, denoise_strength, 10, 7, 21) return image # 处理图像的线程 def process_frame(frame, exposure_value, filter_type, scale_factor, roi, result_queue): frame = auto_exposure(frame, exposure_value)

推荐阅读