168 lines
5.1 KiB
Python
Executable File
168 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import sys
|
|
import random
|
|
|
|
import numpy as np
|
|
import cv2
|
|
from cv2 import VideoCapture
|
|
|
|
from utils import *
|
|
|
|
def get_42_img(
|
|
img_path: str,
|
|
margin_top: int,
|
|
margin_bottom: int,
|
|
margin_left: int,
|
|
margin_right: int,
|
|
) -> np.ndarray:
|
|
global img42_side_len
|
|
|
|
img: np.ndarray = cv2.imread(img_path, 0)
|
|
|
|
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,
|
|
margin_left:img_width-margin_right,
|
|
]
|
|
|
|
b_top, b_bottom, b_left, b_right = [10]*4
|
|
img = cv2.copyMakeBorder(img, b_top, b_bottom, b_left, b_right, cv2.BORDER_CONSTANT, value=(0, 0, 0))
|
|
|
|
img = cv2.resize(img, (img42_side_len, img42_side_len))
|
|
|
|
return img
|
|
|
|
img42_side_len: int = 100
|
|
img42: np.ndarray = get_42_img(
|
|
"./assets/img/42.png",
|
|
margin_top = 100 + 20,
|
|
margin_bottom = 100 + 20,
|
|
margin_left = 100,
|
|
margin_right = 100,
|
|
)
|
|
|
|
def touches_42(x: int, y: int, img42_x: int, img42_y: int) -> bool:
|
|
global collected_42
|
|
|
|
return (
|
|
img42_x <= x <= img42_x + img42_side_len
|
|
and img42_y <= y <= img42_y + img42_side_len
|
|
)
|
|
|
|
def add_directional_triangle(
|
|
frame: np.ndarray,
|
|
x1: int,
|
|
y1: int,
|
|
x2: int,
|
|
y2: int,
|
|
rgb: tuple[int, int, int],
|
|
side_len: int,
|
|
stretch: float,
|
|
) -> tuple[int, int]:
|
|
dir_vector: np.ndarray = np.array([
|
|
x1 - x2, y1 - y2
|
|
]).astype(np.float64)
|
|
|
|
# normalize
|
|
dir_vector /= np.linalg.norm(dir_vector)
|
|
|
|
triangle_height: float = side_len * (3**0.5) / 2
|
|
half_base: float = side_len / 2
|
|
|
|
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),
|
|
int(y1 - perp_vector[1] * half_base - dir_vector[1] * triangle_height/3))
|
|
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.ndarray = np.array([apex_vertex, left_vertex, right_vertex])
|
|
cv2.drawContours(frame, [triangle], 0, rgb, -1)
|
|
|
|
return apex_vertex
|
|
|
|
def show_frame(frame: np.ndarray, to_stdout: bool=False) -> None:
|
|
if to_stdout:
|
|
sys.stdout.buffer.write(frame.tobytes())
|
|
else:
|
|
cv2.imshow("Image", frame)
|
|
cv2.waitKey(1)
|
|
|
|
def main() -> int:
|
|
start_game_sfx()
|
|
|
|
capture: VideoCapture = cv2.VideoCapture(0)
|
|
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
|
|
img42_y: int = -img42_side_len - 1 - noise_42img
|
|
no_fingers: int = 0
|
|
score: int = 0
|
|
|
|
i: int = 0
|
|
while True:
|
|
success: bool
|
|
frame: np.ndarray
|
|
success, frame = capture.read()
|
|
if not success:
|
|
continue
|
|
|
|
if i > 30:
|
|
if collected_42:
|
|
collected_42 = False
|
|
frame_height, frame_width = frame.shape[:2]
|
|
img42_x = random.randint(0, frame_width - img42_side_len - 1)
|
|
img42_y = random.randint(0, frame_height - img42_side_len - 1)
|
|
rand_noise_y = random.randint(0, noise_42img)
|
|
rand_noise_x = random.randint(0, noise_42img)
|
|
frame[
|
|
img42_y + rand_noise_y : img42_y + img42_side_len + rand_noise_y,
|
|
img42_x + rand_noise_x : img42_x + img42_side_len + rand_noise_x,
|
|
] = img42
|
|
|
|
finger_positions = list(get_finger_positions(frame, hands, add_landmarks=True))
|
|
if finger_positions == []:
|
|
no_fingers += 1
|
|
else:
|
|
no_fingers = 0
|
|
if no_fingers > 200:
|
|
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:
|
|
index_knuckle_1_pos = (finger_x, finger_y)
|
|
elif finger_id == FingerType.INDEX_TIP and index_knuckle_1_pos != (-1, -1):
|
|
apex_x, apex_y = add_directional_triangle(
|
|
frame,
|
|
finger_x,
|
|
finger_y,
|
|
*index_knuckle_1_pos,
|
|
(0, 0, 0,),
|
|
side_len=70,
|
|
stretch=2.0,
|
|
)
|
|
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__':
|
|
save_score(main())
|
|
sys.exit(0)
|