Browse Source

refactoring rendering to a separate controller

asobolev 1 year ago
parent
commit
7d00d61b9f
2 changed files with 208 additions and 123 deletions
  1. 83 123
      SIT.ipynb
  2. 125 0
      controllers/display.ipynb

File diff suppressed because it is too large
+ 83 - 123
SIT.ipynb


+ 125 - 0
controllers/display.ipynb

@@ -0,0 +1,125 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "cad57710",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import cv2\n",
+    "import numpy as np"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "91d021d9",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class SITDisplay:\n",
+    "    COLORS = {\n",
+    "        'red': (0,0,255), 'green': (127,255,0), 'blue': (255,127,0), 'yellow': (0,127,255), \\\n",
+    "        'black': (0,0,0), 'white': (255,255,255), 'pink': (255, 0, 255), 'tortoise': (0, 255, 255)\n",
+    "    }\n",
+    "\n",
+    "    island_colors = {2: 'green', 3: 'blue', 4: 'yellow', 5: 'black'}\n",
+    "    animal_colors = {1: 'tortoise', 2: 'pink', 3: 'white'}\n",
+    "\n",
+    "    def __init__(self, pt):  # injected dependency - position controller\n",
+    "        self.pt = pt\n",
+    "        self.masked_frame = None\n",
+    "        \n",
+    "    def render(self, input_frame, status, islands=[], angles=[], text_infos=[]):\n",
+    "        COLORS = SITDisplay.COLORS\n",
+    "        FONT = cv2.FONT_HERSHEY_DUPLEX\n",
+    "        status_color = COLORS['green'] if status.value == 1 else COLORS['red']\n",
+    "        texts = list(text_infos)\n",
+    "        \n",
+    "        # mask unused areas\n",
+    "        frame = cv2.bitwise_and(src1=input_frame, src2=self.pt.mask)\n",
+    "        self.masked_frame = frame.copy()\n",
+    "\n",
+    "        # size of the arena and status indicator\n",
+    "        cv2.circle(frame, (self.pt.cfg['arena_x'], self.pt.cfg['arena_y']), self.pt.cfg['arena_radius'], COLORS['red'], 2)\n",
+    "        cv2.circle(frame, (self.pt.cfg['arena_x'], self.pt.cfg['arena_y']), self.pt.cfg['floor_radius'], COLORS['red'], 2)\n",
+    "        cv2.circle(frame, (20,20), 10, status_color, -6)\n",
+    "        \n",
+    "        # draw islands\n",
+    "        if len(islands) > 0:\n",
+    "            for island in islands:\n",
+    "                clr = COLORS[SITDisplay.island_colors[island.sound_id]]\n",
+    "                x, y = self.pt.meters_to_px(island.x, island.y)\n",
+    "                cv2.circle(frame, (x, y), int(island.r/self.pt.pixel_size), clr, 2)\n",
+    "            \n",
+    "        # draw anglular indicators\n",
+    "        if len(angles) > 0:  # should not be more than 4\n",
+    "            p_rho = self.pt.cfg['floor_radius'] * self.pt.pixel_size\n",
+    "            for p_phi, clr in zip(angles, ['blue', 'yellow', 'pink', 'tortoise'][:len(angles)]):\n",
+    "                x_init, y_init = self.pt.meters_to_px(p_rho * np.sin(p_phi), p_rho * np.cos(p_phi))\n",
+    "                cv2.circle(frame, (x_init, y_init), 10, COLORS[clr], -1)\n",
+    "\n",
+    "        # light or dark period\n",
+    "        texts.append('Light' if self.pt.is_light else 'Dark')\n",
+    "\n",
+    "        # draw animal position center(s) and contours\n",
+    "        if self.pt.positions_in_px is not None:\n",
+    "            pos_in_px = self.pt.positions_in_px\n",
+    "            pos_in_m = self.pt.positions_in_m\n",
+    "            contours = self.pt.contours\n",
+    "            \n",
+    "            for i in range(len(pos_in_px)):\n",
+    "                clr = COLORS[SITDisplay.animal_colors[i+1]]\n",
+    "                x_px, y_px, alpha = pos_in_px[i][0], pos_in_px[i][1], self.pt.hds[0]\n",
+    "                \n",
+    "                # draw animal center and contours\n",
+    "                cv2.circle(frame, (x_px, y_px), 5, clr, -1)\n",
+    "                cv2.drawContours(frame, [contours[i]], 0, clr, 1, cv2.LINE_AA)\n",
+    "                \n",
+    "                # draw instant position values and HD vector\n",
+    "                cv2.putText(frame, '%.2f %.2f' % (pos_in_m[i][0], pos_in_m[i][1]), (x_px + 10, y_px + 10), FONT, .3, clr)\n",
+    "                x1, y1 = int(x_px + 40*np.cos(np.deg2rad(alpha))), int(y_px - 40*np.sin(np.deg2rad(alpha)))\n",
+    "                cv2.line(frame, (x_px, y_px), (x1, y1), clr, 1)\n",
+    "                \n",
+    "                texts.append('Animal %d: %.3f %.3f' % (i+1, pos_in_m[i][0], pos_in_m[i][1]))\n",
+    "                texts.append('Speed/HD: %.2f %.2f' % (self.pt.speeds[0], self.pt.hds[0]))\n",
+    "                \n",
+    "        # draw text infos\n",
+    "        for i, text in enumerate(texts):\n",
+    "            cv2.putText(frame, text, (10, 30 + 20*(i+1)), FONT, .5, COLORS['white'])\n",
+    "\n",
+    "        return frame"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "5e7f5cbd",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "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.8.8"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}