161 lines
6.1 KiB
Python
161 lines
6.1 KiB
Python
import cv2
|
|
from pyzbar.pyzbar import decode
|
|
import time
|
|
import numpy as np
|
|
from urllib.parse import urlparse, parse_qs, unquote
|
|
from PIL import ImageFont, ImageDraw, Image
|
|
import os
|
|
import subprocess
|
|
|
|
# Fenstergröße & Farben
|
|
window_width, window_height = 1920, 1080
|
|
# Habegger Gold
|
|
COLOR_GREEN = (0, 255, 0)
|
|
COLOR_YELLOW = (0, 255, 255)
|
|
COLOR_BACKGROUND = (45, 46, 47) # HTML-Farbe #2d2e2f
|
|
COLOR_WHITE = (255, 255, 255)
|
|
COLOR_GOLD = (131, 188, 214) # BGR für Habegger-Gold
|
|
|
|
# Font & Logo
|
|
FONT_PATH = os.path.join("fonts", "Tisa Sans Pro Regular.ttf"
|
|
"") # Alternativ: Georgia.ttf, falls vorhanden
|
|
FONT_SIZE = 48
|
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
|
logo_path = "images/habegger_logo_goldbar_whitefont.png" # Logo mit sichtbarem Text
|
|
logo_pil = Image.open(logo_path).convert("RGBA")
|
|
logo_pil.thumbnail((300, 100))
|
|
logo_pil = Image.alpha_composite(Image.new("RGBA", logo_pil.size, (0, 0, 0, 0)), logo_pil)
|
|
logo_img = np.array(logo_pil)
|
|
logo_img = cv2.cvtColor(logo_img, cv2.COLOR_RGBA2BGRA)
|
|
|
|
def draw_unicode_text(cv2_image, text, position, color=COLOR_WHITE):
|
|
img_pil = Image.fromarray(cv2_image)
|
|
draw = ImageDraw.Draw(img_pil)
|
|
draw.text(position, text, font=font, fill=color)
|
|
return np.array(img_pil)
|
|
|
|
def parse_qr_data(data):
|
|
try:
|
|
parsed = urlparse(data)
|
|
query = parse_qs(parsed.query)
|
|
mail = query.get("mail", [""])[0]
|
|
name = query.get("name", [""])[0]
|
|
name = unquote(name, encoding="utf-8", errors="replace")
|
|
name = (name.replace("鐼", "ö")
|
|
.replace("ü", "ü")
|
|
.replace("ä", "ä")
|
|
.replace("Ö", "Ö")
|
|
.replace("Ü", "Ü")
|
|
.replace("Ãß", "ß"))
|
|
if "@habegger.ch" in mail.lower() and name.strip():
|
|
return mail.strip(), name.strip()
|
|
except:
|
|
pass
|
|
return None, None
|
|
|
|
def start_game(mail, name):
|
|
with open("last_user.txt", "w", encoding="utf-8-sig") as f:
|
|
f.write(f"{mail}\n{name}")
|
|
subprocess.run(["python", "loader_game.py"])
|
|
|
|
# Endlosschleife für den Scanner
|
|
while True:
|
|
detected_color = COLOR_GOLD
|
|
detected_time = None
|
|
cap = cv2.VideoCapture(0)
|
|
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
|
|
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
|
|
|
|
# Rahmenfarbe wird später im Loop anhand der Zeit gesetzt
|
|
last_display_text = ""
|
|
start_timer = None
|
|
game_started = False
|
|
|
|
while True:
|
|
success, frame = cap.read()
|
|
if not success:
|
|
break
|
|
|
|
decoded_objects = decode(frame)
|
|
# QR-Status zurücksetzen nach 5 Sek.
|
|
if detected_time and time.time() - detected_time >= 5.0:
|
|
detected_color = COLOR_GOLD
|
|
frame_color = COLOR_GOLD
|
|
|
|
if decoded_objects:
|
|
detected_time = time.time()
|
|
for obj in decoded_objects:
|
|
points = obj.polygon
|
|
if len(points) > 4:
|
|
hull = cv2.convexHull(np.array([point for point in points], dtype=np.float32))
|
|
points = hull.reshape(-1, 2)
|
|
for i in range(len(points)):
|
|
pt1 = tuple(points[i])
|
|
pt2 = tuple(points[(i + 1) % len(points)])
|
|
cv2.line(frame, pt1, pt2, COLOR_GREEN, 3)
|
|
|
|
data = obj.data.decode("utf-8")
|
|
mail, name = parse_qr_data(data)
|
|
|
|
if mail and name:
|
|
detected_color = COLOR_GREEN
|
|
last_display_text = f"Richtiger QR-Code: Hallo {name}"
|
|
detected_time = time.time()
|
|
start_timer = time.time()
|
|
game_started = True
|
|
last_mail = mail
|
|
last_name = name
|
|
else:
|
|
detected_color = COLOR_YELLOW
|
|
detected_time = time.time()
|
|
last_display_text = "Bitte dein HAG Last-Thursday Code scannen."
|
|
break
|
|
|
|
if start_timer and time.time() - start_timer >= 5.0:
|
|
cap.release()
|
|
cv2.destroyAllWindows()
|
|
start_game(last_mail, last_name)
|
|
break
|
|
|
|
display_frame = np.full((window_height, window_width, 3), COLOR_BACKGROUND, dtype=np.uint8)
|
|
cam_h, cam_w = frame.shape[:2]
|
|
x_offset = (window_width - cam_w) // 2
|
|
y_offset = (window_height - cam_h) // 2
|
|
display_frame[y_offset:y_offset+cam_h, x_offset:x_offset+cam_w] = frame
|
|
|
|
display_frame = draw_unicode_text(display_frame,
|
|
"Scanne deinen QR-Code um das Spiel zu starten.",
|
|
(80, 100), COLOR_WHITE)
|
|
|
|
if last_display_text:
|
|
display_frame = draw_unicode_text(display_frame, last_display_text,
|
|
(80, window_height - 100), COLOR_WHITE)
|
|
|
|
# Kamera-Rahmen
|
|
if detected_time and time.time() - detected_time < 5.0:
|
|
current_color = detected_color
|
|
else:
|
|
current_color = COLOR_GOLD
|
|
|
|
cv2.rectangle(display_frame, (x_offset, y_offset),
|
|
(x_offset + cam_w, y_offset + cam_h), current_color, 6)
|
|
|
|
# Logo oben rechts ohne Alpha-Blending-Probleme
|
|
logo_pos = (window_width - logo_img.shape[1] - 40, 40)
|
|
overlay = np.zeros_like(display_frame, dtype=np.uint8)
|
|
overlay[logo_pos[1]:logo_pos[1]+logo_img.shape[0], logo_pos[0]:logo_pos[0]+logo_img.shape[1]] = logo_img[:, :, :3]
|
|
mask = logo_img[:, :, 3] # alpha channel
|
|
for c in range(3):
|
|
display_frame[logo_pos[1]:logo_pos[1]+logo_img.shape[0], logo_pos[0]:logo_pos[0]+logo_img.shape[1], c] = (
|
|
logo_img[:, :, c] * (mask / 255.0) + display_frame[logo_pos[1]:logo_pos[1]+logo_img.shape[0], logo_pos[0]:logo_pos[0]+logo_img.shape[1], c] * (1.0 - mask / 255.0)).astype(np.uint8)
|
|
|
|
cv2.namedWindow("QR Scanner", cv2.WINDOW_NORMAL)
|
|
cv2.setWindowProperty("QR Scanner", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
|
cv2.imshow("QR Scanner", display_frame)
|
|
|
|
key = cv2.waitKey(1)
|
|
if key == 27 or key == ord('q'):
|
|
cap.release()
|
|
cv2.destroyAllWindows()
|
|
exit()
|