Skip to content

Commit

Permalink
Merge pull request #267 from Rohit131313/aivirtualpainter
Browse files Browse the repository at this point in the history
Added a new project Aivirtualpainter
  • Loading branch information
UTSAVS26 authored Oct 8, 2024
2 parents f6ebe43 + 0108c51 commit 467e41d
Show file tree
Hide file tree
Showing 14 changed files with 311 additions and 0 deletions.
89 changes: 89 additions & 0 deletions Data_Science/AI Virtual Painter/HandTrackingModule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import cv2
import mediapipe as mp
import math

class handDetector():
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.trackCon = trackCon

self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(
static_image_mode=self.mode,
max_num_hands=self.maxHands,
min_detection_confidence=self.detectionCon,
min_tracking_confidence=self.trackCon
)
self.mpDraw = mp.solutions.drawing_utils
self.tipIds = [4, 8, 12, 16, 20]

def findHands(self, img, draw=True):
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(imgRGB)

if self.results.multi_hand_landmarks:
for handLms in self.results.multi_hand_landmarks:
if draw:
self.mpDraw.draw_landmarks(img, handLms,
self.mpHands.HAND_CONNECTIONS)

return img

def findPosition(self, img, handNo=0, draw=True):
xList = []
yList = []
bbox = []
self.lmList = []
if self.results.multi_hand_landmarks:
myHand = self.results.multi_hand_landmarks[handNo]
for id, lm in enumerate(myHand.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
xList.append(cx)
yList.append(cy)
self.lmList.append([id, cx, cy])
if draw:
cv2.circle(img, (cx, cy), 5, (255, 0, 255), cv2.FILLED)

xmin, xmax = min(xList), max(xList)
ymin, ymax = min(yList), max(yList)
bbox = xmin, ymin, xmax, ymax

if draw:
cv2.rectangle(img, (xmin - 20, ymin - 20), (xmax + 20, ymax + 20),
(0, 255, 0), 2)

return self.lmList, bbox

def fingersUp(self):
fingers = []
# Thumb
if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]:
fingers.append(1)
else:
fingers.append(0)

# Fingers
for id in range(1, 5):
if self.lmList[self.tipIds[id]][2] < self.lmList[self.tipIds[id] - 2][2]:
fingers.append(1)
else:
fingers.append(0)

return fingers

def findDistance(self, p1, p2, img, draw=True,r=15, t=3):
x1, y1 = self.lmList[p1][1:]
x2, y2 = self.lmList[p2][1:]
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2

if draw:
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), t)
cv2.circle(img, (x1, y1), r, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (x2, y2), r, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (cx, cy), r, (0, 0, 255), cv2.FILLED)
length = math.hypot(x2 - x1, y2 - y1)

return length, img, [x1, y1, x2, y2, cx, cy]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 91 additions & 0 deletions Data_Science/AI Virtual Painter/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# AI Virtual Painter Project

## AIM
Create a real-time interactive AI tool that uses hand gestures to allow users to paint or draw virtually using their camera feed.

## DESCRIPTION
The **AI Virtual Painter** project utilizes computer vision techniques to detect hand gestures and track finger movements in real-time, transforming these gestures into painting or drawing actions on the screen. This project leverages libraries like OpenCV and MediaPipe for hand detection and tracking, allowing users to interact with the system through gestures.

### Why is this project necessary?
This project showcases the innovative application of AI in enhancing user interaction without physical touch, particularly useful in creating virtual experiences. It’s beneficial for artists, educators, and anyone looking for creative ways to engage with digital tools.

### How is it beneficial and used?
The virtual painter can be used for:
- Teaching and creative drawing experiences.
- Gesture-controlled applications.
- Fun and interactive painting applications.

### How did you start approaching this project?
I began by researching hand detection techniques and gesture-based controls using OpenCV and MediaPipe. After building a basic hand-tracking system, I incrementally added drawing capabilities, color selection, and an eraser feature.

## EXPLANATION

### DETAILS OF THE DIFFERENT FEATURES
1. **Hand Detection and Tracking**: Using MediaPipe to detect and track hand landmarks.
2. **Drawing**: Raising the index finger allows the user to draw on the screen.
3. **Color Selection**: Both index and middle fingers raised allows color selection from the virtual palette.
4. **Eraser**: Switches to eraser mode based on the gesture selection.

### WHAT I HAVE DONE
1. Implemented real-time camera feed capture.
2. Integrated hand detection using MediaPipe.
3. Added virtual painting and erasing capabilities.
4. Created gesture-based interaction for selecting different colors and tools.
5. Implemented a virtual header to house drawing tools.
6. Enhanced the system for smooth tracking and minimal lag.

### Controls for the AI Virtual Painter

#### 1. Header Interaction
- Use your right hand with both the **index and middle fingers** raised to hover over the header.
- This gesture allows you to select between different tools and colors: **pink, blue, green**, or the **eraser**.

#### 2. Drawing and Erasing
- Raise only your **index finger** to draw or erase on the screen.
- The action (drawing or erasing) depends on your current selection from the header.

#### 3. Gesture Control
- Ensure that your hand gestures are clear and visible to guarantee smooth interaction.
- This will help in achieving precise drawing and erasing operations.

### LIBRARIES NEEDED
- OpenCV
- MediaPipe
- NumPy

### SCREENSHOTS
1. **Project structure**:
![Project Structure](Images/treediagram.png)
2. **Visualization of hand tracking and painting actions**:
![Hand Tracking](Images/Project.png)

### MODELS USED AND THEIR ACCURACIES
This project does not involve traditional ML models but instead focuses on real-time computer vision for gesture detection.


## CONCLUSION

### WHAT YOU HAVE LEARNED
- Real-time hand detection and tracking using MediaPipe.
- Gesture-based interaction for virtual environments.
- Building interactive applications with minimal lag using computer vision.

### USE CASES OF THIS MODEL
1. **Virtual Art Studio**: Artists can create digital art using hand gestures without any physical tools.
2. **Interactive Teaching Tool**: Teachers can engage students by drawing and explaining concepts interactively.

### HOW TO INTEGRATE THIS MODEL IN REAL WORLD
1. **Prepare the data pipeline**: Ensure a high-quality camera feed is available for smooth hand-tracking.
2. **Deploy the model**: Use tools like Flask or Streamlit to deploy the AI Virtual Painter as a web application.
3. **Monitor and maintain**: Keep the hand detection models updated for improved accuracy in future versions.

### FEATURES PLANNED BUT NOT IMPLEMENTED
- **Save Drawings Feature**: The ability to save drawings created on the virtual canvas.
- **Multi-user Interaction**: Supporting multiple users in real-time.

*Rohit Motwani*

[![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/rohit-motwani1313/)

#### Happy Coding 🧑‍💻
### Show some &nbsp;❤️&nbsp; by &nbsp;🌟&nbsp; this repository!
100 changes: 100 additions & 0 deletions Data_Science/AI Virtual Painter/VirtualPainter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import cv2
import numpy as np
import os
import HandTrackingModule as htm

#######################
brushThickness = 25
eraserThickness = 40
########################

folderPath = "Header Files"
myList = os.listdir(folderPath)
overlayList = []
for imPath in myList:
image = cv2.imread(f'{folderPath}/{imPath}')
overlayList.append(image)

header = overlayList[0]
drawColor = (255, 0, 255)

cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

detector = htm.handDetector(detectionCon=0.65, maxHands=1)
xp, yp = 0, 0
imgCanvas = np.zeros((720, 1280, 3), np.uint8)

eraser = False
while True:
# 1. Import image
success, img = cap.read()
img = cv2.flip(img, 1)

# 2. Find Hand Landmarks
img = detector.findHands(img)
lmList, bbox = detector.findPosition(img, draw=False)
if len(lmList) != 0:
# tip of index and middle fingers
x1, y1 = lmList[8][1:]
x2, y2 = lmList[12][1:]

# 3. Check which fingers are up
fingers = detector.fingersUp()

# 4. If Selection Mode – Two fingers are up
if fingers[1] and fingers[2]:
# Checking for the click
if y1 < 125:
if 250 < x1 < 450:
eraser = False
header = overlayList[0]
drawColor = (255, 0, 255)
elif 550 < x1 < 750:
eraser = False
header = overlayList[1]
drawColor = (250, 0, 0)
elif 800 < x1 < 950:
eraser = False
header = overlayList[2]
drawColor = (0, 255, 0)
elif 1050 < x1 < 1200:
eraser = True
header = overlayList[3]
drawColor = (0, 0, 0)
cv2.rectangle(img, (x1, y1 - 25), (x2, y2 + 25), drawColor, cv2.FILLED)
xp, yp = 0, 0

# 5. If Drawing Mode – Index finger is up
if fingers[1] and not fingers[2]:
cv2.circle(img, (x1, y1), 15, drawColor, cv2.FILLED)
if xp == 0 and yp == 0:
xp, yp = x1, y1

if eraser:
cv2.line(imgCanvas, (xp, yp), (x1, y1), drawColor, eraserThickness)
else:
cv2.line(imgCanvas, (xp, yp), (x1, y1), drawColor, brushThickness)


xp, yp = x1, y1

# # Modify canvas
imgGray = cv2.cvtColor(imgCanvas, cv2.COLOR_BGR2GRAY)
_, imgInv = cv2.threshold(imgGray, 50, 255, cv2.THRESH_BINARY_INV)
imgInv = cv2.cvtColor(imgInv, cv2.COLOR_GRAY2BGR)
img = cv2.bitwise_and(img, imgInv)
img = cv2.bitwise_or(img, imgCanvas)

height, width, channel = header.shape
# Setting the header image
img[0:height, 0:1280] = header

cv2.imshow("Image", img)

if cv2.waitKey(1) & 0xFF == ord('q'):
break

cv2.destroyAllWindows()
cap.release()
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions Data_Science/AI Virtual Painter/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
matplotlib==3.9.2
mediapipe==0.10.14
numpy==1.26.4
opencv-contrib-python==4.10.0.84

13 changes: 13 additions & 0 deletions Repo-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,19 @@
│ └── Readme.md
├── Data_Science
│ ├── Data-science.md
│ ├── AI Virtual Painter
│ ├── Header Files
│ ├── header 1.png
│ ├── header 2.png
│ ├── header 3.png
│ ├── header 4.png
│ ├── Images
│ ├── Project.png
│ ├── treediagram.png
│ ├── HandTrackingModule.py
│ ├── Readme.md
│ ├── requirements.txt
│ ├── VirtualPainter.py
│ ├── Whatsapp_Chat_Analyzer
│ │ ├── README.md
│ │ ├── Sample_Data
Expand Down
13 changes: 13 additions & 0 deletions repo_structure.txt
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,19 @@
│ └── Readme.md
├── Data_Science
│ ├── Data-science.md
│ ├── AI Virtual Painter
│ ├── Header Files
│ ├── header 1.png
│ ├── header 2.png
│ ├── header 3.png
│ ├── header 4.png
│ ├── Images
│ ├── Project.png
│ ├── treediagram.png
│ ├── HandTrackingModule.py
│ ├── Readme.md
│ ├── requirements.txt
│ ├── VirtualPainter.py
│ ├── Whatsapp_Chat_Analyzer
│ │ ├── README.md
│ │ ├── Sample_Data
Expand Down

0 comments on commit 467e41d

Please sign in to comment.