218 lines
6.0 KiB
Plaintext
218 lines
6.0 KiB
Plaintext
{
|
||
"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
|
||
}
|