{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# FIRST import all the necessary libraries and modules!\n", "import cv2 # import OpenCV\n", "import numpy as np # import NumPy\n", "\n", "# import instructor made functions \n", "import sys\n", "sys.path.insert(0, '../..')\n", "from utils import * " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Painter Lab\n", "\n", "
\n",
" Let's learn how to paint on live video using colored objects! \n",
"
To do this, we will need to combine everything we've learned so far: drawing, color tracking, and contours!\n",
"
\n",
" HSV tends to be better for tracking an object by color than BGR. \n",
"
Do you remember why this is? Discuss with your partner!\n",
"
\n", " We can mask video frames using lower and upper bounds for hue (H), saturation (S), and value (V) to track objects by their color.\n", "
\n", "\n", "![HSV](hsv.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Isolating Objects\n", "\n", "\n", " First, we need to detect the colored objects we will be drawing with! \n", "
\n", "\n", "\n", " Here is an example of a GOOD MASK:\n", "
\n", "\n", "![hsv_good_example](hsv_good_example.png)\n", "\n", "\n", " Here is an example of a BAD MASK:\n", "
\n", "\n", "\n", "\n", "\n", " Exercise:\n", "
hsv_select_live()
to select HSV upper/lower bounds so that only the object's color is visible. Everything else should be MASKED/BLACK. \n",
" Exercise:\n",
"
Let's create a function that returns a masked frame using input HSV values:\n",
"
cv2.cvtColor
cv2.inRange
to create a mask using the given inputs\n",
" \n",
" Exercise:\n",
"
Let's test our mask on a colored object! \n",
"
Set hsv_lower
and hsv_upper
using the values you recorded for one of your colored objects.\n",
"
\n", " Run the code below to see your mask work in real time!\n", "
\n", " \n", "\n", " It should look something like this:\n", "
\n", "\n", "![mask](mask.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def show_mask(frame):\n", " mask = mask_frame(frame, hsv_lower, hsv_upper) # calculates the mask\n", " cv2.imshow('Mask', mask) # displays the mask\n", "\n", "video(show_mask)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Finding Contours\n", "\n", "\n",
" We can track the location of your colored object using contours. \n",
"
We can calculate a list of contours based on a given mask like this:\n",
"
\n",
" Exercise:\n",
"
In the function below, find and return the list of all contours.\n",
"
\n", " Run the code block below to see your contours drawn on the frame!\n", "
\n", "\n", "\n", " It should look similar to this:\n", "
\n", "\n", "![contours](contours.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def show_contours(frame):\n", " mask = mask_frame(frame, hsv_lower, hsv_upper) # calculates the mask\n", " contours = find_contours(mask) # finds the contours\n", " cv2.drawContours(frame, contours, -1, (0, 255, 0), 3) # draw contours over the frame\n", " cv2.imshow('Contours', frame)\n", "\n", "video(show_contours)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Isolating Object Contour" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n",
" As you can see, there are extra contours :( \n",
"
We just want ONE contour for our colored object! \n",
"
\n",
" Let's only consider contours with area larger than 1000
pixels. \n",
"
We can find the area of a single contour like this:\n",
"
\n",
" Exercise:\n",
"
Fill in the function below to return only contours larger than 1000 pixels:\n",
"
1000
to be our object contour.None
.\n", " Run the code below to display this contour!\n", "
\n", " \n", "
\n", " It should look similar to this:\n", "
\n", " \n", "![object contour](obj_contour.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def show_object_contour(frame):\n", " mask = mask_frame(frame, hsv_lower, hsv_upper) # calculates the mask\n", " obj_contour = object_contour(mask) # finds the object contour\n", " if obj_contour is not None: # if the contour exists,\n", " cv2.drawContours(frame, [obj_contour], -1, (0, 255, 0), 3) # draws the contour\n", " cv2.imshow('Object Contour', frame)\n", "\n", "video(show_object_contour)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Smallest Enclosing Circle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n",
" The instructor-made functions find_center(<contour>)
and find_radius(<contour>)
find the center coordinates and radius of the smallest circle that fits around our object.\n",
"
\n",
" Exercise:\n",
"
Using these functions, draw a circle around the object. \n",
"
Choose the color and thickness of the circle yourself!\n",
"
\n", " Run the code below to see your circle drawn on the frame in real time!\n", "
\n", "\n", "\n", " It should look like this:\n", "
\n", "\n", "![circle](circle.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def display_circle(frame):\n", " mask = mask_frame(frame, hsv_lower, hsv_upper) # calculates the mask\n", " contour = object_contour(mask) # find the object contour\n", " if contour is not None: # if the contour exists\n", " draw_circle(frame, contour) # draws circle around object\n", " cv2.imshow('Circle Tracking', frame)\n", "\n", "video(display_circle)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Drawing with an Object" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n",
" In the draw
function below, we will:\n",
"
\n",
" Exercise:\n",
"
Fill in the draw
function below to draw with your object!\n",
"
\n",
" Exercise:\n",
"
In the function below, call draw
on a color of your choice! \n",
"
Then draw the lines saved in lines
onto the frame.\n",
"
\n", " Run the code below. You should be able to draw on top of the video with your object!\n", "
\n", " \n", "
\n", " It should look something like this:\n", "
\n", "\n", "![draw](draw.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lines = [] # reset lines list\n", "video(show_draw)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# BONUS: Drawing with Multiple Objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n",
" Exercise:\n",
"
To draw with multiple objects, we need to:\n",
"
prev_pos
\n",
" Exercise:\n",
"
Now we need to update show_draw
to include multiple colors.\n",
"
\n", " Run the code below. Each object should now draw a different color!\n", "
\n", " \n", "
\n", " It should look something like this:\n", "
\n", "\n", "![multiple draw](multiple_draw.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "lines = [] # reset lines list\n", "video(show_draw)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bonus Challenge Ideas!!!!!\n", "- Add more colors!!!!!\n", "\n", "### Make a mask for a color \"tool\" that, when introduced in frame, \n", "- switches/cycles through colors! So you can have one tool for multiple colors\n", "- stops the drawing so that you can reposition your paintbrush without covering it or moving it off the screen\n", "- changes your drawings from lines to shapes! (circles, rectangles)\n", "\n", "\n" ] } ], "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.1" } }, "nbformat": 4, "nbformat_minor": 4 }