Compare commits

..

No commits in common. "ade4654112de5ff52cad9b25cd09f180a5ee8eec" and "7e939522dd6d7fd97175fbd7f551a4c4bcd9daa8" have entirely different histories.

8 changed files with 324726 additions and 134 deletions

View File

@ -1,5 +0,0 @@
python3 -m venv env
.\env\bin\activate.bat
python3 -m pip install -r requirements.txt
echo Ready
pause

View File

@ -1,105 +0,0 @@
import sys
import time
from enum import Enum
from subprocess import Popen
from typing import Generator
from types import ModuleType
import numpy as np
import mediapipe as mp
import cv2
from cv2 import VideoCapture
mp_hands = mp.solutions.hands
mp_draw: ModuleType = mp.solutions.drawing_utils
class FingerType(Enum):
BASE = 0
BASE_RIGHT = 1
THUMB_BASE = 2
THUMB_KNUCKLE_1 = 3
THUMB_TIP = 4
INDEX_BASE = 5
INDEX_KNUCKLE_1 = 6
INDEX_KNUCKLE_2 = 7
INDEX_TIP = 8
MIDDLE_BASE = 9
MIDDLE_KNUCKLE_1 = 10
MIDDLE_KNUCKLE_2 = 11
MIDDLE_TIP = 12
RING_BASE = 13
RING_KNUCKLE_1 = 14
RING_KNUCKLE_2 = 15
RING_TIP = 16
PINKY_BASE = 17
PINKY_KNUCKLE_1 = 18
PINKY_KNUCKLE_2 = 19
PINKY_TIP = 20
def save_score(score: int) -> None:
with open('./.score', 'w') as score_file:
score_file.write(str(score))
def start_game_sfx() -> Popen:
return
Popen(['paplay', './assets/sound/start.mp3']).communicate()
time.sleep(.5)
return Popen(['paplay', './assets/sound/background_music.mp3'])
def collect_sfx() -> None:
pass # Popen(['paplay', './assets/sound/collect.mp3'])
def lost_sfx() -> None:
pass # Popen(['paplay', './assets/sound/lost.mp3']).communicate()
def show_matrix() -> None:
pass # Popen(['cmatrix'])
def initiate_rick() -> None:
return
Popen(['paplay', './assets/sound/rick.mp3'])
cap = cv2.VideoCapture('./assets/video/rick2.mp4')
fps: int = int(cap.get(cv2.CAP_PROP_FPS))
desired_delay: float = 1 / fps
while True:
start_time = time.time()
ret, frame = cap.read()
if not ret:
break
sys.stdout.buffer.write(frame.tobytes())
elapsed_time = time.time() - start_time
remaining_delay = max(desired_delay - elapsed_time, 0)
time.sleep(remaining_delay)
cap.release()
def found_hands() -> bool:
capture: VideoCapture = cv2.VideoCapture(0)
hands = mp_hands.Hands(max_num_hands=1)
success, frame = capture.read()
if not success:
return False
return list(get_finger_positions(frame, hands)) != []
def get_finger_positions(
frame: np.ndarray,
hands: mp.solutions.hands.Hands,
add_landmarks: bool=False,
) -> Generator[list[tuple[int, int, int]], None, None]:
height, width = frame.shape[:2]
img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(img_rgb)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
positions = []
for id, lm in enumerate(hand_landmarks.landmark):
x = int(lm.x * width)
y = int(lm.y * height)
positions.append((FingerType(id), x, y))
yield positions
if add_landmarks:
mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)

11
game.py
View File

@ -22,6 +22,8 @@ def get_42_img(
if len(img.shape) in [1, 2]:
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
img = cv2.flip(img, 1)
img_height, img_width = img.shape[:2]
img = img[
margin_top:img_height-margin_bottom,
@ -68,7 +70,7 @@ def add_directional_triangle(
# normalize
norm = np.linalg.norm(dir_vector)
dir_vector /= (norm or 1)
dir_vector /= norm
# TODO: Fix type issue
side_len *= norm / 15
@ -94,8 +96,6 @@ def show_frame(frame: np.ndarray, to_stdout: bool=False) -> None:
if to_stdout:
sys.stdout.buffer.write(frame.tobytes())
else:
cv2.namedWindow("Image", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Image", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.imshow("Image", frame)
cv2.waitKey(1)
@ -103,7 +103,7 @@ def main() -> int:
music = start_game_sfx()
capture: cv2.VideoCapture = cv2.VideoCapture(0)
hands: mp.solutions.hands.Hands = mp_hands.Hands(max_num_hands=2)
hands: mp.solutions.hands.Hands = mp_hands.Hands(max_num_hands=1)
collected_42: bool = True
noise_42img: int = 5
img42_x: int = -img42_side_len - 1 - noise_42img
@ -114,7 +114,7 @@ def main() -> int:
finger_y: int = -1
no_collect_ratio = 0
no_finger_ratio = 0
timer = 1000
timer = 100
i: int = 0
while True:
@ -124,7 +124,6 @@ def main() -> int:
if not success:
continue
frame = cv2.flip(frame, 1)
ratio = max(no_finger_ratio, no_collect_ratio)
frame = cv2.addWeighted(frame, 1 - ratio, np.ones(frame.shape, dtype=frame.dtype), ratio, 0)
if i > 30:

324708
libcaca/a Normal file

File diff suppressed because one or more lines are too long

View File

@ -38,7 +38,7 @@ def main() -> NoReturn:
while True:
if found_hands():
start_game()
sleep(1)
sleep(2)
if __name__ == '__main__':
main()

View File

@ -13,11 +13,8 @@ opencv-contrib-python==4.8.0.76
opencv-python==4.8.0.76
packaging==23.1
Pillow==10.0.0
playsound==1.3.0
protobuf==3.20.3
pycairo==1.24.0
pycparser==2.21
PyGObject==3.44.1
pyparsing==3.0.9
python-dateutil==2.8.2
six==1.16.0

View File

@ -1,7 +1,7 @@
#!/bin/sh
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray" -c:v libx265 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=caca --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; } | ./game.py'
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray" -c:v libx265 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=caca --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; }'
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray" -c:v libx264 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=tct --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; }'
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray,hflip" -c:v libx265 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=caca --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; } | ./game.py'
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray,hflip" -c:v libx265 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=caca --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; }'
# st -f 'SauceCodePro Nerd Font Mono:size=10' -e sh -c '{ ./game.py | 2>/dev/null ffmpeg -y -f rawvideo -s 640x480 -pix_fmt bgr24 -i - -map 0:V:0 -filter:v "format=gray,hflip" -c:v libx264 -preset ultrafast -tune zerolatency -crf 30 -f nut - | TERM=xterm-mono CACA_DRIVER=ncurses DISPLAY= mpv --really-quiet --no-cache --no-config --vo=tct --untimed --profile=low-latency - || { echo Error 1>&2; read X; }; }'
TERM_FONT='SauceCodePro Nerd Font Mono'
TERM_FONT_SIZE='10'
@ -21,7 +21,7 @@ xterm \
-pix_fmt bgr24 \
-i - \
-map 0:V:0 \
-filter:v "format=gray" \
-filter:v "format=gray,hflip" \
-c:v libx265 \
-preset ultrafast \
-tune zerolatency \

View File

@ -4,12 +4,11 @@ from enum import Enum
from subprocess import Popen
from typing import Generator
from types import ModuleType
import threading
import numpy as np
import mediapipe as mp
import cv2
from playsound import playsound
from cv2 import VideoCapture
mp_hands = mp.solutions.hands
mp_draw: ModuleType = mp.solutions.drawing_utils
@ -41,23 +40,22 @@ def save_score(score: int) -> None:
with open('./.score', 'w') as score_file:
score_file.write(str(score))
def start_game_sfx() -> None:
playsound('./assets/sound/start.mp3')
def start_game_sfx() -> Popen:
Popen(['paplay', './assets/sound/start.mp3']).communicate()
time.sleep(.5)
threading.Thread(target=playsound, args=('./assets/sound/background_music.mp3',), daemon=True).start()
return Popen(['paplay', './assets/sound/background_music.mp3'])
def collect_sfx() -> None:
pass
threading.Thread(target=playsound, args=('./assets/sound/collect.mp3',), daemon=True).start()
Popen(['paplay', './assets/sound/collect.mp3'])
def lost_sfx() -> None:
playsound('./assets/sound/lost.mp3')
Popen(['paplay', './assets/sound/lost.mp3']).communicate()
def show_matrix() -> None:
Popen(['tmatrix'])
def initiate_rick() -> None:
threading.Thread(target=playsound, args=('./assets/sound/rick.mp3',), daemon=True).start()
Popen(['paplay', './assets/sound/rick.mp3'])
cap = cv2.VideoCapture('./assets/video/rick2.mp4')
fps: int = int(cap.get(cv2.CAP_PROP_FPS))
desired_delay: float = 1 / fps
@ -75,7 +73,7 @@ def initiate_rick() -> None:
def found_hands() -> bool:
capture: cv2.VideoCapture = cv2.VideoCapture(0)
capture: VideoCapture = cv2.VideoCapture(0)
hands = mp_hands.Hands(max_num_hands=1)
success, frame = capture.read()
if not success: