Skip to content

Commit fcfef18

Browse files
...
1 parent 6088fc5 commit fcfef18

18 files changed

Lines changed: 1017 additions & 46 deletions

audio_analysis.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from pydub import AudioSegment
2+
import numpy as np
3+
4+
class AudioAnalyzer:
5+
def __init__(self, filepath, num_bars=50):
6+
self.audio = AudioSegment.from_file(filepath)
7+
self.num_bars = num_bars
8+
self.samples = np.array(self.audio.get_array_of_samples())
9+
10+
# Mono or stereo?
11+
if self.audio.channels == 2:
12+
self.samples = self.samples.reshape((-1, 2))
13+
self.samples = self.samples.mean(axis=1) # convert to mono
14+
15+
self.sample_rate = self.audio.frame_rate
16+
self.duration = len(self.audio) / 1000.0 # duration in seconds
17+
18+
# Normalize samples to [-1,1]
19+
self.samples = self.samples / np.max(np.abs(self.samples))
20+
21+
# Precompute chunk size for bars
22+
self.chunk_size = len(self.samples) // self.num_bars
23+
24+
def get_amplitudes(self, current_time):
25+
"""
26+
Given current playback time in seconds, returns a list of amplitudes (0 to 1)
27+
for each bar of the waveform visualizer.
28+
"""
29+
start_sample = int(current_time * self.sample_rate)
30+
amplitudes = []
31+
32+
# Avoid overflow
33+
if start_sample + self.chunk_size * self.num_bars > len(self.samples):
34+
# Loop back to start or clip
35+
start_sample = 0
36+
37+
for i in range(self.num_bars):
38+
chunk = self.samples[start_sample + i * self.chunk_size : start_sample + (i+1) * self.chunk_size]
39+
amp = np.abs(chunk).mean()
40+
amplitudes.append(amp)
41+
42+
return amplitudes

clear-commits.bat

100644100755
File mode changed.

clear-commits.sh

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
#!/bin/bash
2-
3-
# Switch to a new orphan branch
4-
git checkout --orphan new_branch
5-
6-
# Stage all changes
7-
git add .
8-
9-
# Commit changes
10-
git commit -m "new_commit"
11-
12-
# Delete the old main branch
13-
git branch -D main
14-
15-
# Rename the new branch to main
16-
git branch -m main
17-
18-
# Force push to the remote main branch
1+
#!/bin/bash
2+
3+
# Switch to a new orphan branch
4+
git checkout --orphan new_branch
5+
6+
# Stage all changes
7+
git add .
8+
9+
# Commit changes
10+
git commit -m "new_commit"
11+
12+
# Delete the old main branch
13+
git branch -D main
14+
15+
# Rename the new branch to main
16+
git branch -m main
17+
18+
# Force push to the remote main branch
1919
git push -f origin main

config.json

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
{
2-
"Config": {
3-
"AppName": "TemplateProject",
4-
"Description": "",
5-
"ProjectStructure": {
6-
"MainScript": "main.py",
7-
"DependenciesScript": "scripts/install-dependencies.py"
8-
},
9-
"Scripts": {
10-
11-
}
12-
}
1+
{
2+
"Config": {
3+
"AppName": "Gender Age ID",
4+
"Description": "",
5+
"ProjectStructure": {
6+
"MainScript": "main.py",
7+
"DependenciesScript": "scripts/install-dependencies.py"
8+
},
9+
"Scripts": {
10+
"MainScript": "main.py",
11+
"DependenciesScript": "scripts/install-dependencies.py"
12+
}
13+
}
1314
}

face-detection/feed_detection.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import cv2
2+
import time
3+
from picamera2 import Picamera2
4+
5+
# Initialize PiCamera2
6+
cam = Picamera2()
7+
cam.preview_configuration.main.size = (640, 480)
8+
cam.preview_configuration.main.format = "RGB888"
9+
cam.configure("preview")
10+
cam.start()
11+
time.sleep(1) # Let the camera warm up
12+
13+
# Load the Haar Cascade face detector
14+
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
15+
16+
print("👁️ Press 'q' to quit.")
17+
18+
while True:
19+
# Capture frame from PiCamera
20+
frame = cam.capture_array()
21+
22+
# Convert to grayscale for face detection
23+
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
24+
25+
# Detect faces
26+
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, minSize=(30, 30))
27+
28+
# Draw rectangles around faces
29+
for (x, y, w, h) in faces:
30+
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
31+
32+
# Display the result
33+
cv2.imshow('🎥 PiCamera Face Detection', cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
34+
35+
# Quit if 'q' is pressed
36+
if cv2.waitKey(1) & 0xFF == ord('q'):
37+
break
38+
39+
# Cleanup
40+
cv2.destroyAllWindows()
41+
cam.stop()

face-detection/image_detection.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import cv2
2+
from PIL import Image
3+
import os
4+
import glob
5+
import numpy as np
6+
import json
7+
8+
def detect_and_mark_faces(input_path, output_dir):
9+
# Load the image using PIL to handle various image formats
10+
image_pil = Image.open(input_path)
11+
image = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGB2BGR) # Use np for nump
12+
13+
# Convert the image to grayscale
14+
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
15+
16+
# Load the pre-trained face detector
17+
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
18+
19+
# Detect faces in the image
20+
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
21+
22+
# Draw rectangles around the faces
23+
for (x, y, w, h) in faces:
24+
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
25+
26+
# Create an output directory if it doesn't exist
27+
os.makedirs(output_dir, exist_ok=True)
28+
29+
# Save the marked image using PIL to handle various image formats
30+
output_path = os.path.join(output_dir, f"marked_{os.path.basename(input_path)}")
31+
marked_image_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
32+
marked_image_pil.save(output_path)
33+
34+
print(f"Detected {len(faces)} face(s). Marked image saved to {output_path}")
35+
36+
if __name__ == "__main__":
37+
38+
script_directory = os.path.dirname(os.path.abspath(__file__))
39+
40+
with open("settings.json", "r") as file:
41+
settings = json.load(file)
42+
43+
input_directory = os.path.join(script_directory, settings["directories"]["input"])
44+
output_directory = os.path.join(script_directory, settings["directories"]["output"])
45+
46+
# Get a list of all image files in the input directory
47+
image_files = glob.glob(os.path.join(input_directory, "*"))
48+
49+
for image_file in image_files:
50+
detect_and_mark_faces(image_file, output_directory)

gpio-requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
sudo apt install python3-rpi.gpio python3-picamera2 ffmpeg
2+
pip install qrcode[pil] pillow

led_control.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import threading
2+
import numpy
3+
import spidev
4+
5+
class SPI_WS2812_LEDStrip:
6+
def __init__(self, count=8, brightness=255, sequence='GRB', bus=0, device=0):
7+
self.set_led_type(sequence)
8+
self.set_led_count(count)
9+
self.set_led_brightness(brightness)
10+
self.led_begin(bus, device)
11+
self.set_all_led_color(0, 0, 0)
12+
self.lock = threading.Lock()
13+
14+
def set_led_type(self, rgb_type):
15+
led_types = ['RGB', 'RBG', 'GRB', 'GBR', 'BRG', 'BGR']
16+
offsets = [0x06, 0x09, 0x12, 0x21, 0x18, 0x24]
17+
try:
18+
idx = led_types.index(rgb_type)
19+
offset = offsets[idx]
20+
self.led_red_offset = (offset >> 4) & 3
21+
self.led_green_offset = (offset >> 2) & 3
22+
self.led_blue_offset = offset & 3
23+
except ValueError:
24+
self.led_red_offset, self.led_green_offset, self.led_blue_offset = 1, 0, 2
25+
26+
def set_led_count(self, count):
27+
self.led_count = count
28+
self.led_color = [0] * (count * 3)
29+
self.led_original_color = [0] * (count * 3)
30+
31+
def set_led_brightness(self, brightness):
32+
self.led_brightness = brightness
33+
for i in range(self.led_count):
34+
self.set_led_rgb_data(i, [0, 0, 0])
35+
36+
def set_ledpixel(self, index, r, g, b):
37+
p = [0, 0, 0]
38+
p[self.led_red_offset] = round(r * self.led_brightness / 255)
39+
p[self.led_green_offset] = round(g * self.led_brightness / 255)
40+
p[self.led_blue_offset] = round(b * self.led_brightness / 255)
41+
for i, color in enumerate((r, g, b)):
42+
self.led_original_color[index * 3 + i] = color
43+
for i in range(3):
44+
self.led_color[index * 3 + i] = p[i]
45+
46+
def set_led_rgb_data(self, index, color):
47+
self.set_ledpixel(index, *color)
48+
49+
def set_all_led_color(self, r, g, b):
50+
for i in range(self.led_count):
51+
self.set_ledpixel(i, r, g, b)
52+
self.show()
53+
54+
def led_begin(self, bus=0, device=0):
55+
self.bus, self.device = bus, device
56+
try:
57+
self.spi = spidev.SpiDev()
58+
self.spi.open(bus, device)
59+
self.spi.mode = 0
60+
self.led_init_state = 1
61+
except OSError:
62+
print("SPI init failed. Check config.txt and raspi-config.")
63+
self.led_init_state = 0
64+
65+
def check_spi_state(self):
66+
return self.led_init_state
67+
68+
def show(self):
69+
d = numpy.array(self.led_color).ravel()
70+
tx = numpy.zeros(len(d) * 8, dtype=numpy.uint8)
71+
for ibit in range(8):
72+
tx[7 - ibit::8] = ((d >> ibit) & 1) * 0x78 + 0x80
73+
if self.led_init_state:
74+
speed = int(8 / (1.25e-6 if self.bus == 0 else 1.0e-6))
75+
self.spi.xfer(tx.tolist(), speed)
76+
77+
def led_close(self):
78+
self.set_all_led_color(0, 0, 0)
79+
self.spi.close()
80+
81+
def rhythm_wave(self, frame):
82+
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255), (0, 255, 255)]
83+
count = self.led_count
84+
base = (frame // 20) % len(colors)
85+
self.set_all_led_color(0, 0, 0)
86+
for i in range(count):
87+
phase = (frame + i * 6) % (count * 12)
88+
bright = phase / (count * 6) if phase < count * 6 else (count * 12 - phase) / (count * 6)
89+
color = colors[(base + i) % len(colors)]
90+
scaled = [int(c * bright) for c in color]
91+
self.set_ledpixel(i, *scaled)
92+
self.show()

motor_control.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import pygame
2+
from gpiozero import Motor
3+
4+
class MotorController:
5+
def __init__(self, left_pins=(24, 23), right_pins=(5, 6)):
6+
self.left = Motor(forward=left_pins[0], backward=left_pins[1])
7+
self.right = Motor(forward=right_pins[0], backward=right_pins[1])
8+
9+
def stop(self):
10+
self.left.stop()
11+
self.right.stop()
12+
13+
def forward(self, speed=1.0):
14+
self.left.forward(speed)
15+
self.right.forward(speed)
16+
17+
def backward(self, speed=1.0):
18+
self.left.backward(speed)
19+
self.right.backward(speed)
20+
21+
def turn_left(self, speed=1.0):
22+
self.left.backward(speed)
23+
self.right.forward(speed)
24+
25+
def turn_right(self, speed=1.0):
26+
self.left.forward(speed)
27+
self.right.backward(speed)
28+
29+
def control_mode_2(self, keys, speed):
30+
left_active = right_active = False
31+
if keys[pygame.K_q]:
32+
self.left.forward(speed)
33+
left_active = True
34+
elif keys[pygame.K_a]:
35+
self.left.backward(speed)
36+
left_active = True
37+
else:
38+
self.left.stop()
39+
40+
if keys[pygame.K_w]:
41+
self.right.forward(speed)
42+
right_active = True
43+
elif keys[pygame.K_s]:
44+
self.right.backward(speed)
45+
right_active = True
46+
else:
47+
self.right.stop()
48+
49+
return left_active, right_active

0 commit comments

Comments
 (0)