batch24-28 1.2.3__tar.gz → 1.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {batch24_28-1.2.3/src/batch24_28.egg-info → batch24_28-1.2.4}/PKG-INFO +32 -3
- batch24_28-1.2.3/PKG-INFO → batch24_28-1.2.4/README.md +22 -9
- batch24_28-1.2.4/pyproject.toml +21 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/__init__.py +3 -2
- batch24_28-1.2.4/src/batch24_28/vision.py +187 -0
- batch24_28-1.2.3/README.md → batch24_28-1.2.4/src/batch24_28.egg-info/PKG-INFO +39 -1
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28.egg-info/SOURCES.txt +1 -0
- batch24_28-1.2.4/src/batch24_28.egg-info/requires.txt +9 -0
- batch24_28-1.2.3/pyproject.toml +0 -10
- batch24_28-1.2.3/src/batch24_28.egg-info/requires.txt +0 -2
- {batch24_28-1.2.3 → batch24_28-1.2.4}/setup.cfg +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/art.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/calculator.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/chess_game.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/from .py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/games.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/monitor.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/reporter.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/timers.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28/watcher.py +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28.egg-info/dependency_links.txt +0 -0
- {batch24_28-1.2.3 → batch24_28-1.2.4}/src/batch24_28.egg-info/top_level.txt +0 -0
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batch24-28
|
|
3
|
-
Version: 1.2.
|
|
4
|
-
Summary: A multi featured Python terminal
|
|
5
|
-
Requires-Python: >=3.
|
|
3
|
+
Version: 1.2.4
|
|
4
|
+
Summary: A multi featured Python terminal and vision toolkit
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
Requires-Dist: psutil
|
|
8
8
|
Requires-Dist: watchdog
|
|
9
|
+
Requires-Dist: opencv-python
|
|
10
|
+
Requires-Dist: mediapipe==0.10.21
|
|
11
|
+
Requires-Dist: fer
|
|
12
|
+
Requires-Dist: tensorflow==2.17.0
|
|
13
|
+
Requires-Dist: protobuf==4.25.9
|
|
14
|
+
Requires-Dist: setuptools==81.0.0
|
|
15
|
+
Requires-Dist: python-chess
|
|
9
16
|
|
|
10
17
|
|
|
11
18
|
# batch24-28
|
|
@@ -145,3 +152,25 @@ from batch24_28 import start_file_watcher
|
|
|
145
152
|
# Watch the current directory
|
|
146
153
|
start_file_watcher(path=".")
|
|
147
154
|
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 10. Computer Vision & Emotion Analysis Toolkit
|
|
159
|
+
|
|
160
|
+
An interactive computer vision pipeline powered by MediaPipe hand-tracking and deep learning emotion recognition. Includes virtual mid-air drawing (Air Canvas) and facial expression tracking via webcam, static images, or video files.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from batch24_28 import VisionAnalyzer
|
|
164
|
+
|
|
165
|
+
analyzer = VisionAnalyzer()
|
|
166
|
+
|
|
167
|
+
# Option A: Run live Air Canvas and Emotion detection via webcam
|
|
168
|
+
analyzer.run_air_canvas(run_draw=True, run_emotion=True)
|
|
169
|
+
|
|
170
|
+
# Option B: Analyze facial expression from a static image file
|
|
171
|
+
emotion, score, img = analyzer.analyze_image_file("path_to_image.jpg")
|
|
172
|
+
print(f"Detected: {emotion} ({int(score * 100)}%)")
|
|
173
|
+
|
|
174
|
+
# Option C: Stream and analyze a video file for expressions
|
|
175
|
+
analyzer.analyze_video_file("path_to_video.mp4")
|
|
176
|
+
```
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: batch24-28
|
|
3
|
-
Version: 1.2.3
|
|
4
|
-
Summary: A multi featured Python terminal
|
|
5
|
-
Requires-Python: >=3.7
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: psutil
|
|
8
|
-
Requires-Dist: watchdog
|
|
9
|
-
|
|
10
1
|
|
|
11
2
|
# batch24-28
|
|
12
3
|
|
|
@@ -145,3 +136,25 @@ from batch24_28 import start_file_watcher
|
|
|
145
136
|
# Watch the current directory
|
|
146
137
|
start_file_watcher(path=".")
|
|
147
138
|
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### 10. Computer Vision & Emotion Analysis Toolkit
|
|
143
|
+
|
|
144
|
+
An interactive computer vision pipeline powered by MediaPipe hand-tracking and deep learning emotion recognition. Includes virtual mid-air drawing (Air Canvas) and facial expression tracking via webcam, static images, or video files.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from batch24_28 import VisionAnalyzer
|
|
148
|
+
|
|
149
|
+
analyzer = VisionAnalyzer()
|
|
150
|
+
|
|
151
|
+
# Option A: Run live Air Canvas and Emotion detection via webcam
|
|
152
|
+
analyzer.run_air_canvas(run_draw=True, run_emotion=True)
|
|
153
|
+
|
|
154
|
+
# Option B: Analyze facial expression from a static image file
|
|
155
|
+
emotion, score, img = analyzer.analyze_image_file("path_to_image.jpg")
|
|
156
|
+
print(f"Detected: {emotion} ({int(score * 100)}%)")
|
|
157
|
+
|
|
158
|
+
# Option C: Stream and analyze a video file for expressions
|
|
159
|
+
analyzer.analyze_video_file("path_to_video.mp4")
|
|
160
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "batch24-28"
|
|
7
|
+
version = "1.2.4"
|
|
8
|
+
description = "A multi featured Python terminal and vision toolkit"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"psutil",
|
|
13
|
+
"watchdog",
|
|
14
|
+
"opencv-python",
|
|
15
|
+
"mediapipe==0.10.21",
|
|
16
|
+
"fer",
|
|
17
|
+
"tensorflow==2.17.0",
|
|
18
|
+
"protobuf==4.25.9",
|
|
19
|
+
"setuptools==81.0.0",
|
|
20
|
+
"python-chess"
|
|
21
|
+
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ = "1.2.
|
|
1
|
+
__version__ = "1.2.4"
|
|
2
2
|
|
|
3
3
|
from .timers import start_countdown, start_stopwatch, run_interactive_timer
|
|
4
4
|
from .art import print_hello
|
|
@@ -7,4 +7,5 @@ from .games import RockPaperScissors
|
|
|
7
7
|
from .chess_game import TerminalChess
|
|
8
8
|
from .watcher import start_file_watcher
|
|
9
9
|
from .monitor import monitor_performance
|
|
10
|
-
from .reporter import generate_system_report
|
|
10
|
+
from .reporter import generate_system_report
|
|
11
|
+
from .vision import VisionAnalyzer
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import math
|
|
3
|
+
import time
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
class VisionAnalyzer:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.colors = {
|
|
9
|
+
"BLUE": (255, 0, 0),
|
|
10
|
+
"GREEN": (0, 255, 0),
|
|
11
|
+
"RED": (0, 0, 255),
|
|
12
|
+
"YELLOW": (0, 255, 255)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def analyze_image_file(self, img_path):
|
|
16
|
+
"""Analyzes facial emotion from a static image file."""
|
|
17
|
+
from fer.fer import FER
|
|
18
|
+
if not os.path.exists(img_path):
|
|
19
|
+
raise FileNotFoundError(f"Image not found at: {img_path}")
|
|
20
|
+
|
|
21
|
+
detector = FER(mtcnn=False)
|
|
22
|
+
img = cv2.imread(img_path)
|
|
23
|
+
dominant_emotion, score = detector.top_emotion(img)
|
|
24
|
+
|
|
25
|
+
if dominant_emotion is None:
|
|
26
|
+
dominant_emotion = "Neutral"
|
|
27
|
+
score = 0.0
|
|
28
|
+
|
|
29
|
+
return dominant_emotion, score, img
|
|
30
|
+
|
|
31
|
+
def analyze_video_file(self, vid_path):
|
|
32
|
+
"""Streams and analyzes facial emotion from a video file."""
|
|
33
|
+
from fer.fer import FER
|
|
34
|
+
if not os.path.exists(vid_path):
|
|
35
|
+
raise FileNotFoundError(f"Video not found at: {vid_path}")
|
|
36
|
+
|
|
37
|
+
detector = FER(mtcnn=False)
|
|
38
|
+
cap = cv2.VideoCapture(vid_path)
|
|
39
|
+
|
|
40
|
+
while cap.isOpened():
|
|
41
|
+
success, frame = cap.read()
|
|
42
|
+
if not success:
|
|
43
|
+
break
|
|
44
|
+
|
|
45
|
+
dominant_emotion, score = detector.top_emotion(frame)
|
|
46
|
+
if dominant_emotion is None:
|
|
47
|
+
dominant_emotion = "Neutral"
|
|
48
|
+
score = 0.0
|
|
49
|
+
|
|
50
|
+
expression_text = f"Emotion: {dominant_emotion.capitalize()} ({int(score * 100)}%)"
|
|
51
|
+
cv2.putText(frame, expression_text, (30, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
|
|
52
|
+
|
|
53
|
+
cv2.imshow('Video Emotion Analysis', frame)
|
|
54
|
+
if cv2.waitKey(25) & 0xFF == ord('q'):
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
cap.release()
|
|
58
|
+
cv2.destroyAllWindows()
|
|
59
|
+
|
|
60
|
+
def run_air_canvas(self, run_draw=True, run_emotion=True):
|
|
61
|
+
"""Runs the live webcam pipeline for Air Canvas and/or Emotion Detection."""
|
|
62
|
+
from fer.fer import FER
|
|
63
|
+
import mediapipe as mp
|
|
64
|
+
|
|
65
|
+
emotion_detector = FER(mtcnn=False) if run_emotion else None
|
|
66
|
+
mp_hands = mp.solutions.hands if run_draw else None
|
|
67
|
+
mp_drawing = mp.solutions.drawing_utils if run_draw else None
|
|
68
|
+
|
|
69
|
+
strokes = []
|
|
70
|
+
current_stroke = []
|
|
71
|
+
cap = cv2.VideoCapture(0)
|
|
72
|
+
|
|
73
|
+
PINCH_THRESHOLD = 42
|
|
74
|
+
ERASER_RADIUS = 35
|
|
75
|
+
is_drawing = False
|
|
76
|
+
tool_mode = "DRAW"
|
|
77
|
+
current_color_name = "GREEN"
|
|
78
|
+
current_color = self.colors[current_color_name]
|
|
79
|
+
|
|
80
|
+
save_message_timer = 0
|
|
81
|
+
prev_ix, prev_iy = 0, 0
|
|
82
|
+
smoothing_factor = 0.5
|
|
83
|
+
|
|
84
|
+
hands_obj = mp_hands.Hands(min_detection_confidence=0.75, min_tracking_confidence=0.75) if run_draw else None
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
while cap.isOpened():
|
|
88
|
+
success, frame = cap.read()
|
|
89
|
+
if not success:
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
frame = cv2.flip(frame, 1)
|
|
93
|
+
h, w, _ = frame.shape
|
|
94
|
+
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
95
|
+
|
|
96
|
+
expression_text = ""
|
|
97
|
+
expression_color = (200, 200, 200)
|
|
98
|
+
|
|
99
|
+
if run_emotion and emotion_detector:
|
|
100
|
+
dominant_emotion, score = emotion_detector.top_emotion(frame)
|
|
101
|
+
if dominant_emotion is None:
|
|
102
|
+
dominant_emotion = "Neutral"
|
|
103
|
+
score = 0.0
|
|
104
|
+
expression_text = f"Emotion: {dominant_emotion.capitalize()} ({int(score * 100)}%)"
|
|
105
|
+
expression_color = (0, 255, 255) if dominant_emotion == "happy" else (200, 200, 200)
|
|
106
|
+
|
|
107
|
+
if run_draw:
|
|
108
|
+
box_width, box_height, box_y = 90, 40, 15
|
|
109
|
+
palette_x = 50
|
|
110
|
+
|
|
111
|
+
for name, col in self.colors.items():
|
|
112
|
+
thickness = 3 if current_color_name == name and tool_mode == "DRAW" else 1
|
|
113
|
+
cv2.rectangle(frame, (palette_x, box_y), (palette_x + box_width, box_y + box_height), col, -1)
|
|
114
|
+
cv2.rectangle(frame, (palette_x, box_y), (palette_x + box_width, box_y + box_height), (255, 255, 255), thickness)
|
|
115
|
+
cv2.putText(frame, name, (palette_x + 10, box_y + 26), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (255, 255, 255), 1)
|
|
116
|
+
palette_x += 105
|
|
117
|
+
|
|
118
|
+
mode_text = f"MODE: DRAW | Color: {current_color_name} ('e' to Erase)" if tool_mode == "DRAW" else "MODE: ERASER ('e' to Draw)"
|
|
119
|
+
mode_color = current_color if tool_mode == "DRAW" else (0, 165, 255)
|
|
120
|
+
|
|
121
|
+
hand_results = hands_obj.process(rgb_frame)
|
|
122
|
+
if hand_results.multi_hand_landmarks:
|
|
123
|
+
for hand_landmarks in hand_results.multi_hand_landmarks:
|
|
124
|
+
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
|
|
125
|
+
thumb_tip = hand_landmarks.landmark[4]
|
|
126
|
+
index_tip = hand_landmarks.landmark[8]
|
|
127
|
+
|
|
128
|
+
raw_ix, raw_iy = int(index_tip.x * w), int(index_tip.y * h)
|
|
129
|
+
tx, ty = int(thumb_tip.x * w), int(thumb_tip.y * h)
|
|
130
|
+
|
|
131
|
+
ix = int(prev_ix * smoothing_factor + raw_ix * (1 - smoothing_factor))
|
|
132
|
+
iy = int(prev_iy * smoothing_factor + raw_iy * (1 - smoothing_factor))
|
|
133
|
+
prev_ix, prev_iy = ix, iy
|
|
134
|
+
|
|
135
|
+
distance = math.hypot(ix - tx, iy - ty)
|
|
136
|
+
|
|
137
|
+
if iy < box_y + box_height + 10:
|
|
138
|
+
p_x = 50
|
|
139
|
+
for name in self.colors.keys():
|
|
140
|
+
if p_x <= ix <= p_x + box_width:
|
|
141
|
+
current_color_name = name
|
|
142
|
+
current_color = self.colors[name]
|
|
143
|
+
tool_mode = "DRAW"
|
|
144
|
+
p_x += 105
|
|
145
|
+
else:
|
|
146
|
+
if tool_mode == "DRAW":
|
|
147
|
+
if distance < PINCH_THRESHOLD:
|
|
148
|
+
cv2.circle(frame, (ix, iy), 10, current_color, -1)
|
|
149
|
+
if not is_drawing:
|
|
150
|
+
is_drawing = True
|
|
151
|
+
current_stroke = []
|
|
152
|
+
strokes.append((current_stroke, current_color))
|
|
153
|
+
current_stroke.append((ix, iy))
|
|
154
|
+
else:
|
|
155
|
+
cv2.circle(frame, (ix, iy), 8, (0, 0, 255), -1)
|
|
156
|
+
is_drawing = False
|
|
157
|
+
elif tool_mode == "ERASER":
|
|
158
|
+
cv2.circle(frame, (ix, iy), ERASER_RADIUS, (0, 165, 255), 2)
|
|
159
|
+
if distance < PINCH_THRESHOLD:
|
|
160
|
+
cv2.circle(frame, (ix, iy), ERASER_RADIUS, (0, 165, 255), -1)
|
|
161
|
+
for stroke_pts, _ in strokes:
|
|
162
|
+
stroke_pts[:] = [pt for pt in stroke_pts if math.hypot(pt[0] - ix, pt[1] - iy) > ERASER_RADIUS]
|
|
163
|
+
strokes = [s for s in strokes if len(s[0]) > 0]
|
|
164
|
+
else:
|
|
165
|
+
is_drawing = False
|
|
166
|
+
|
|
167
|
+
for stroke_pts, col in strokes:
|
|
168
|
+
for i in range(1, len(stroke_pts)):
|
|
169
|
+
cv2.line(frame, stroke_pts[i - 1], stroke_pts[i], col, 4)
|
|
170
|
+
|
|
171
|
+
if run_emotion:
|
|
172
|
+
cv2.putText(frame, expression_text, (w - 380, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.6, expression_color, 2)
|
|
173
|
+
|
|
174
|
+
cv2.imshow('Batch24-28 Vision Pipeline', frame)
|
|
175
|
+
|
|
176
|
+
key = cv2.waitKey(1) & 0xFF
|
|
177
|
+
if key == ord('q'):
|
|
178
|
+
break
|
|
179
|
+
elif key == ord('c') and run_draw:
|
|
180
|
+
strokes.clear()
|
|
181
|
+
elif key == ord('e') and run_draw:
|
|
182
|
+
tool_mode = "ERASER" if tool_mode == "DRAW" else "DRAW"
|
|
183
|
+
finally:
|
|
184
|
+
if hands_obj:
|
|
185
|
+
hands_obj.close()
|
|
186
|
+
cap.release()
|
|
187
|
+
cv2.destroyAllWindows()
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: batch24-28
|
|
3
|
+
Version: 1.2.4
|
|
4
|
+
Summary: A multi featured Python terminal and vision toolkit
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: psutil
|
|
8
|
+
Requires-Dist: watchdog
|
|
9
|
+
Requires-Dist: opencv-python
|
|
10
|
+
Requires-Dist: mediapipe==0.10.21
|
|
11
|
+
Requires-Dist: fer
|
|
12
|
+
Requires-Dist: tensorflow==2.17.0
|
|
13
|
+
Requires-Dist: protobuf==4.25.9
|
|
14
|
+
Requires-Dist: setuptools==81.0.0
|
|
15
|
+
Requires-Dist: python-chess
|
|
16
|
+
|
|
1
17
|
|
|
2
18
|
# batch24-28
|
|
3
19
|
|
|
@@ -135,4 +151,26 @@ from batch24_28 import start_file_watcher
|
|
|
135
151
|
|
|
136
152
|
# Watch the current directory
|
|
137
153
|
start_file_watcher(path=".")
|
|
138
|
-
```
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 10. Computer Vision & Emotion Analysis Toolkit
|
|
159
|
+
|
|
160
|
+
An interactive computer vision pipeline powered by MediaPipe hand-tracking and deep learning emotion recognition. Includes virtual mid-air drawing (Air Canvas) and facial expression tracking via webcam, static images, or video files.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from batch24_28 import VisionAnalyzer
|
|
164
|
+
|
|
165
|
+
analyzer = VisionAnalyzer()
|
|
166
|
+
|
|
167
|
+
# Option A: Run live Air Canvas and Emotion detection via webcam
|
|
168
|
+
analyzer.run_air_canvas(run_draw=True, run_emotion=True)
|
|
169
|
+
|
|
170
|
+
# Option B: Analyze facial expression from a static image file
|
|
171
|
+
emotion, score, img = analyzer.analyze_image_file("path_to_image.jpg")
|
|
172
|
+
print(f"Detected: {emotion} ({int(score * 100)}%)")
|
|
173
|
+
|
|
174
|
+
# Option C: Stream and analyze a video file for expressions
|
|
175
|
+
analyzer.analyze_video_file("path_to_video.mp4")
|
|
176
|
+
```
|
batch24_28-1.2.3/pyproject.toml
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|