Compare commits
4 Commits
14ef055eaa
...
6b06beac24
| Author | SHA1 | Date |
|---|---|---|
|
|
6b06beac24 | |
|
|
aa2e9b27e1 | |
|
|
15b53cd262 | |
|
|
b0d21d30a3 |
Binary file not shown.
104
game.py
104
game.py
|
|
@ -2,38 +2,12 @@
|
|||
|
||||
import sys
|
||||
import random
|
||||
from enum import Enum
|
||||
from typing import NoReturn, Generator
|
||||
from types import ModuleType
|
||||
from subprocess import Popen
|
||||
|
||||
import numpy as np
|
||||
import mediapipe as mp
|
||||
import cv2
|
||||
from cv2 import VideoCapture
|
||||
|
||||
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
|
||||
from utils import *
|
||||
|
||||
def get_42_img(
|
||||
img_path: str,
|
||||
|
|
@ -64,10 +38,7 @@ def get_42_img(
|
|||
|
||||
return img
|
||||
|
||||
mp_hands = mp.solutions.hands
|
||||
mp_draw: ModuleType = mp.solutions.drawing_utils
|
||||
|
||||
img42_side_len = 70
|
||||
img42_side_len: int = 70
|
||||
img42: np.ndarray = get_42_img(
|
||||
"./assets/img/42.png",
|
||||
margin_top = 100 + 20,
|
||||
|
|
@ -94,17 +65,17 @@ def add_directional_triangle(
|
|||
side_len: int,
|
||||
stretch: float,
|
||||
) -> tuple[int, int]:
|
||||
dir_vector = np.array([
|
||||
dir_vector: np.ndarray = np.array([
|
||||
x1 - x2, y1 - y2
|
||||
]).astype(np.float64)
|
||||
|
||||
# normalize
|
||||
dir_vector /= np.linalg.norm(dir_vector)
|
||||
|
||||
triangle_height = side_len * (3**0.5) / 2
|
||||
half_base = side_len / 2
|
||||
triangle_height: float = side_len * (3**0.5) / 2
|
||||
half_base: float = side_len / 2
|
||||
|
||||
perp_vector = np.array([-dir_vector[1], dir_vector[0]])
|
||||
perp_vector: np.ndarray = np.array([-dir_vector[1], dir_vector[0]])
|
||||
|
||||
apex_vertex = (int(x1 + dir_vector[0] * triangle_height * 2/3 * stretch), int(y1 + dir_vector[1] * triangle_height * 2/3 * stretch))
|
||||
left_vertex = (int(x1 - perp_vector[0] * half_base - dir_vector[0] * triangle_height/3),
|
||||
|
|
@ -112,32 +83,11 @@ def add_directional_triangle(
|
|||
right_vertex = (int(x1 + perp_vector[0] * half_base - dir_vector[0] * triangle_height/3),
|
||||
int(y1 + perp_vector[1] * half_base - dir_vector[1] * triangle_height/3))
|
||||
|
||||
triangle = np.array([apex_vertex, left_vertex, right_vertex])
|
||||
triangle: np.ndarray = np.array([apex_vertex, left_vertex, right_vertex])
|
||||
cv2.drawContours(frame, [triangle], 0, rgb, -1)
|
||||
|
||||
return apex_vertex
|
||||
|
||||
def get_finger_positions(
|
||||
frame: np.ndarray,
|
||||
hands: mp.solutions.hands.Hands,
|
||||
add_landmarks: bool,
|
||||
) -> 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)
|
||||
|
||||
def show_frame(frame: np.ndarray, to_stdout: bool=False) -> None:
|
||||
if to_stdout:
|
||||
sys.stdout.buffer.write(frame.tobytes())
|
||||
|
|
@ -145,19 +95,18 @@ def show_frame(frame: np.ndarray, to_stdout: bool=False) -> None:
|
|||
cv2.imshow("Image", frame)
|
||||
cv2.waitKey(1)
|
||||
|
||||
def collect_sfx() -> None:
|
||||
Popen(['paplay', './assets/sfx/collect.mp3'])
|
||||
|
||||
def main() -> NoReturn:
|
||||
Popen(['paplay', './assets/sfx/start.mp3'])
|
||||
def main() -> int:
|
||||
start_sfx()
|
||||
|
||||
capture: VideoCapture = cv2.VideoCapture(0)
|
||||
hands = mp_hands.Hands(max_num_hands=2)
|
||||
collected_42 = True
|
||||
img42_x = -img42_side_len - 1
|
||||
img42_y = -img42_side_len - 1
|
||||
hands: mp.solutions.hands.Hands = mp_hands.Hands(max_num_hands=2)
|
||||
collected_42: bool = True
|
||||
img42_x: int = -img42_side_len - 1
|
||||
img42_y: int = -img42_side_len - 1
|
||||
no_fingers: int = 0
|
||||
score: int = 0
|
||||
|
||||
i = 0
|
||||
i: int = 0
|
||||
while True:
|
||||
success: bool
|
||||
frame: np.ndarray
|
||||
|
|
@ -176,7 +125,15 @@ def main() -> NoReturn:
|
|||
img42_x : img42_x+img42_side_len,
|
||||
] = img42
|
||||
|
||||
for positions in get_finger_positions(frame, hands, add_landmarks=True):
|
||||
finger_positions = list(get_finger_positions(frame, hands, add_landmarks=True))
|
||||
if finger_positions == []:
|
||||
no_fingers += 1
|
||||
else:
|
||||
no_fingers = 0
|
||||
if no_fingers > 70:
|
||||
return score
|
||||
|
||||
for positions in finger_positions:
|
||||
index_knuckle_1_pos: tuple[int, int] = (-1, -1)
|
||||
for finger_id, finger_x, finger_y in positions:
|
||||
if finger_id == FingerType.INDEX_KNUCKLE_2:
|
||||
|
|
@ -191,12 +148,19 @@ def main() -> NoReturn:
|
|||
side_len=70,
|
||||
stretch=2.0,
|
||||
)
|
||||
if not collected_42 and touches_42(apex_x, apex_y, img42_x, img42_y):
|
||||
if not collected_42 and (
|
||||
touches_42(apex_x, apex_y, img42_x, img42_y)
|
||||
or touches_42(finger_x, finger_y, img42_x, img42_y)
|
||||
):
|
||||
collected_42 = True
|
||||
i = 0
|
||||
score += 42
|
||||
collect_sfx()
|
||||
show_frame(frame, to_stdout=(not sys.stdout.isatty()))
|
||||
i += 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
score: int = main()
|
||||
with open('./.score', 'w') as score_file:
|
||||
score_file.write(str(score))
|
||||
sys.exit(0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from time import sleep
|
||||
from typing import NoReturn
|
||||
|
||||
from utils import *
|
||||
|
||||
def start_game() -> None:
|
||||
proc = Popen(['./start_game.sh'])
|
||||
proc.communicate()
|
||||
|
||||
def main() -> NoReturn:
|
||||
show_matrix()
|
||||
while True:
|
||||
if found_hands():
|
||||
start_game()
|
||||
sleep(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -4,18 +4,11 @@ import sys
|
|||
from typing import NoReturn
|
||||
|
||||
def main() -> NoReturn:
|
||||
x = 0
|
||||
y = 0
|
||||
while True:
|
||||
chunk = sys.stdin.buffer.read(100)
|
||||
if not chunk:
|
||||
continue
|
||||
nls = chunk.count(b'\n')
|
||||
if nls != 0:
|
||||
open('/dev/pts/1', 'w').write(
|
||||
f'{nls}'
|
||||
)
|
||||
modified_chunk = chunk
|
||||
modified_chunk = chunk.replace(b'X', b'.')
|
||||
sys.stdout.buffer.write(modified_chunk)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
# 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; }; }'
|
||||
|
||||
export TERM_FONT='SauceCodePro Nerd Font Mono'
|
||||
export TERM_FONT_SIZE='10'
|
||||
export OUT_TERM='xterm-mono'
|
||||
TERM_FONT='SauceCodePro Nerd Font Mono'
|
||||
TERM_FONT_SIZE='10'
|
||||
OUT_TERM='xterm-mono'
|
||||
# TERM_FULLSCREEN='-fullscreen'
|
||||
xterm \
|
||||
-bg black \
|
||||
-fg white \
|
||||
-s -fullscreen \
|
||||
${TERM_FULLSCREEN} \
|
||||
-fa "${TERM_FONT}" \
|
||||
-fs "${TERM_FONT_SIZE}" \
|
||||
-e '{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
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 collect_sfx() -> None:
|
||||
Popen(['paplay', './assets/sfx/collect.mp3'])
|
||||
|
||||
def start_sfx() -> None:
|
||||
Popen(['paplay', './assets/sfx/start.mp3'])
|
||||
|
||||
def show_matrix() -> None:
|
||||
Popen(['tmatrix'])
|
||||
|
||||
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)
|
||||
Loading…
Reference in New Issue