Draw Using a Virtual Pen/Marker on a Computer Screen using OpenCV in Python

by May 26, 2020IoT Programming

In this project, we use OpenCV in python to draw on the screen using a virtual pen i.e, any marker can be used to draw/erase using the technique of contour detection based on the mask of the desired colored target marker.

Note: Make sure the target maker color is not present in the background to avoid error.

Have a look at the final project in action:

Here we simply draw few random stuff

The entire code for this opencv post is available at the following github Repository:

Work flow/Structure:

  • STEP1: Find the HSV range of the target Marker/pen and save the values in a .npy file
  • STEP 2: Use the above values to start drawing in the main code
    • First, we will use color masking to get a mask of our colored pen/marker using the above HSV range.
    • Next, using contour detection we detect and track the location of that pen,i.e get the x,y coordinates.
    • Next, draw a line by joining the x,y coordinates of pen’s previous location (location in the previous frame) with the new x,y points.
    • Add a feature to use the marker as an Eraser to erase unwanted lines.
    • Finally, add another feature to clear the entire Canvas/Screen.

Step1: Find HSV color range of the marker/pen we will use

Press ‘s’ to save and exit once you are done setting up.
  • Import the required Libraries:
import cv2
import numpy as np
  • Define a capture device .Here we use our primary laptop camera(0).If using external usb camera use replace 0 with 1.
cap=cv2.VideoCapture(0)
  • We create six trackbars to set the values of upper and lower limit of H,S,V respectively within a new window named “trackbar
def nothing(x):
    pass
#Create trackbar to adjust HSV range
cv2.namedWindow("trackbar")
cv2.createTrackbar("L-H","trackbar",0,179,nothing)
cv2.createTrackbar("L-S","trackbar",0,255,nothing)
cv2.createTrackbar("L-V","trackbar",0,255,nothing)
cv2.createTrackbar("U-H","trackbar",179,179,nothing)
cv2.createTrackbar("U-S","trackbar",255,255,nothing)
cv2.createTrackbar("U-V","trackbar",255,255,nothing)
  • Start reading frames inside an infinite loop:
    • get the updated trackbar values,
    • create a mask using this range, and
    • Finally, do a bitwise operation and display the result.
while True:
    ret,frame =cap.read()
    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)    
    
    l_h=cv2.getTrackbarPos("L-H","trackbar")
    l_s=cv2.getTrackbarPos("L-S","trackbar")
    l_v=cv2.getTrackbarPos("L-V","trackbar")
    h_h=cv2.getTrackbarPos("U-H","trackbar")
    h_s=cv2.getTrackbarPos("U-S","trackbar")
    h_v=cv2.getTrackbarPos("U-V","trackbar")
   
    low=np.array([l_h,l_s,l_v])
    high=np.array([h_h,h_s,h_v])

    mask=cv2.inRange(hsv,low,high) 
    result=cv2.bitwise_and(frame,frame,mask=mask)    
    cv2.imshow("result",result)# If the user presses ESC then exit the program
  • press ‘s’ in keyboard to save the current settings of HSV range values and break from the infinite loop.This will create a new file penrange.npy and exit from the program.
The ultimate file we need for the main code to run.
  • Outside the loop release cap and destroy all open windows.
    key = cv2.waitKey(1)
    # If the user presses `s` then print and save this array.
    if key == ord('s'):
        thearray = [[l_h,l_s,l_v],[h_h, h_s, h_v]]
        # Save this array as penrange.npy
        np.save('penrange',thearray)
        break
    #if esc pressed exit
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()

STEP 2: Use the above values to start drawing in the main code

  • Import the required libraries.
import cv2
import numpy as np
  • Create a new class named drawingCanvas withing which we will define all the required functions.
    • First, we define __init__() and initialize the required variables.
    • Also, call the draw() function from here.
class drawingCanvas():
    def __init__(self):
        self.penrange = np.load('penrange.npy') # load HSV range
        self.cap = cv2.VideoCapture(0)          #0 means primary camera .
        self.canvas = None                      #initialize blank canvas
        #initial position on pen 
        self.x1,self.y1=0,0
        # val is used to toggle between pen and eraser mode
        self.val=1
        self.draw()                            #Finally call the draw function
  • Next, define the draw() function:
    • read frames from the camera within an infinite loop
    • flip the frame horizontally
    • create a mask by calling CreateMask function
    • Detect contours using the mask.
    • Draw lines on the canvas.
    • Finally, display the results.
    • Read keyboard input ,store it in k and call takeAction() function.
    • Press ‘Esc’ key to break and exit the program.
    def draw(self):
        while True:
            _, self.frame = self.cap.read()       #read new frame
            self.frame = cv2.flip( self.frame, 1 ) #flip horizontally

            if self.canvas is None:
                self.canvas = np.zeros_like(self.frame) #initialize a black canvas
            
            mask=self.CreateMask()             #createmask
            contours=self.ContourDetect(mask)  #detect Contours
            self.drawLine(contours)            #draw lines
            self.display()                     #display results
            k = cv2.waitKey(1) & 0xFF          #wait for keyboard input
            self.takeAction(k)                 #take action based on k value
         
            if k == 27:                        #if esc key is pressed exit
                break        
  • Next , define CreateMask() function.
    def CreateMask(self):
        hsv = cv2.cvtColor(self.frame, cv2.COLOR_BGR2HSV) #convert from BGR to HSV color range
        lower_range = self.penrange[0]                    #load  HSV lower range
        upper_range = self.penrange[1]                    #load  HSV upper range
        mask = cv2.inRange(hsv, lower_range, upper_range) #Create binary mask
        return mask
  • Next, define ContourDetect() function.
    def ContourDetect(self,mask):
        # Find Contours based on the mask created.
        contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        return contours
  • Next, define drawLine() function: Here based on valid current and previous marker position we draw a line by joining the two coordinates.
    def drawLine(self,contours):
        #if contour area is not none and is greater than 100 draw the line
        if contours and cv2.contourArea(max(contours, key = cv2.contourArea)) > 100:  #100 is required min contour area              
            c = max(contours, key = cv2.contourArea)    
            x2,y2,w,h = cv2.boundingRect(c)
    
            if self.x1 == 0 and self.y1 == 0:    #this will we true only for the first time marker is detected
                self.x1,self.y1= x2,y2
            else:
                # Draw the line on the canvas
                self.canvas = cv2.line(self.canvas, (self.x1,self.y1),(x2,y2), [255*self.val,0,0], 10)
            #New point becomes the previous point 
            self.x1,self.y1= x2,y2
        else:
            # If there were no contours detected then make x1,y1 = 0 (reset)
            self.x1,self.y1 =0,0        
  • Next, define display(): Here the canvas and frame with lines is displayed.
    def display(self):
        # Merge the canvas and the frame.
        self.frame = cv2.add(self.frame,self.canvas)    
        cv2.imshow('frame',self.frame)
        cv2.imshow('canvas',self.canvas)
  • Define takeAction() to perform different operations based on keyboard input
    • eraser toggle mode (Press ‘e’ to toggle). This will draw with black color when we move the marker and in a way can perform erase action on the canvas.
    • canvas clear operation (Press ‘c’ ).
Added Eraser Feature

Finally Create instance of the class drawingCanvas.

    def takeAction(self,k):
        # When c is pressed clear the entire canvas
        if k == ord('c'):
            self.canvas = None
        #press e to change between eraser mode and writing mode
        if k==ord('e'):
            self.val= int(not self.val) # toggle val value between 0 and 1 to change marker color.
                   
if __name__ == '__main__':
    drawingCanvas()
    
cv2.destroyAllWindows()

That’s all we need to make our very own virtual marker for the screen using Opencv and any marker/color object lying around.

Creating a multiplication Skill in Alexa using python

Written By Monisha Macharla

Hi, I'm Monisha. I am a tech blogger and a hobbyist. I am eager to learn and explore tech related stuff! also, I wanted to deliver you the same as much as the simpler way with more informative content. I generally appreciate learning by doing, rather than only learning. Thank you for reading my blog! Happy learning!

RELATED POSTS

Advanced Generics: Higher-Order Functions

Advanced Generics: Higher-Order Functions

In our journey through TypeScript generics, we've covered the basics, interfaces, and classes. Now, it's time to explore advanced concepts by combining generics with higher-order functions. These functions, which take other functions as arguments or return them,...

Basic Usage of Generics in Typescript

Basic Usage of Generics in Typescript

Keypoints Show how to declare generic functions and classes in TypeScript. Provide examples of generic functions that work with different data types. Demonstrate the use of built-in generics like Array<T> and Promise<T>. Here's the content...

Getting Started with Bash Script : A Simple Guide

Getting Started with Bash Script : A Simple Guide

Introduction In this tutorial, we will be looking into Bash Script - a tool used by developers to increase productivity and manage tasks. A lot of professionals use it for tasks such as system administration, data crunching, web app development, automated backups,...

How to Extract REST API Data using Python

How to Extract REST API Data using Python

Introduction In this tutorial, we will be discussing in detail on how to extract REST API data using Python. It is one of the most popular APIs and is used by a majority of applications. We will be using VS code editor for executing the python code. The extracted API...

Create a Simple ReactJs Application – Part 1

Create a Simple ReactJs Application – Part 1

ReactJs is one of the famous front-end open-source libraries of JavaScript developed by Facebook. It aims to allow developers to quickly create fast user interfaces for websites and applications. In this blog, we will create a simple and basic ReactJs...

Create a Simple ReactJs Application – Part 2

Create a Simple ReactJs Application – Part 2

In the tutorial's last part, we discussed about ReactJs and how to run a simple react app on a web browser. In this part, we will dig more into some interesting stuff, such as creating a home, about us, and contact pages. Click here for the first part - Create a...

VIDEOS – FOLLOW US ON YOUTUBE

EXPLORE OUR IOT PROJECTS

IoT Smart Gardening System – ESP8266, MQTT, Adafruit IO

Gardening is always a very calming pastime. However, our gardens' plants may not always receive the care they require due to our active lifestyles. What if we could remotely keep an eye on their health and provide them with the attention they require? In this article,...

How to Simulate IoT projects using Cisco Packet Tracer

In this tutorial, let's learn how to simulate the IoT project using the Cisco packet tracer. As an example, we shall build a simple Home Automation project to control and monitor devices. Introduction Firstly, let's quickly look at the overview of the software. Packet...

All you need to know about integrating NodeMCU with Ubidots over MQTT

In this tutorial, let's discuss Integrating NodeMCU and Ubidots IoT platform. As an illustration, we shall interface the DHT11 sensor to monitor temperature and Humidity. Additionally, an led bulb is controlled using the dashboard. Besides, the implementation will be...

All you need to know about integrating NodeMCU with Ubidots over Https

In this tutorial, let's discuss Integrating NodeMCU and Ubidots IoT platform. As an illustration, we shall interface the DHT11 sensor to monitor temperature and Humidity. Additionally, an led bulb is controlled using the dashboard. Besides, the implementation will be...

How to design a Wireless Blind Stick using nRF24L01 Module?

Introduction Let's learn to design a low-cost wireless blind stick using the nRF24L01 transceiver module. So the complete project is divided into the transmitter part and receiver part. Thus, the Transmitter part consists of an Arduino Nano microcontroller, ultrasonic...

Sending Temperature data to ThingSpeak Cloud and Visualize

In this article, we are going to learn “How to send temperature data to ThingSpeak Cloud?”. We can then visualize the temperature data uploaded to ThingSpeak Cloud anywhere in the world. But "What is ThingSpeak?” ThingSpeak is an open-source IoT platform that allows...

Amaze your friend with latest tricks of Raspberry Pi and Firebase

Introduction to our Raspberry Pi and Firebase trick Let me introduce you to the latest trick of Raspberry Pi and Firebase we'll be using to fool them. It begins with a small circuit to connect a temperature sensor and an Infrared sensor with Raspberry Pi. The circuit...

How to implement Machine Learning on IoT based Data?

Introduction The industrial scope for the convergence of the Internet of Things(IoT) and Machine learning(ML) is wide and informative. IoT renders an enormous amount of data from various sensors. On the other hand, ML opens up insight hidden in the acquired data....

Smart Display Board based on IoT and Google Firebase

Introduction In this tutorial, we are going to build a Smart Display Board based on IoT and Google Firebase by using NodeMCU8266 (or you can even use NodeMCU32) and LCD. Generally, in shops, hotels, offices, railway stations, notice/ display boards are used. They are...

Smart Gardening System – GO GREEN Project

Automation of farm activities can transform agricultural domain from being manual into a dynamic field to yield higher production with less human intervention. The project Green is developed to manage farms using modern information and communication technologies....