{
 "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
}
