├── Header ├── 1.jpg ├── 2.jpg ├── 3.jpg └── 4.jpg ├── assets ├── 0.jpg ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg └── 5.jpg ├── mouseController.py ├── Ref.md ├── .idea ├── vcs.xml ├── other.xml ├── .gitignore ├── misc.xml ├── inspectionProfiles │ ├── profiles_settings.xml │ └── Project_Default.xml ├── modules.xml └── Air-Canvas-OpenCV.iml ├── air_canvas.py ├── HandTrackingModule.py └── temp.py /Header/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/Header/1.jpg -------------------------------------------------------------------------------- /Header/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/Header/2.jpg -------------------------------------------------------------------------------- /Header/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/Header/3.jpg -------------------------------------------------------------------------------- /Header/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/Header/4.jpg -------------------------------------------------------------------------------- /assets/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/assets/0.jpg -------------------------------------------------------------------------------- /assets/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/assets/1.jpg -------------------------------------------------------------------------------- /assets/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/assets/2.jpg -------------------------------------------------------------------------------- /assets/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/assets/3.jpg -------------------------------------------------------------------------------- /assets/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/assets/4.jpg -------------------------------------------------------------------------------- /assets/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shubham8550/Air-Canvas-OpenCV/master/assets/5.jpg -------------------------------------------------------------------------------- /mouseController.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy 3 | import HandTrackingModule 4 | import time 5 | import autopy -------------------------------------------------------------------------------- /Ref.md: -------------------------------------------------------------------------------- 1 | https://www.youtube.com/watch?v=ZiwZaAVbXQo&list=WL&index=1&t=1107s 2 | https://www.youtube.com/watch?v=8gPONnGIPgw&list=WL&index=2&t=492s -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/other.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/Air-Canvas-OpenCV.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | -------------------------------------------------------------------------------- /air_canvas.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import time 3 | import HandTrackingModule as htm 4 | import numpy as np 5 | import os 6 | 7 | 8 | 9 | overlayList = [] # to store all images 10 | 11 | brushThickness =15 12 | eraserThickness = 100 13 | drawColor=(0,0,255) 14 | 15 | xp, yp = 0, 0 # Previous points 16 | imgCanvas = np.zeros((720,1280,3),np.uint8) 17 | 18 | # loading imagegs from assets 19 | folderPath = "assets" 20 | myList = os.listdir(folderPath) 21 | for imPath in myList: 22 | image = cv2.imread(f'{folderPath}/{imPath}') 23 | overlayList.append(image) 24 | header = overlayList[1] 25 | cap = cv2.VideoCapture(0) 26 | cap.set(3,1280) 27 | cap.set(4,720) 28 | 29 | detector = htm.handDetector(detectionCon=0.50,maxHands=1) #making obj 30 | 31 | while True: 32 | #import image 33 | success, img = cap.read() 34 | img=cv2.flip(img,1) 35 | # if not success: 36 | # continue 37 | 38 | # find hands Landmarks 39 | img = detector.findHands(img) 40 | lmList ,bbox =detector.findPosition(img,draw=False) 41 | 42 | if len(lmList) != 0: 43 | #print(lmList) 44 | x1,y1=lmList[8][1],lmList[8][2] # ttip of index finger 45 | x2,y2=lmList[12][1],lmList[12][2] # ttip of middle finger 46 | 47 | # check which fingers are up 48 | fingers = detector.fingersUp() 49 | 50 | # if Selection Mode - Two fingers up 51 | if fingers[1] and fingers[2]: 52 | xp,yp= 0,0 53 | 54 | #checking if index finger tip is in menu region 55 | #and for click 56 | if y1 < 120: 57 | if 34 < x1 < 234: # if im clicking at Red brush 58 | header = overlayList[1] 59 | drawColor = (0, 0, 255) 60 | elif 262 < x1 < 462:# if im clicking at Green brush 61 | header = overlayList[2] 62 | drawColor = (0, 255, 0) 63 | elif 490 < x1 < 690:# if im clicking at Blue brush 64 | header = overlayList[3] 65 | drawColor = (255, 0, 0) 66 | elif 837 < x1 < 988: # if i m clicking at eraser 67 | header = overlayList[4] 68 | drawColor = (0, 0, 0) 69 | 70 | cv2.rectangle(img, (x1, y1 - 25), (x2, y2 + 25), drawColor,cv2.FILLED) # selection mode is represented as rectangle 71 | 72 | # if drawing Mode - index finger is up 73 | if fingers[1] and fingers[2] == False: 74 | cv2.circle(img, (x1, y1),15,drawColor,cv2.FILLED) # drawing mode is represented as circle 75 | 76 | if xp == 0 and yp == 0: # initially xp and yp will be at 0,0 so it will draw a line from 0,0 to whichever point our tip is at 77 | xp, yp = x1, y1 # so to avoid that we set xp=x1 and yp=y1 78 | # till now we are creating our drawing but it gets removed as everytime our frames are updating so we have to define our canvas where we can draw and show also 79 | 80 | #eraser 81 | if drawColor == (0,0,0): 82 | cv2.line(img,(xp,yp), (x1, y1),drawColor,eraserThickness) 83 | cv2.line(imgCanvas, (xp, yp), (x1, y1), drawColor, eraserThickness) 84 | else: 85 | cv2.line(img, (xp, yp), (x1, y1), drawColor,brushThickness) # gonna draw lines from previous coodinates to new positions 86 | cv2.line(imgCanvas, (xp, yp), (x1, y1), drawColor, brushThickness) 87 | 88 | xp,yp =x1,y1 #writing history 89 | else: 90 | xp,yp = 0, 0 91 | 92 | # merging two windows into one imgcanvas and img 93 | 94 | # 1 converting img to gray 95 | imgGray = cv2.cvtColor(imgCanvas, cv2.COLOR_BGR2GRAY) 96 | 97 | # 2 converting into binary image and thn inverting 98 | _, imgInv = cv2.threshold(imgGray, 50, 255, cv2.THRESH_BINARY_INV) # on canvas all the region in which we drew is black and where it is black it is cosidered as white,it will create a mask 99 | 100 | imgInv = cv2.cvtColor(imgInv, cv2.COLOR_GRAY2BGR) # converting again to gray bcoz we have to add in a RGB image i.e img 101 | 102 | # add original img with imgInv ,by doing this we get our drawing only in black color 103 | img = cv2.bitwise_and(img, imgInv) 104 | 105 | # add img and imgcanvas,by doing this we get colors on img 106 | img = cv2.bitwise_or(img, imgCanvas) 107 | 108 | # setting the header image 109 | img[0:120, 0:1280] = header # on our frame we are setting our JPG image acc to H,W of jpg images 110 | 111 | cv2.imshow("Image", img) 112 | # cv2.imshow("Canvas", imgCanvas) 113 | # cv2.imshow("Inv", imgInv) 114 | cv2.waitKey(1) 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /HandTrackingModule.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | import time 4 | import math 5 | import numpy as np 6 | 7 | class handDetector(): 8 | def __init__(self,mode=False,maxHands=2,detectionCon=0.5,trackCon=0.5):#constructor 9 | self.mode=mode 10 | self.maxHands=maxHands 11 | self.detectionCon=detectionCon 12 | self.trackCon=trackCon 13 | self.mpHands=mp.solutions.hands#initializing hands module for the instance 14 | self.hands=self.mpHands.Hands(self.mode,self.maxHands,1,self.detectionCon,self.trackCon) #object for Hands for a particular instance 15 | self.mpDraw=mp.solutions.drawing_utils#object for Drawing 16 | self.tipIds = [4, 8, 12, 16, 20] 17 | 18 | def findHands(self,img,draw=True): 19 | imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#converting to RGB bcoz hand recognition works only on RGB image 20 | self.results=self.hands.process(imgRGB)#processing the RGB image 21 | if self.results.multi_hand_landmarks:# gives x,y,z of every landmark or if no hand than NONE 22 | for handLms in self.results.multi_hand_landmarks:#each hand landmarks in results 23 | if draw: 24 | self.mpDraw.draw_landmarks(img,handLms,self.mpHands.HAND_CONNECTIONS)#joining points on our hand 25 | 26 | return img 27 | 28 | def findPosition(self,img,handNo=0,draw=True): 29 | xList=[] 30 | yList=[] 31 | bbox=[] 32 | self.lmlist=[] 33 | if self.results.multi_hand_landmarks:# gives x,y,z of every landmark 34 | myHand=self.results.multi_hand_landmarks[handNo]#Gives result for particular hand 35 | for id,lm in enumerate(myHand.landmark):#gives id and lm(x,y,z) 36 | h,w,c=img.shape#getting h,w for converting decimals x,y into pixels 37 | cx,cy=int(lm.x*w),int(lm.y*h)# pixels coordinates for landmarks 38 | # print(id, cx, cy) 39 | xList.append(cx) 40 | yList.append(cy) 41 | self.lmlist.append([id,cx,cy]) 42 | if draw: 43 | cv2.circle(img,(cx,cy),5,(255,0,255),cv2.FILLED) 44 | xmin,xmax=min(xList),max(xList) 45 | ymin,ymax=min(yList),max(yList) 46 | bbox=xmin,ymin,xmax,ymax 47 | 48 | if draw: 49 | cv2.rectangle(img,(bbox[0]-20,bbox[1]-20),(bbox[2]+20,bbox[3]+20),(0,255,0),2) 50 | 51 | return self.lmlist,bbox 52 | 53 | def fingersUp(self):#checking which finger is open 54 | fingers = []#storing final result 55 | # Thumb < sign only when we use flip function to avoid mirror inversion else > sign 56 | if self.lmlist[self.tipIds[0]][1] > self.lmlist[self.tipIds[0] - 1][1]:#checking x position of 4 is in right to x position of 3 57 | fingers.append(1) 58 | else: 59 | fingers.append(0) 60 | 61 | # Fingers 62 | for id in range(1, 5):#checking tip point is below tippoint-2 (only in Y direction) 63 | if self.lmlist[self.tipIds[id]][2] < self.lmlist[self.tipIds[id] - 2][2]: 64 | fingers.append(1) 65 | else: 66 | fingers.append(0) 67 | 68 | # totalFingers = fingers.count(1) 69 | 70 | return fingers 71 | 72 | def findDistance(self, p1, p2, img, draw=True,r=15,t=3):# finding distance between two points p1 & p2 73 | x1, y1 = self.lmlist[p1][1],self.lmlist[p1][2]#getting x,y of p1 74 | x2, y2 = self.lmlist[p2][1],self.lmlist[p2][2]#getting x,y of p2 75 | cx, cy = (x1 + x2) // 2, (y1 + y2) // 2#getting centre point 76 | 77 | if draw: #drawing line and circles on the points 78 | cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), t) 79 | cv2.circle(img, (x1, y1), r, (255, 0, 255), cv2.FILLED) 80 | cv2.circle(img, (x2, y2), r, (255, 0, 255), cv2.FILLED) 81 | cv2.circle(img, (cx, cy), r, (0, 0, 255), cv2.FILLED) 82 | 83 | length = math.hypot(x2 - x1, y2 - y1) 84 | 85 | return length, img, [x1, y1, x2, y2, cx, cy] 86 | 87 | 88 | def main(): 89 | 90 | PTime=0# previous time 91 | CTime=0# current time 92 | cap=cv2.VideoCapture(0) 93 | detector=handDetector() 94 | 95 | while True: 96 | success,img=cap.read()#T or F,frame 97 | img =detector.findHands(img) 98 | lmlist,bbox= detector.findPosition(img) 99 | if len(lmlist)!=0: 100 | print(lmlist[4]) 101 | 102 | CTime=time.time()#current time 103 | fps=1/(CTime-PTime)#FPS 104 | PTime=CTime#previous time is replaced by current time 105 | 106 | cv2.putText(img,str(int(fps)),(10,70),cv2.FONT_HERSHEY_COMPLEX,3,(255,0,255),3)# showing Fps on screen 107 | 108 | 109 | cv2.imshow("Image",img)#showing img not imgRGB 110 | cv2.waitKey(1) 111 | 112 | 113 | if __name__=="__main__": 114 | main() -------------------------------------------------------------------------------- /temp.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import time 3 | import HandTrackingModule as htm 4 | import numpy as np 5 | import os 6 | 7 | overlayList = [] # list to store all the images 8 | 9 | brushThickness = 25 10 | eraserThickness = 100 11 | drawColor = (255, 0, 255) # setting purple color 12 | 13 | xp, yp = 0, 0 14 | imgCanvas = np.zeros((720, 1280, 3), np.uint8) # defining canvas 15 | 16 | # images in header folder 17 | folderPath = "Header" 18 | myList = os.listdir(folderPath) # getting all the images used in code 19 | # print(myList) 20 | for imPath in myList: # reading all the images from the folder 21 | image = cv2.imread(f'{folderPath}/{imPath}') 22 | overlayList.append(image) # inserting images one by one in the overlayList 23 | header = overlayList[0] # storing 1st image 24 | cap = cv2.VideoCapture(0) 25 | cap.set(3, 1280) # width 26 | cap.set(4, 720) # height 27 | 28 | detector = htm.handDetector(detectionCon=0.50, maxHands=1) # making object 29 | 30 | while True: 31 | 32 | # 1. Import image 33 | success, img = cap.read() 34 | img = cv2.flip(img, 1) # for neglecting mirror inversion 35 | 36 | # 2. Find Hand Landmarks 37 | img = detector.findHands(img) # using functions fo connecting landmarks 38 | lmList, bbox = detector.findPosition(img, 39 | draw=False) # using function to find specific landmark position,draw false means no circles on landmarks 40 | 41 | if len(lmList) != 0: 42 | # print(lmList) 43 | x1, y1 = lmList[8][1], lmList[8][2] # tip of index finger 44 | x2, y2 = lmList[12][1], lmList[12][2] # tip of middle finger 45 | 46 | # 3. Check which fingers are up 47 | fingers = detector.fingersUp() 48 | # print(fingers) 49 | 50 | # 4. If Selection Mode - Two finger are up 51 | if fingers[1] and fingers[2]: 52 | xp, yp = 0, 0 53 | # print("Selection Mode") 54 | # checking for click 55 | if y1 < 125: 56 | if 250 < x1 < 450: # if i m clicking at purple brush 57 | header = overlayList[0] 58 | drawColor = (255, 0, 255) 59 | elif 550 < x1 < 750: # if i m clicking at blue brush 60 | header = overlayList[1] 61 | drawColor = (255, 0, 0) 62 | elif 800 < x1 < 950: # if i m clicking at green brush 63 | header = overlayList[2] 64 | drawColor = (0, 255, 0) 65 | elif 1050 < x1 < 1200: # if i m clicking at eraser 66 | header = overlayList[3] 67 | drawColor = (0, 0, 0) 68 | cv2.rectangle(img, (x1, y1 - 25), (x2, y2 + 25), drawColor, 69 | cv2.FILLED) # selection mode is represented as rectangle 70 | 71 | # 5. If Drawing Mode - Index finger is up 72 | if fingers[1] and fingers[2] == False: 73 | cv2.circle(img, (x1, y1), 15, drawColor, cv2.FILLED) # drawing mode is represented as circle 74 | # print("Drawing Mode") 75 | if xp == 0 and yp == 0: # initially xp and yp will be at 0,0 so it will draw a line from 0,0 to whichever point our tip is at 76 | xp, yp = x1, y1 # so to avoid that we set xp=x1 and yp=y1 77 | # till now we are creating our drawing but it gets removed as everytime our frames are updating so we have to define our canvas where we can draw and show also 78 | 79 | # eraser 80 | if drawColor == (0, 0, 0): 81 | cv2.line(img, (xp, yp), (x1, y1), drawColor, eraserThickness) 82 | cv2.line(imgCanvas, (xp, yp), (x1, y1), drawColor, eraserThickness) 83 | else: 84 | cv2.line(img, (xp, yp), (x1, y1), drawColor, 85 | brushThickness) # gonna draw lines from previous coodinates to new positions 86 | cv2.line(imgCanvas, (xp, yp), (x1, y1), drawColor, brushThickness) 87 | xp, yp = x1, y1 # giving values to xp,yp everytime 88 | else: 89 | xp, yp = 0, 0 90 | 91 | # merging two windows into one imgcanvas and img 92 | 93 | # 1 converting img to gray 94 | imgGray = cv2.cvtColor(imgCanvas, cv2.COLOR_BGR2GRAY) 95 | 96 | # 2 converting into binary image and thn inverting 97 | _, imgInv = cv2.threshold(imgGray, 50, 255, 98 | cv2.THRESH_BINARY_INV) # on canvas all the region in which we drew is black and where it is black it is cosidered as white,it will create a mask 99 | 100 | imgInv = cv2.cvtColor(imgInv, 101 | cv2.COLOR_GRAY2BGR) # converting again to gray bcoz we have to add in a RGB image i.e img 102 | 103 | # add original img with imgInv ,by doing this we get our drawing only in black color 104 | img = cv2.bitwise_and(img, imgInv) 105 | 106 | # add img and imgcanvas,by doing this we get colors on img 107 | img = cv2.bitwise_or(img, imgCanvas) 108 | 109 | # setting the header image 110 | img[0:125, 0:1280] = header # on our frame we are setting our JPG image acc to H,W of jpg images 111 | 112 | cv2.imshow("Image", img) 113 | # cv2.imshow("Canvas", imgCanvas) 114 | # cv2.imshow("Inv", imgInv) 115 | cv2.waitKey(1) --------------------------------------------------------------------------------