{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "857f6a30", "metadata": {}, "outputs": [], "source": [ "import cv2\n", "import numpy as np\n", "from mss import mss\n", "\n", "class FrameDiffProcessor:\n", " def __init__(self):\n", " self.prev_frame = None\n", " self.threshold = 25 # 差异阈值(0-255)\n", " self.min_contour_area = 100 # 最小变化区域面积(像素)\n", "\n", " def _preprocess(self, frame):\n", " \"\"\"预处理:转为灰度图并高斯模糊\"\"\"\n", " gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n", " return cv2.GaussianBlur(gray, (21, 21), 0)\n", "\n", " def _get_diff_rects(self, current_frame):\n", " \"\"\"计算差异区域边界框\"\"\"\n", " # 计算绝对差异并二值化\n", " diff = cv2.absdiff(self.prev_frame, current_frame)\n", " mean_diff = np.mean(diff)\n", " dynamic_threshold = max(15, min(mean_diff * 0.7, 50))\n", " _, thresh = cv2.threshold(diff, dynamic_threshold, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU )\n", " \n", " # 查找轮廓\n", " contours, _2 = cv2.findContours(\n", " thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE\n", " )\n", " \n", " # 过滤小面积区域\n", " rects = []\n", " for cnt in contours:\n", " if cv2.contourArea(cnt) > self.min_contour_area:\n", " x, y, w, h = cv2.boundingRect(cnt)\n", " rects.append((x, y, x + w, y + h)) # (x1,y1,x2,y2)\n", " cv2.imshow(\"Debug: Prev|Current|Diff|Thresh\", debug_img)\n", " return rects\n", "\n", " def process(self, frame):\n", " \"\"\"主处理流程\"\"\"\n", " processed = self._preprocess(frame)\n", " if self.prev_frame is None:\n", " self.prev_frame = processed\n", " return None # 首帧不处理\n", " \n", " rects = self._get_diff_rects(processed)\n", " self.prev_frame = processed # 更新前一帧\n", " \n", " return rects" ] }, { "cell_type": "code", "execution_count": 17, "id": "6ce9c8d7", "metadata": {}, "outputs": [], "source": [ "sct = mss()\n", "m1 = sct.monitors[1]" ] }, { "cell_type": "code", "execution_count": 18, "id": "5b3dde01", "metadata": {}, "outputs": [], "source": [ "sct_img = sct.grab(m1)\n", "frame = np.array(sct_img)" ] }, { "cell_type": "code", "execution_count": 19, "id": "128102cf", "metadata": {}, "outputs": [], "source": [ "sct_img2 = sct.grab(m1)\n", "frame2 = np.array(sct_img2)" ] }, { "cell_type": "code", "execution_count": 20, "id": "225bdfb5", "metadata": {}, "outputs": [], "source": [ "diff_processor = FrameDiffProcessor()" ] }, { "cell_type": "code", "execution_count": 21, "id": "ab333ef4", "metadata": {}, "outputs": [], "source": [ "diff_processor.process(frame)" ] }, { "cell_type": "code", "execution_count": 22, "id": "714efc64", "metadata": {}, "outputs": [], "source": [ "rect = diff_processor.process(frame2)" ] }, { "cell_type": "code", "execution_count": 24, "id": "e59dc64f", "metadata": {}, "outputs": [], "source": [ "img3= frame2.copy() \n", "for item in rect:\n", " x1, y1, x2, y2 = item\n", " cv2.rectangle(img3, (x1, y1), (x2, y2), (0, 255, 0), 2)\n", "cv2.imshow(\"Result\", img3)\n", "cv2.waitKey(0)\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "code", "execution_count": 25, "id": "e9519185", "metadata": {}, "outputs": [], "source": [ "cv2.imshow(\"Result\", frame)\n", "cv2.waitKey(0)\n", "cv2.destroyAllWindows()\n", "cv2.imshow(\"Result\", frame2)\n", "cv2.waitKey(0)\n", "cv2.destroyAllWindows()" ] }, { "cell_type": "code", "execution_count": 26, "id": "5ccd739c", "metadata": {}, "outputs": [], "source": [ "# async def send_screen(websocket):\n", "# sct = mss()\n", "# monitor = sct.monitors[1]\n", "# diff_processor = FrameDiffProcessor()\n", " \n", "# while True:\n", "# # 捕获原始帧\n", "# sct_img = sct.grab(monitor)\n", "# frame = np.array(sct_img)\n", " \n", "# # 计算差异区域\n", "# diff_rects = diff_processor.process(frame)\n", " \n", "# if diff_rects:\n", "# # 提取变化区域并压缩\n", "# payload = []\n", "# for (x1, y1, x2, y2) in diff_rects:\n", "# roi = frame[y1:y2, x1:x2] # 截取变化区域\n", "# _, buffer = cv2.imencode('.jpg', roi, [cv2.IMWRITE_JPEG_QUALITY, 85])\n", "# payload.append({\n", "# 'x': x1,\n", "# 'y': y1,\n", "# 'data': buffer.tobytes()\n", "# })\n", " \n", "# # 序列化并发送\n", "# await websocket.send(json.dumps(payload))\n", "# else:\n", "# # 无变化时发送心跳包\n", "# await websocket.send(\"no_change\")\n", " \n", "# await asyncio.sleep(0.05) # 控制帧率" ] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.4" } }, "nbformat": 4, "nbformat_minor": 5 }