{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Лаба 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 199804 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img = cv.imread('img/coins.jpg', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "sift = cv.SIFT_create()\n",
    "\n",
    "kp, des = sift.detectAndCompute(img, None)\n",
    "\n",
    "img2 = cv.drawKeypoints(img, kp, None, (255, 0, 0), 4)\n",
    "plt.imshow(img2)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 205528 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 191500 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/df/d0c/tutorial_py_fast.html\n",
    "import cv2 as cv\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "img = cv.imread('img/blox.jpg', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "fast = cv.FastFeatureDetector_create()\n",
    "kp = fast.detect(img, None)\n",
    "img2 = cv.drawKeypoints(img, kp, None, color=(255, 0, 0))\n",
    "plt.imshow(img2)\n",
    "plt.show()\n",
    "\n",
    "fast.setNonmaxSuppression(0)\n",
    "kp = fast.detect(img, None)\n",
    "img3 = cv.drawKeypoints(img, kp, None, color=(255, 0, 0))\n",
    "plt.imshow(img3)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 100440 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# https://docs.opencv.org/3.4/dc/d7d/tutorial_py_brief.html\n",
    "import cv2 as cv\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "def brief_descriptor(image, keypoints, patch_size=31, pairs=256):\n",
    "    descriptors = []\n",
    "    for kp in keypoints:\n",
    "        x, y = int(kp.pt[0]), int(kp.pt[1])\n",
    "        patch = image[y - patch_size // 2:y + patch_size // 2 + 1,\n",
    "                      x - patch_size // 2:x + patch_size // 2 + 1]\n",
    "        if patch.shape != (patch_size, patch_size):\n",
    "            continue\n",
    "        patch = cv.GaussianBlur(patch, (5, 5), 0)\n",
    "        desc = []\n",
    "        for _ in range(pairs):\n",
    "            p1 = np.random.randint(0, patch_size, 2)\n",
    "            p2 = np.random.randint(0, patch_size, 2)\n",
    "            desc.append(1 if patch[p1[0], p1[1]] < patch[p2[0], p2[1]] else 0)\n",
    "        descriptors.append(desc)\n",
    "    return np.array(descriptors, dtype=np.uint8)\n",
    "\n",
    "img = cv.imread('img/blox.jpg', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "fast = cv.FastFeatureDetector_create()\n",
    "keypoints = fast.detect(img, None)\n",
    "descriptors = brief_descriptor(img, keypoints)\n",
    "\n",
    "img_with_circles = img.copy()\n",
    "for kp in keypoints:\n",
    "    x, y = int(kp.pt[0]), int(kp.pt[1])\n",
    "    radius = int(kp.size / 2)\n",
    "    cv.circle(img_with_circles, (x, y), radius, (255, 0, 0), 2)\n",
    "\n",
    "plt.imshow(img_with_circles, cmap='gray')\n",
    "plt.axis('off')\n",
    "plt.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Лаба 11"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(290, 32)\n",
      "Descriptor size: 32 bytes (default for BRIEF)\n",
      "Descriptor shape: (290, 32)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 138628 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/d1/d89/tutorial_py_orb.html\n",
    "import cv2 as cv\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "img = cv.imread('img/blox.jpg', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "orb = cv.ORB_create()\n",
    "kp, des = orb.detectAndCompute(img, None)\n",
    "\n",
    "print(des.shape)\n",
    "print(f\"Descriptor size: {des.shape[1]} bytes (default for BRIEF)\")\n",
    "print(f\"Descriptor shape: {des.shape}\")\n",
    "img_with_keypoints = cv.drawKeypoints(img, kp, None, color=(255, 0, 0))\n",
    "plt.imshow(img_with_keypoints)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 179236 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/dc/dc3/tutorial_py_matcher.html\n",
    "import cv2 as cv\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img1 = cv.imread('img/box.png', cv.IMREAD_GRAYSCALE)\n",
    "img2 = cv.imread('img/box_in_scene.png', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "orb = cv.ORB_create()\n",
    "kp1, des1 = orb.detectAndCompute(img1, None)\n",
    "kp2, des2 = orb.detectAndCompute(img2, None)\n",
    "\n",
    "bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)\n",
    "matches = bf.match(des1, des2)\n",
    "matches = sorted(matches, key=lambda x: x.distance)\n",
    "\n",
    "img3 = cv.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)\n",
    "plt.imshow(img3)\n",
    "plt.axis('off')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 214348 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img1 = cv.imread('img/box.png', cv.IMREAD_GRAYSCALE)\n",
    "img2 = cv.imread('img/box_in_scene.png', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "sift = cv.SIFT_create()\n",
    "kp1, des1 = sift.detectAndCompute(img1, None)\n",
    "kp2, des2 = sift.detectAndCompute(img2, None)\n",
    "\n",
    "bf = cv.BFMatcher()\n",
    "matches = bf.knnMatch(des1, des2, k=2)\n",
    "\n",
    "good_matches = []\n",
    "for m, n in matches:\n",
    "    if m.distance < 0.75 * n.distance:\n",
    "        good_matches.append([m])\n",
    "\n",
    "img3 = cv.drawMatchesKnn(img1, kp1, img2, kp2, good_matches, None, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)\n",
    "plt.imshow(img3)\n",
    "plt.axis('off')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 250744 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img1 = cv.imread('img/box.png', cv.IMREAD_GRAYSCALE)\n",
    "img2 = cv.imread('img/box_in_scene.png', cv.IMREAD_GRAYSCALE)\n",
    "\n",
    "sift = cv.SIFT_create()\n",
    "kp1, des1 = sift.detectAndCompute(img1, None)\n",
    "kp2, des2 = sift.detectAndCompute(img2, None)\n",
    "\n",
    "FLANN_INDEX_KDTREE = 1\n",
    "index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)\n",
    "search_params = dict(checks=50)\n",
    "flann = cv.FlannBasedMatcher(index_params, search_params)\n",
    "\n",
    "matches = flann.knnMatch(des1, des2, k=2)\n",
    "\n",
    "matchesMask = [[0, 0] for _ in range(len(matches))]\n",
    "for i, (m, n) in enumerate(matches):\n",
    "    if m.distance < 0.7 * n.distance:\n",
    "        matchesMask[i] = [1, 0]\n",
    "\n",
    "draw_params = dict(matchColor=(0, 255, 0),\n",
    "                   singlePointColor=(255, 0, 0),\n",
    "                   matchesMask=matchesMask,\n",
    "                   flags=cv.DrawMatchesFlags_DEFAULT)\n",
    "\n",
    "img3 = cv.drawMatchesKnn(img1, kp1, img2, kp2, matches, None, **draw_params)\n",
    "plt.imshow(img3)\n",
    "plt.axis('off')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Краткое описание методов:\n",
    "\n",
    "    Brute-Force Matching с ORB:\n",
    "        Используется Hamming Distance для бинарных дескрипторов.\n",
    "        Подходит для ORB, BRIEF, BRISK.\n",
    "\n",
    "    Brute-Force Matching с SIFT:\n",
    "        Используется L2 расстояние для вещественных дескрипторов.\n",
    "        Применяется knnMatch и тест отношения Дэвида Лоу (Ratio Test).\n",
    "\n",
    "    FLANN Matcher:\n",
    "        Быстрее для больших наборов данных.\n",
    "        Использует K-D деревья для вещественных дескрипторов (например, SIFT, SURF).\n",
    "        Использует LSH для бинарных дескрипторов (например, ORB)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 209780 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/d1/de0/tutorial_py_feature_homography.html\n",
    "import numpy as np\n",
    "import cv2 as cv\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "MIN_MATCH_COUNT = 10\n",
    "\n",
    "img1 = cv.imread('img/box.png', cv.IMREAD_GRAYSCALE)  # queryImage\n",
    "img2 = cv.imread('img/box_in_scene.png', cv.IMREAD_GRAYSCALE)  # trainImage\n",
    "\n",
    "sift = cv.SIFT_create()\n",
    "\n",
    "kp1, des1 = sift.detectAndCompute(img1, None)\n",
    "kp2, des2 = sift.detectAndCompute(img2, None)\n",
    "\n",
    "FLANN_INDEX_KDTREE = 1\n",
    "index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)\n",
    "search_params = dict(checks=50)\n",
    "\n",
    "flann = cv.FlannBasedMatcher(index_params, search_params)\n",
    "\n",
    "matches = flann.knnMatch(des1, des2, k=2)\n",
    "\n",
    "good = []\n",
    "for m, n in matches:\n",
    "    if m.distance < 0.7 * n.distance:\n",
    "        good.append(m)\n",
    "\n",
    "if len(good) > MIN_MATCH_COUNT:\n",
    "    src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)\n",
    "    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)\n",
    "\n",
    "    M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)\n",
    "    matchesMask = mask.ravel().tolist()\n",
    "\n",
    "    h, w = img1.shape\n",
    "    pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)\n",
    "    dst = cv.perspectiveTransform(pts, M)\n",
    "\n",
    "    img2 = cv.polylines(img2, [np.int32(dst)], True, 255, 3, cv.LINE_AA)\n",
    "else:\n",
    "    print(f\"Not enough matches are found - {len(good)}/{MIN_MATCH_COUNT}\")\n",
    "    matchesMask = None\n",
    "\n",
    "draw_params = dict(matchColor=(0, 255, 0),\n",
    "                   singlePointColor=None,\n",
    "                   matchesMask=matchesMask,\n",
    "                   flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)\n",
    "\n",
    "img3 = cv.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params)\n",
    "\n",
    "plt.imshow(img3, 'gray')\n",
    "plt.axis('off')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Лаба 12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "ename": "",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n",
      "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n",
      "\u001b[1;31mClick <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. \n",
      "\u001b[1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
     ]
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/db/d28/tutorial_cascade_classifier.html\n",
    "import cv2 as cv\n",
    "\n",
    "def detectAndDisplay(frame):\n",
    "    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)\n",
    "    frame_gray = cv.equalizeHist(frame_gray)\n",
    "\n",
    "    faces = face_cascade.detectMultiScale(frame_gray)\n",
    "    for (x, y, w, h) in faces:\n",
    "        center = (x + w // 2, y + h // 2)\n",
    "        frame = cv.ellipse(frame, center, (w // 2, h // 2), 0, 0, 360, (255, 0, 255), 4)\n",
    "\n",
    "        faceROI = frame_gray[y:y + h, x:x + w]\n",
    "        eyes = eyes_cascade.detectMultiScale(faceROI)\n",
    "        for (x2, y2, w2, h2) in eyes:\n",
    "            eye_center = (x + x2 + w2 // 2, y + y2 + h2 // 2)\n",
    "            radius = int(round((w2 + h2) * 0.25))\n",
    "            frame = cv.circle(frame, eye_center, radius, (255, 0, 0), 4)\n",
    "\n",
    "    cv.imshow('Capture - Face detection', frame)\n",
    "\n",
    "face_cascade = cv.CascadeClassifier()\n",
    "eyes_cascade = cv.CascadeClassifier()\n",
    "\n",
    "face_cascade_name = 'data/haarcascade_frontalface_alt.xml'\n",
    "eyes_cascade_name = 'data/haarcascade_eye_tree_eyeglasses.xml'\n",
    "\n",
    "if not face_cascade.load(cv.samples.findFile(face_cascade_name)):\n",
    "    print('--(!)Error loading face cascade')\n",
    "    exit(0)\n",
    "if not eyes_cascade.load(cv.samples.findFile(eyes_cascade_name)):\n",
    "    print('--(!)Error loading eyes cascade')\n",
    "    exit(0)\n",
    "\n",
    "cap = cv.VideoCapture(0)\n",
    "if not cap.isOpened():\n",
    "    print('--(!)Error opening video capture')\n",
    "    exit(0)\n",
    "\n",
    "while True:\n",
    "    ret, frame = cap.read()\n",
    "    if frame is None:\n",
    "        print('--(!) No captured frame -- Break!')\n",
    "        break\n",
    "\n",
    "    detectAndDisplay(frame)\n",
    "\n",
    "    if cv.waitKey(10) & 0xFF == ord('q'):  # Нажмите 'q' для выхода\n",
    "        break\n",
    "\n"
   ]
  },
  {
   "attachments": {
    "image.png": {
     "image/png": "[encoded data, 684412 characters]"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![image.png](attachment:image.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 618436 characters]",
      "text/plain": [
       "<Figure size 1000x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/d6/d10/tutorial_py_houghlines.html\n",
    "import cv2 as cv\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img = cv.imread('img/sudoku.png')\n",
    "gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)\n",
    "edges = cv.Canny(gray, 50, 150, apertureSize=3)\n",
    "\n",
    "lines = cv.HoughLines(edges, 1, np.pi / 180, 200)\n",
    "for line in lines:\n",
    "    rho, theta = line[0]\n",
    "    a = np.cos(theta)\n",
    "    b = np.sin(theta)\n",
    "    x0 = a * rho\n",
    "    y0 = b * rho\n",
    "    x1 = int(x0 + 1000 * (-b))\n",
    "    y1 = int(y0 + 1000 * (a))\n",
    "    x2 = int(x0 - 1000 * (-b))\n",
    "    y2 = int(y0 - 1000 * (a))\n",
    "    cv.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)\n",
    "\n",
    "plt.figure(figsize=(10, 10))\n",
    "plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))\n",
    "plt.title(\"Hough Lines\")\n",
    "plt.axis(\"off\")\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 617536 characters]",
      "text/plain": [
       "<Figure size 1000x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img = cv.imread('img/sudoku.png')\n",
    "gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)\n",
    "edges = cv.Canny(gray, 50, 150, apertureSize=3)\n",
    "\n",
    "lines = cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=100, maxLineGap=10)\n",
    "for line in lines:\n",
    "    x1, y1, x2, y2 = line[0]\n",
    "    cv.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)\n",
    "\n",
    "plt.figure(figsize=(10, 10))\n",
    "plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))\n",
    "plt.title(\"Probabilistic Hough Lines\")\n",
    "plt.axis(\"off\")\n",
    "plt.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 51168 characters]",
      "text/plain": [
       "<Figure size 800x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#https://docs.opencv.org/3.4/da/d53/tutorial_py_houghcircles.html\n",
    "import numpy as np\n",
    "import cv2 as cv\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img = cv.imread('img/geometric_shapes.jpg', cv.IMREAD_GRAYSCALE)\n",
    "assert img is not None, \"Image could not be read. Check the file path.\"\n",
    "\n",
    "img = cv.medianBlur(img, 5)\n",
    "cimg = cv.cvtColor(img, cv.COLOR_GRAY2BGR)\n",
    "\n",
    "circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 20,\n",
    "                          param1=50, param2=30, minRadius=0, maxRadius=0)\n",
    "\n",
    "if circles is not None:\n",
    "    circles = np.uint16(np.around(circles))\n",
    "    for i in circles[0, :]:\n",
    "        cv.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)  # Draw the circle\n",
    "        cv.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)    # Draw the center\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "plt.imshow(cv.cvtColor(cimg, cv.COLOR_BGR2RGB))\n",
    "plt.title(\"Detected Circles\")\n",
    "plt.axis(\"off\")\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "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.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
