From 11e49f17d63a53be99474a31f42fef7ea055ff6a Mon Sep 17 00:00:00 2001 From: mariakakis Date: Sat, 2 Dec 2023 20:46:28 -0500 Subject: [PATCH] updating hw4 --- _lecturesfall/4_images.md | 4 +- homeworks/HW4 Answers.ipynb | 379 ++++++++++++++++ homeworks/HW4.ipynb | 360 +++++++++++++++ lectures/fall/4_images/4c - Shapes.ipynb | 554 ++++++++++++++++++++++- 4 files changed, 1294 insertions(+), 3 deletions(-) create mode 100644 homeworks/HW4 Answers.ipynb create mode 100644 homeworks/HW4.ipynb diff --git a/_lecturesfall/4_images.md b/_lecturesfall/4_images.md index dc699e1..9fdae58 100644 --- a/_lecturesfall/4_images.md +++ b/_lecturesfall/4_images.md @@ -32,10 +32,10 @@ materials: - type: "colab" url: https://colab.research.google.com/github/C4M-UofT/C4M-UofT.github.io/blob/master/lectures/fall/4_images/4g - Outlines.ipynb assignment: - text: "Materials in progress" + text: "HW 4" due_date: 2024-01-17 12:00 PM submission_link: https://q.utoronto.ca/courses/342394/assignments/1175771 files: - type: "colab" - url: TBD + url: https://colab.research.google.com/github/C4M-UofT/C4M-UofT.github.io/blob/master/homeworks/HW4.ipynb --- \ No newline at end of file diff --git a/homeworks/HW4 Answers.ipynb b/homeworks/HW4 Answers.ipynb new file mode 100644 index 0000000..cbcea9f --- /dev/null +++ b/homeworks/HW4 Answers.ipynb @@ -0,0 +1,379 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [ + "B6v86VjQmIrK", + "7XJJtyIRQgSQ", + "ckicG5ai2Mbe" + ] + }, + "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.2" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "B6v86VjQmIrK" + }, + "source": [ + "## Important: Run this code cell each time you start a new session!" + ] + }, + { + "cell_type": "code", + "source": [ + "!pip install numpy\n", + "!pip install pandas\n", + "!pip install matplotlib\n", + "!pip install os\n", + "!pip install opencv-python\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import os\n", + "import cv2" + ], + "metadata": { + "id": "jrO0X1ZMxMN5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "!wget -Ncnp https://physionet.org/files/images/1.0.0/E1154S7I000.png\n", + "!wget -Ncnp https://physionet.org/files/images/1.0.0/E1154S7I024.png" + ], + "metadata": { + "id": "mD9SEZljuFVA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import shutil\n", + "import os\n", + "orig_file = os.path.join('E1154S7I000.png')\n", + "os.rename(orig_file, 'bw_mra_single.png')\n", + "orig_file = os.path.join('E1154S7I024.png')\n", + "os.rename(orig_file, 'bw_mra_multiple.png')" + ], + "metadata": { + "id": "o8I8wOuMuPOn" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IhQvi7z1v6rm" + }, + "source": [ + "# Instructions" + ] + }, + { + "cell_type": "markdown", + "source": [ + "To get full credit for this assignment, we should be able to run your entire notbook from start to finish without any errors. You can check this yourself by selecting \"Runtime\" > \"Run all\" in the Google Colab menu." + ], + "metadata": { + "id": "FmZhTZTraQGQ" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Exercise 1: Working with Basic Shapes and Colors" + ], + "metadata": { + "id": "7XJJtyIRQgSQ" + } + }, + { + "cell_type": "markdown", + "source": [ + "This exercise will require drawing shapes on a blank image created using the following function:" + ], + "metadata": { + "id": "xtwly1OhRpGP" + } + }, + { + "cell_type": "code", + "source": [ + "def create_black_img():\n", + " return np.zeros((300,300,3), np.uint8)" + ], + "metadata": { + "id": "xChw-dSJQk_u" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 1)** Write code that draws a red circle with the following properties:\n", + "* Center at position `x = 250, y = 100`\n", + "* Radius of `25`\n", + "* Outline thickness of `3`" + ], + "metadata": { + "id": "7gEjqGWZR9r4" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "cv2.circle(img, center=(250, 100), radius=25,\n", + " color=(255, 0, 0), thickness=3)\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "DFNaewqkSvUh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 2)** Write code that draws a filled magenta rectangle with the following properties:\n", + "* Top left corner at position `x = 50, y = 100`\n", + "* Height of `50`\n", + "* Width of `100`\n" + ], + "metadata": { + "id": "umOgE7tZQ4IZ" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "top_left = (50, 100)\n", + "h = 50\n", + "w = 100\n", + "bottom_right = (top_left[0]+w, top_left[1]+h)\n", + "cv2.rectangle(img, pt1=top_left, pt2=bottom_right,\n", + " color=(255, 0, 255), thickness=-1)\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "jjQT41bURWLg" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 3)** Write code that draws a filled white ellipse with the following properties:\n", + "* Center at position `x = 100, y = 200`\n", + "* Major axis of `100`\n", + "* Minor axis of `25`\n", + "* No rotation" + ], + "metadata": { + "id": "Z0rRrjwrTUDc" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "cv2.ellipse(img, center=(100, 200), axes=(100, 25), angle=0,\n", + " startAngle=0, endAngle=360,\n", + " color=(255, 255, 255), thickness=-1)\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "d62CLFCsTvr0" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Exercise 2: Identifying a Region of Interest in an MRA Image" + ], + "metadata": { + "id": "ckicG5ai2Mbe" + } + }, + { + "cell_type": "markdown", + "source": [ + "This exercise will revolve around a magnetic resonance angiography (MRA) image showing a coronal slice from an anteroposterior position within the torso. We have already taken the liberty of applying a binary threshold to reveal the prominent regions of the MRA image." + ], + "metadata": { + "id": "0DWUqG9Z3fJG" + } + }, + { + "cell_type": "code", + "source": [ + "img = cv2.imread('bw_mra_multiple.png')\n", + "img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n", + "_, img_thresh = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY)\n", + "\n", + "plt.figure(figsize=(6, 3))\n", + "plt.subplot(1, 2, 1), plt.title('Original Image')\n", + "plt.imshow(img)\n", + "plt.subplot(1, 2, 2), plt.title('Thresholded Image')\n", + "plt.imshow(img_thresh, cmap='gray')\n", + "plt.show()" + ], + "metadata": { + "id": "Xm0Kq1yM3fJH" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Notice that the binary image still contains numerous regions: three prominent ones along the center and right side of the image, and many smaller ones along the left side and the periphery. Our goal is to measure the radius of the round blob in the upper half of the image." + ], + "metadata": { + "id": "YX8AR1fqMSXK" + } + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 1)** Write code that collects a list of the contours corresponding to the three largest regions in the binary image. There are multiple ways of doing this, but here are a couple of suggestions:\n", + "1. Sort all of the contours by their size and then pick the largest three ones\n", + "2. Iterate through the contours and keep the ones whose size exceed a minimum threshold defined by you\n", + "\n", + "To confirm that this is working properly, draw green outlines around these regions using the code provided." + ], + "metadata": { + "id": "sH4HFMfs6QBi" + } + }, + { + "cell_type": "code", + "source": [ + "# Locate the contours\n", + "cnts, hierarchy = cv2.findContours(img_thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)\n", + "\n", + "# Only keep the contours that pass the size check\n", + "large_cnts = []\n", + "for cnt in cnts:\n", + " cnt_area = cv2.contourArea(cnt)\n", + " if 500 < cnt_area:\n", + " large_cnts.append(cnt)\n", + "\n", + "# Draw the outlines on the image\n", + "output_img = img.copy()\n", + "for cnt in large_cnts:\n", + " cv2.drawContours(output_img, [cnt], -1, (0, 255, 0), 3)\n", + "\n", + "# Show the result\n", + "plt.figure(figsize=(6, 3))\n", + "plt.imshow(output_img, cmap='gray')\n", + "plt.show()" + ], + "metadata": { + "id": "mBOeY12sJu4L" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 2)** Write code that identifies the most circular contour out of the three regions that were selected in the previous problem. Draw a green outline around it using the code provided.\n", + "\n", + "*Hint:* Think about the contour properties we covered during the lecture. A circle is a special kind of ellipse where the major and minor axes are equal." + ], + "metadata": { + "id": "_06qfRD9Jvq_" + } + }, + { + "cell_type": "code", + "source": [ + "# Iterate through all of the contours\n", + "circular_cnt = None\n", + "min_axis_ratio = 1e6\n", + "for cnt in large_cnts:\n", + " # Calculate the \"roundness\" using the ratio of the major and minor axes\n", + " cnt_ellipse = cv2.fitEllipse(cnt)\n", + " cnt_axes = cnt_ellipse[1]\n", + " cnt_axis_ratio = cnt_axes[0]/cnt_axes[1]\n", + " # Save the contour if this one is more round than past ones\n", + " if cnt_axis_ratio < min_axis_ratio:\n", + " circular_cnt = cnt\n", + "\n", + "# Draw the outlines on the image\n", + "output_img = img.copy()\n", + "cv2.drawContours(output_img, [circular_cnt], -1, (0, 255, 0), 3)\n", + "\n", + "# Show the result\n", + "plt.figure(figsize=(6, 3))\n", + "plt.imshow(output_img, cmap='gray')\n", + "plt.show()" + ], + "metadata": { + "id": "u4i6qrHDJwIJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 3)** Write code that calculates the radius of the circular region that you have identified in pixels." + ], + "metadata": { + "id": "cnNmSd5RKK-p" + } + }, + { + "cell_type": "code", + "source": [ + "circle_outline = cv2.minEnclosingCircle(circular_cnt)\n", + "circle_outline[1]" + ], + "metadata": { + "id": "0Qmwz3dYKN7s" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/homeworks/HW4.ipynb b/homeworks/HW4.ipynb new file mode 100644 index 0000000..992ceb1 --- /dev/null +++ b/homeworks/HW4.ipynb @@ -0,0 +1,360 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [ + "B6v86VjQmIrK", + "7XJJtyIRQgSQ", + "ckicG5ai2Mbe" + ] + }, + "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.2" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "B6v86VjQmIrK" + }, + "source": [ + "## Important: Run this code cell each time you start a new session!" + ] + }, + { + "cell_type": "code", + "source": [ + "!pip install numpy\n", + "!pip install pandas\n", + "!pip install matplotlib\n", + "!pip install os\n", + "!pip install opencv-python\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import os\n", + "import cv2" + ], + "metadata": { + "id": "jrO0X1ZMxMN5" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "!wget -Ncnp https://physionet.org/files/images/1.0.0/E1154S7I000.png\n", + "!wget -Ncnp https://physionet.org/files/images/1.0.0/E1154S7I024.png" + ], + "metadata": { + "id": "mD9SEZljuFVA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import shutil\n", + "import os\n", + "orig_file = os.path.join('E1154S7I000.png')\n", + "os.rename(orig_file, 'bw_mra_single.png')\n", + "orig_file = os.path.join('E1154S7I024.png')\n", + "os.rename(orig_file, 'bw_mra_multiple.png')" + ], + "metadata": { + "id": "o8I8wOuMuPOn" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IhQvi7z1v6rm" + }, + "source": [ + "# Instructions" + ] + }, + { + "cell_type": "markdown", + "source": [ + "To get full credit for this assignment, we should be able to run your entire notbook from start to finish without any errors. You can check this yourself by selecting \"Runtime\" > \"Run all\" in the Google Colab menu." + ], + "metadata": { + "id": "FmZhTZTraQGQ" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Exercise 1: Working with Basic Shapes and Colors" + ], + "metadata": { + "id": "7XJJtyIRQgSQ" + } + }, + { + "cell_type": "markdown", + "source": [ + "This exercise will require drawing shapes on a blank image created using the following function:" + ], + "metadata": { + "id": "xtwly1OhRpGP" + } + }, + { + "cell_type": "code", + "source": [ + "def create_black_img():\n", + " return np.zeros((300,300,3), np.uint8)" + ], + "metadata": { + "id": "xChw-dSJQk_u" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 1)** Write code that draws a red circle with the following properties:\n", + "* Center at position `x = 250, y = 100`\n", + "* Radius of `25`\n", + "* Outline thickness of `3`" + ], + "metadata": { + "id": "7gEjqGWZR9r4" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "\n", + "# Write your code here\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "DFNaewqkSvUh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 2)** Write code that draws a filled magenta rectangle with the following properties:\n", + "* Top left corner at position `x = 50, y = 100`\n", + "* Height of `50`\n", + "* Width of `100`\n" + ], + "metadata": { + "id": "umOgE7tZQ4IZ" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "\n", + "# Write your code here\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "jjQT41bURWLg" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 3)** Write code that draws a filled white ellipse with the following properties:\n", + "* Center at position `x = 100, y = 200`\n", + "* Major axis of `100`\n", + "* Minor axis of `25`\n", + "* No rotation" + ], + "metadata": { + "id": "Z0rRrjwrTUDc" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "\n", + "# Write your code here\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "d62CLFCsTvr0" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Exercise 2: Identifying a Region of Interest in an MRA Image" + ], + "metadata": { + "id": "ckicG5ai2Mbe" + } + }, + { + "cell_type": "markdown", + "source": [ + "This exercise will revolve around a magnetic resonance angiography (MRA) image showing a coronal slice from an anteroposterior position within the torso. We have already taken the liberty of applying a binary threshold to reveal the prominent regions of the MRA image." + ], + "metadata": { + "id": "0DWUqG9Z3fJG" + } + }, + { + "cell_type": "code", + "source": [ + "img = cv2.imread('bw_mra_multiple.png')\n", + "img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n", + "_, img_thresh = cv2.threshold(img_gray, 200, 255, cv2.THRESH_BINARY)\n", + "\n", + "plt.figure(figsize=(6, 3))\n", + "plt.subplot(1, 2, 1), plt.title('Original Image')\n", + "plt.imshow(img)\n", + "plt.subplot(1, 2, 2), plt.title('Thresholded Image')\n", + "plt.imshow(img_thresh, cmap='gray')\n", + "plt.show()" + ], + "metadata": { + "id": "Xm0Kq1yM3fJH" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Notice that the binary image still contains numerous regions: three prominent ones along the center and right side of the image, and many smaller ones along the left side and the periphery. Our goal is to measure the radius of the round blob in the upper half of the image." + ], + "metadata": { + "id": "YX8AR1fqMSXK" + } + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 1)** Write code that collects a list of the contours corresponding to the three largest regions in the binary image. There are multiple ways of doing this, but here are a couple of suggestions:\n", + "1. Sort all of the contours by their size and then pick the largest three ones\n", + "2. Iterate through the contours and keep the ones whose size exceed a minimum threshold defined by you\n", + "\n", + "To confirm that this is working properly, draw green outlines around these regions using the code provided." + ], + "metadata": { + "id": "sH4HFMfs6QBi" + } + }, + { + "cell_type": "code", + "source": [ + "# Write your code here\n", + "large_cnts = [] # TODO: write code that will save the large contours here\n", + "\n", + "# Draw the outlines on the image\n", + "output_img = img.copy()\n", + "for cnt in large_cnts:\n", + " cv2.drawContours(output_img, [cnt], -1, (0, 255, 0), 3)\n", + "\n", + "# Show the result\n", + "plt.figure(figsize=(6, 3))\n", + "plt.imshow(output_img, cmap='gray')\n", + "plt.show()" + ], + "metadata": { + "id": "mBOeY12sJu4L" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 2)** Write code that identifies the most circular contour out of the three regions that were selected in the previous problem. Draw a green outline around it using the code provided.\n", + "\n", + "*Hint:* Think about the contour properties we covered during the lecture. A circle is a special kind of ellipse where the major and minor axes are equal." + ], + "metadata": { + "id": "_06qfRD9Jvq_" + } + }, + { + "cell_type": "code", + "source": [ + "# Write your code here\n", + "circular_cnt = None # TODO: write code that will save the circular contour here\n", + "\n", + "# Draw the outlines on the image\n", + "output_img = img.copy()\n", + "cv2.drawContours(output_img, [circular_cnt], -1, (0, 255, 0), 3)\n", + "\n", + "# Show the result\n", + "plt.figure(figsize=(6, 3))\n", + "plt.imshow(output_img, cmap='gray')\n", + "plt.show()" + ], + "metadata": { + "id": "u4i6qrHDJwIJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "**(Part 3)** Write code that calculates the radius of the circular region that you have identified in pixels." + ], + "metadata": { + "id": "cnNmSd5RKK-p" + } + }, + { + "cell_type": "code", + "source": [ + "# Write your code here" + ], + "metadata": { + "id": "0Qmwz3dYKN7s" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/lectures/fall/4_images/4c - Shapes.ipynb b/lectures/fall/4_images/4c - Shapes.ipynb index 84f4745..feac1fb 100644 --- a/lectures/fall/4_images/4c - Shapes.ipynb +++ b/lectures/fall/4_images/4c - Shapes.ipynb @@ -1 +1,553 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"collapsed_sections":["oOb-bU29tGe9","0DhARKg3Vkvh","YQRUOY2rdNs3","h9ctHCbPPmeN","jiERM8DIpJPS"],"authorship_tag":"ABX9TyM/cTH4ZovgcL/U7NlhK2l5"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["In this notebook, we're going to talk about how we can draw shapes onto an image, which will be helpful for visualizing the results of other algorithms we write."],"metadata":{"id":"zKBYPS5L5yWH"}},{"cell_type":"markdown","source":["# Important: Run this code cell each time you start a new session!"],"metadata":{"id":"oOb-bU29tGe9"}},{"cell_type":"code","source":["!pip install numpy\n","!pip install pandas\n","!pip install matplotlib\n","!pip install os\n","!pip install opencv-python\n","import numpy as np\n","import pandas as pd\n","import matplotlib.pyplot as plt\n","import os\n","import cv2"],"metadata":{"id":"_41wnpx5tGfG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["!wget -Ncnp https://images.fineartamerica.com/images-medium-large-5/coloured-mri-scan-of-brain-in-sagittal-se-geoff-tompkinson.jpg"],"metadata":{"id":"Y8_yvRuatGfJ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["import shutil\n","import os\n","orig_file = os.path.join('coloured-mri-scan-of-brain-in-sagittal-se-geoff-tompkinson.jpg')\n","\n","os.rename(orig_file, 'color_mri.jpg')"],"metadata":{"id":"N0o-oc_ptGfK"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["# Image Coordinates and Array Indexes"],"metadata":{"id":"0DhARKg3Vkvh"}},{"cell_type":"markdown","source":["Like the Cartesian system you might be used to in math or `matplotlib`, the x-axis is horizontal and the y-axis is vertical. However, `opencv` is different in that the origin starts at the top left, which means that increasing x goes from left to right and increasing y goes from top to bottom."],"metadata":{"id":"JgvqG52TDJup"}},{"cell_type":"markdown","source":["Meanwhile, `numpy` arrays are indexed such that the first dimension corresponds to the row (vertical direction) and the second dimensions corresponds to the column (horizontal direction)."],"metadata":{"id":"soANNPCMVyqA"}},{"cell_type":"markdown","source":["If we were to have an image with a width of 300 and a height of 400, then these would be the coordinates of the image's corners in both systems:\n","\n","| Corner | OpenCV coordinate | Numpy index |\n","|:--------------:|:-----------:|:-----------:|\n","| Top left | `(0, 0)` | `img[0, 0]` |\n","| Top right | `(299, 0)` | `img[0, 299]` |\n","| Bottom left | `(0, 399)` | `img[399, 0]` |\n","| Bottom right | `(299, 399)` | `img[399, 299]` |"],"metadata":{"id":"lYwmQfk1tYAO"}},{"cell_type":"markdown","source":["We can confirm `opencv`'s system by displaying a blank image:"],"metadata":{"id":"YenDQr-5WACC"}},{"cell_type":"code","source":["plt.figure(figsize=(3, 3))\n","plt.imshow(np.zeros((400,300,3), np.uint8))\n","plt.show()"],"metadata":{"id":"gUY-A6i1URXi"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The mismatch between `opencv`'s coordinate system and the indexing of `numpy` arrays can be confusing, so make sure you keep these facts in mind."],"metadata":{"id":"ks82bnS4t771"}},{"cell_type":"markdown","source":["# Creating a Simple Shape Image"],"metadata":{"id":"YQRUOY2rdNs3"}},{"cell_type":"markdown","source":["Now that we understand the coordinate system that `opencv` uses, let's create our own basic image and look at the underlying data to understand how images get translated to multidimensional arrays."],"metadata":{"id":"udIdFma6PkuJ"}},{"cell_type":"markdown","source":["We will start by drawing a green rectangle on a black image. To do that, we will first create a simple helper function to initialize a blank `numpy` array with all zeroes and then use `cv2.rectangle()` to draw a rectangle."],"metadata":{"id":"E480Tjywubie"}},{"cell_type":"code","source":["# Create a function to make a blank image\n","def create_black_img():\n"," return np.zeros((300,300,3), np.uint8)\n","\n","# Set the color and thickness of our drawings\n","green = (0, 255, 0)\n","thickness = 4"],"metadata":{"id":"7PeRthr_AnIq"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Rectangle\n","pt1_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt1_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt2_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt2_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n","\n","img = create_black_img()\n","cv2.rectangle(img, pt1=(pt1_x,pt1_y), pt2=(pt2_x, pt2_y),\n"," color=green, thickness=thickness)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"Z9v0kfhZBH7J"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Let's look at what's happening underneath the hood by examining some of the values in our `img` array in a fixed example:"],"metadata":{"id":"-RlvGqIpNXDP"}},{"cell_type":"code","source":["img = create_black_img()\n","cv2.rectangle(img, pt1=(100,100), pt2=(150, 200),\n"," color=green, thickness=1)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"9Nh2fj8-OK1E"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print(f'Some black pixels:')\n","for pt in [[0, 0], [299, 299], [135, 125]]:\n"," print(f'Coordinate {pt[1], pt[0]}: {img[pt[0], pt[1]]}')"],"metadata":{"id":"QCW9SJyltu-2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print(f'Some green pixels:')\n","for pt in [[100, 100], [200, 100], [100, 150], [200, 150], [100, 125]]:\n"," print(f'Coordinate {pt[1], pt[0]}: {img[pt[0], pt[1]]}')"],"metadata":{"id":"y42mqKaPvNGz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Observe that that the color of all the pixels along the rectangle's edges have been set to green. Meanwhile, the other pixels have been kept black. In the end, all the `cv2.rectangle()` function is doing is a series of assignment statements that is setting the value of the image array at certain indices to the color that we have specified:\n","\n","```\n","compute list of pixels for the rectangle\n","for every point in the list:\n"," set its color to green\n","```"],"metadata":{"id":"8l-vrrzePxHk"}},{"cell_type":"markdown","source":["# Other Shapes and Drawing Tips"],"metadata":{"id":"h9ctHCbPPmeN"}},{"cell_type":"markdown","source":["Now that we have a better sense of how drawing manipulates our image data, let's look at other shapes we can draw:"],"metadata":{"id":"ca0tqpSuO5kj"}},{"cell_type":"code","source":["# Line\n","pt1_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt1_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt2_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt2_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n","\n","img = create_black_img()\n","cv2.line(img, pt1=(pt1_x,pt1_y), pt2=(pt2_x, pt2_y),\n"," color=green, thickness=thickness)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"TtzBMs3vAuCn"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Circle\n","center_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n","center_y = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n","radius = 50 #@param {type:\"slider\", min:0, max:150, step:50}\n","\n","img = create_black_img()\n","cv2.circle(img, center=(center_x,center_y), radius=radius,\n"," color=green, thickness=thickness)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"XrBeh8YlBMQi"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Ellipse\n","center_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n","center_y = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n","major_axis = 100 #@param {type:\"slider\", min:0, max:150, step:50}\n","minor_axis = 50 #@param {type:\"slider\", min:0, max:150, step:50}\n","angle = 0 #@param {type:\"slider\", min:0, max:360, step:45}\n","startAngle = 0 #@param {type:\"slider\", min:0, max:360, step:45}\n","endAngle = 360 #@param {type:\"slider\", min:0, max:360, step:45}\n","\n","img = create_black_img()\n","cv2.ellipse(img, center=(center_x,center_y),\n"," axes=(major_axis,minor_axis), angle=angle,\n"," startAngle=startAngle, endAngle=endAngle,\n"," color=green, thickness=thickness)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"Tfl2gV0pBOVi"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Polygon (a triangle in this example)\n","pt1_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt1_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt2_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt2_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt3_x = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n","pt3_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n","\n","pts = np.array([[pt1_x,pt1_y],\n"," [pt2_x,pt2_y],\n"," [pt3_x,pt3_y]], np.int32)\n","pts = [pts.reshape((-1,1,2))]\n","\n","img = create_black_img()\n","cv2.polylines(img, pts=pts, isClosed=True,\n"," color=green, thickness=thickness)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"cKakAgIzBUqI"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Text\n","origin_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","origin_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n","fontScale = 2 #@param {type:\"slider\", min:0, max:5, step:1}\n","\n","img = create_black_img()\n","font = cv2.FONT_HERSHEY_SIMPLEX\n","cv2.putText(img, text='C4M', org=(origin_x,origin_y),\n"," fontFace=font, fontScale=fontScale,\n"," color=green, thickness=2)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"cMUwvoSNBYDv"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["For all of these examples, we set thickness to a positive integer value. If you find yourself in a situation when you want to fill in the entire shape (excluding lines and text), you can set the thickness to `-1`:"],"metadata":{"id":"TEph-C0ULOsY"}},{"cell_type":"code","source":["# Create a filled circle\n","img = create_black_img()\n","cv2.circle(img, center=(200,200), radius=50,\n"," color=green, thickness=-1)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"KwQnkv5_LOeu"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Although we've drawn these shapes one at a time, you can draw as many shapes as you want on a single image. For any given pixel where two shapes overlap, the latest shape will always take precedence.\n","\n","Visually, you can imagine that we are adding new brush strokes on top of a painting. Programmatically, we are simply updating the elements of our image array just as an array would be updated in any other Python script."],"metadata":{"id":"XGHjlsgCMSZL"}},{"cell_type":"code","source":["red = (255, 0, 0)\n","\n","# Draw a red circle on top of a green line\n","img = create_black_img()\n","cv2.circle(img, center=(150,150), radius=50,\n"," color=green, thickness=-1)\n","cv2.line(img, pt1=(0,0), pt2=(300,300),\n"," color=red, thickness=thickness)\n","\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"kDwTDeoRMoRV"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["# Why Are Shapes Useful?"],"metadata":{"id":"jiERM8DIpJPS"}},{"cell_type":"markdown","source":["Adding shapes onto images is not going to be useful for analyzing images with computer vision or machine learning. However, like working with `matplotlib`, learning these functions can make it much easier for you to visualize the results of your analyses."],"metadata":{"id":"zsG-KDKopLok"}},{"cell_type":"markdown","source":["For example, imagine that we've written an algorithm that identifies an anomaly in an MRI. We can draw an ellipse around the anomaly so that we can visually determine if the algorithm's output makes sense:"],"metadata":{"id":"kPucAM4vGqcx"}},{"cell_type":"code","source":["# Load the image and convert to RGB\n","img = cv2.imread('color_mri.jpg')\n","img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n","\n","# Add the ellipse on top of the image\n","cv2.ellipse(img, center=(200,800),\n"," axes=(60,50), angle=0,\n"," startAngle=0, endAngle=360,\n"," color=green, thickness=5)\n","\n","# Show the overall image\n","plt.figure(figsize=(3, 3))\n","plt.imshow(img)\n","plt.show()"],"metadata":{"id":"L6mgSA6lG2UZ"},"execution_count":null,"outputs":[]}]} \ No newline at end of file +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "collapsed_sections": [ + "oOb-bU29tGe9", + "0DhARKg3Vkvh", + "YQRUOY2rdNs3", + "h9ctHCbPPmeN", + "jiERM8DIpJPS" + ] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "In this notebook, we're going to talk about how we can draw shapes onto an image, which will be helpful for visualizing the results of other algorithms we write." + ], + "metadata": { + "id": "zKBYPS5L5yWH" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Important: Run this code cell each time you start a new session!" + ], + "metadata": { + "id": "oOb-bU29tGe9" + } + }, + { + "cell_type": "code", + "source": [ + "!pip install numpy\n", + "!pip install pandas\n", + "!pip install matplotlib\n", + "!pip install os\n", + "!pip install opencv-python\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import os\n", + "import cv2" + ], + "metadata": { + "id": "_41wnpx5tGfG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "!wget -Ncnp https://images.fineartamerica.com/images-medium-large-5/coloured-mri-scan-of-brain-in-sagittal-se-geoff-tompkinson.jpg" + ], + "metadata": { + "id": "Y8_yvRuatGfJ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import shutil\n", + "import os\n", + "orig_file = os.path.join('coloured-mri-scan-of-brain-in-sagittal-se-geoff-tompkinson.jpg')\n", + "\n", + "os.rename(orig_file, 'color_mri.jpg')" + ], + "metadata": { + "id": "N0o-oc_ptGfK" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Image Coordinates and Array Indexes" + ], + "metadata": { + "id": "0DhARKg3Vkvh" + } + }, + { + "cell_type": "markdown", + "source": [ + "Like the Cartesian system you might be used to in math or `matplotlib`, the x-axis is horizontal and the y-axis is vertical. However, `opencv` is different in that the origin starts at the top left, which means that increasing x goes from left to right and increasing y goes from top to bottom." + ], + "metadata": { + "id": "JgvqG52TDJup" + } + }, + { + "cell_type": "markdown", + "source": [ + "Meanwhile, `numpy` arrays are indexed such that the first dimension corresponds to the row (vertical direction) and the second dimensions corresponds to the column (horizontal direction)." + ], + "metadata": { + "id": "soANNPCMVyqA" + } + }, + { + "cell_type": "markdown", + "source": [ + "If we were to have an image with a width of 300 and a height of 400, then these would be the coordinates of the image's corners in both systems:\n", + "\n", + "| Corner | OpenCV coordinate | Numpy index |\n", + "|:--------------:|:-----------:|:-----------:|\n", + "| Top left | `(0, 0)` | `img[0, 0]` |\n", + "| Top right | `(299, 0)` | `img[0, 299]` |\n", + "| Bottom left | `(0, 399)` | `img[399, 0]` |\n", + "| Bottom right | `(299, 399)` | `img[399, 299]` |" + ], + "metadata": { + "id": "lYwmQfk1tYAO" + } + }, + { + "cell_type": "markdown", + "source": [ + "We can confirm `opencv`'s system by displaying a blank image:" + ], + "metadata": { + "id": "YenDQr-5WACC" + } + }, + { + "cell_type": "code", + "source": [ + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(np.zeros((400,300,3), np.uint8))\n", + "plt.show()" + ], + "metadata": { + "id": "gUY-A6i1URXi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The mismatch between `opencv`'s coordinate system and the indexing of `numpy` arrays can be confusing, so make sure you keep these facts in mind." + ], + "metadata": { + "id": "ks82bnS4t771" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Creating a Simple Shape Image" + ], + "metadata": { + "id": "YQRUOY2rdNs3" + } + }, + { + "cell_type": "markdown", + "source": [ + "Now that we understand the coordinate system that `opencv` uses, let's create our own basic image and look at the underlying data to understand how images get translated to multidimensional arrays." + ], + "metadata": { + "id": "udIdFma6PkuJ" + } + }, + { + "cell_type": "markdown", + "source": [ + "We will start by drawing a green rectangle on a black image. To do that, we will first create a simple helper function to initialize a blank `numpy` array with all zeroes and then use `cv2.rectangle()` to draw a rectangle." + ], + "metadata": { + "id": "E480Tjywubie" + } + }, + { + "cell_type": "code", + "source": [ + "# Create a function to make a blank image\n", + "def create_black_img():\n", + " return np.zeros((300,300,3), np.uint8)\n", + "\n", + "# Set the color and thickness of our drawings\n", + "green = (0, 255, 0)\n", + "thickness = 4" + ], + "metadata": { + "id": "7PeRthr_AnIq" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Rectangle\n", + "pt1_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt1_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt2_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt2_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "\n", + "img = create_black_img()\n", + "cv2.rectangle(img, pt1=(pt1_x, pt1_y), pt2=(pt2_x, pt2_y),\n", + " color=green, thickness=thickness)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "Z9v0kfhZBH7J" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Let's look at what's happening underneath the hood by examining some of the values in our `img` array in a fixed example:" + ], + "metadata": { + "id": "-RlvGqIpNXDP" + } + }, + { + "cell_type": "code", + "source": [ + "img = create_black_img()\n", + "cv2.rectangle(img, pt1=(100,100), pt2=(150, 200),\n", + " color=green, thickness=1)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "9Nh2fj8-OK1E" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print(f'Some black pixels:')\n", + "for pt in [[0, 0], [299, 299], [135, 125]]:\n", + " print(f'Coordinate {pt[1], pt[0]}: {img[pt[0], pt[1]]}')" + ], + "metadata": { + "id": "QCW9SJyltu-2" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print(f'Some green pixels:')\n", + "for pt in [[100, 100], [200, 100], [100, 150], [200, 150], [100, 125]]:\n", + " print(f'Coordinate {pt[1], pt[0]}: {img[pt[0], pt[1]]}')" + ], + "metadata": { + "id": "y42mqKaPvNGz" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Observe that that the color of all the pixels along the rectangle's edges have been set to green. Meanwhile, the other pixels have been kept black. In the end, all the `cv2.rectangle()` function is doing is a series of assignment statements that is setting the value of the image array at certain indices to the color that we have specified:\n", + "\n", + "```\n", + "compute list of pixels for the rectangle\n", + "for every point in the list:\n", + " set its color to green\n", + "```" + ], + "metadata": { + "id": "8l-vrrzePxHk" + } + }, + { + "cell_type": "markdown", + "source": [ + "# Other Shapes and Drawing Tips" + ], + "metadata": { + "id": "h9ctHCbPPmeN" + } + }, + { + "cell_type": "markdown", + "source": [ + "Now that we have a better sense of how drawing manipulates our image data, let's look at other shapes we can draw:" + ], + "metadata": { + "id": "ca0tqpSuO5kj" + } + }, + { + "cell_type": "code", + "source": [ + "# Line\n", + "pt1_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt1_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt2_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt2_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "\n", + "img = create_black_img()\n", + "cv2.line(img, pt1=(pt1_x,pt1_y), pt2=(pt2_x, pt2_y),\n", + " color=green, thickness=thickness)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "TtzBMs3vAuCn" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Circle\n", + "center_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "center_y = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "radius = 50 #@param {type:\"slider\", min:0, max:150, step:50}\n", + "\n", + "img = create_black_img()\n", + "cv2.circle(img, center=(center_x,center_y), radius=radius,\n", + " color=green, thickness=thickness)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "XrBeh8YlBMQi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Ellipse\n", + "center_x = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "center_y = 150 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "major_axis = 100 #@param {type:\"slider\", min:0, max:150, step:50}\n", + "minor_axis = 50 #@param {type:\"slider\", min:0, max:150, step:50}\n", + "angle = 0 #@param {type:\"slider\", min:0, max:360, step:45}\n", + "startAngle = 0 #@param {type:\"slider\", min:0, max:360, step:45}\n", + "endAngle = 360 #@param {type:\"slider\", min:0, max:360, step:45}\n", + "\n", + "img = create_black_img()\n", + "cv2.ellipse(img, center=(center_x,center_y),\n", + " axes=(major_axis,minor_axis), angle=angle,\n", + " startAngle=startAngle, endAngle=endAngle,\n", + " color=green, thickness=thickness)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "Tfl2gV0pBOVi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Polygon (a triangle in this example)\n", + "pt1_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt1_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt2_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt2_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt3_x = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "pt3_y = 200 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "\n", + "pts = np.array([[pt1_x,pt1_y],\n", + " [pt2_x,pt2_y],\n", + " [pt3_x,pt3_y]], np.int32)\n", + "pts = [pts.reshape((-1,1,2))]\n", + "\n", + "img = create_black_img()\n", + "cv2.polylines(img, pts=pts, isClosed=True,\n", + " color=green, thickness=thickness)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "cKakAgIzBUqI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Text\n", + "origin_x = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "origin_y = 100 #@param {type:\"slider\", min:0, max:300, step:50}\n", + "fontScale = 2 #@param {type:\"slider\", min:0, max:5, step:1}\n", + "\n", + "img = create_black_img()\n", + "font = cv2.FONT_HERSHEY_SIMPLEX\n", + "cv2.putText(img, text='C4M', org=(origin_x,origin_y),\n", + " fontFace=font, fontScale=fontScale,\n", + " color=green, thickness=2)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "cMUwvoSNBYDv" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For all of these examples, we set thickness to a positive integer value. If you find yourself in a situation when you want to fill in the entire shape (excluding lines and text), you can set the thickness to `-1`:" + ], + "metadata": { + "id": "TEph-C0ULOsY" + } + }, + { + "cell_type": "code", + "source": [ + "# Create a filled circle\n", + "img = create_black_img()\n", + "cv2.circle(img, center=(200,200), radius=50,\n", + " color=green, thickness=-1)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "KwQnkv5_LOeu" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "Although we've drawn these shapes one at a time, you can draw as many shapes as you want on a single image. For any given pixel where two shapes overlap, the latest shape will always take precedence.\n", + "\n", + "Visually, you can imagine that we are adding new brush strokes on top of a painting. Programmatically, we are simply updating the elements of our image array just as an array would be updated in any other Python script." + ], + "metadata": { + "id": "XGHjlsgCMSZL" + } + }, + { + "cell_type": "code", + "source": [ + "red = (255, 0, 0)\n", + "\n", + "# Draw a red circle on top of a green line\n", + "img = create_black_img()\n", + "cv2.circle(img, center=(150,150), radius=50,\n", + " color=green, thickness=-1)\n", + "cv2.line(img, pt1=(0,0), pt2=(300,300),\n", + " color=red, thickness=thickness)\n", + "\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "kDwTDeoRMoRV" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Why Are Shapes Useful?" + ], + "metadata": { + "id": "jiERM8DIpJPS" + } + }, + { + "cell_type": "markdown", + "source": [ + "Adding shapes onto images is not going to be useful for analyzing images with computer vision or machine learning. However, like working with `matplotlib`, learning these functions can make it much easier for you to visualize the results of your analyses." + ], + "metadata": { + "id": "zsG-KDKopLok" + } + }, + { + "cell_type": "markdown", + "source": [ + "For example, imagine that we've written an algorithm that identifies an anomaly in an MRI. We can draw an ellipse around the anomaly so that we can visually determine if the algorithm's output makes sense:" + ], + "metadata": { + "id": "kPucAM4vGqcx" + } + }, + { + "cell_type": "code", + "source": [ + "# Load the image and convert to RGB\n", + "img = cv2.imread('color_mri.jpg')\n", + "img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n", + "\n", + "# Add the ellipse on top of the image\n", + "cv2.ellipse(img, center=(200,800),\n", + " axes=(60,50), angle=0,\n", + " startAngle=0, endAngle=360,\n", + " color=green, thickness=5)\n", + "\n", + "# Show the overall image\n", + "plt.figure(figsize=(3, 3))\n", + "plt.imshow(img)\n", + "plt.show()" + ], + "metadata": { + "id": "L6mgSA6lG2UZ" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file