├── 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 |
5 |
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 |
4 |
5 |
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 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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)
--------------------------------------------------------------------------------