changed learning to array data only (not visual), changed some collisions
This commit is contained in:
+83
-133
@@ -2,141 +2,87 @@ import mss
|
||||
import cv2
|
||||
import numpy as np
|
||||
import time
|
||||
from typing import List, Tuple
|
||||
|
||||
# ========= Dein Spielausschnitt =========
|
||||
# ===== User config =====
|
||||
monitor_area = {"top": 120, "left": 330, "width": 1900, "height": 1263}
|
||||
# monitor_area = {"top": 121, "left": 27, "width": 672-27, "height": 549-121}
|
||||
|
||||
# ========= HSV-Grenzen =========
|
||||
yellow_lower = np.array([15, 40, 200], dtype=np.uint8)
|
||||
yellow_upper = np.array([25, 120, 255], dtype=np.uint8)
|
||||
white_lower = np.array([0, 0, 220], dtype=np.uint8)
|
||||
white_upper = np.array([180, 50, 255], dtype=np.uint8)
|
||||
# Einträge dürfen Pixel (x0,y0,x1,y1) oder normiert [0..1] sein (identisch zur Env)
|
||||
ui_exclude_rects: List[Tuple[float, float, float, float]] = [
|
||||
# (0.0, 0.0, 1.0, 0.08), # Beispiel: oberer HUD-Streifen (normiert)
|
||||
]
|
||||
# Feste Referenz (muss zur Env passen!)
|
||||
REF_SIZE = (1900, 1263)
|
||||
|
||||
black_lower = np.array([0, 0, 0], dtype=np.uint8)
|
||||
black_upper = np.array([180, 80, 60], dtype=np.uint8)
|
||||
|
||||
green1_lower = np.array([30, 80, 80], dtype=np.uint8)
|
||||
green1_upper = np.array([45, 255, 255], dtype=np.uint8)
|
||||
green2_lower = np.array([65, 100, 80], dtype=np.uint8)
|
||||
green2_upper = np.array([90, 255, 255], dtype=np.uint8)
|
||||
|
||||
kernel = np.ones((3,3), np.uint8)
|
||||
|
||||
# Radien
|
||||
EAT_RADIUS = 95
|
||||
COLL_RADIUS = 115
|
||||
|
||||
# Bomben-Filter
|
||||
BOMB_MIN_AREA = 400 # angepasst!
|
||||
BOMB_CIRC_MIN = 0.60
|
||||
BOMB_ASPECT_TOL = 0.35
|
||||
BOMB_EXTENT_MIN = 0.60
|
||||
BOMB_SOLIDITY_MIN = 0.85
|
||||
|
||||
# Fenster-Skalierung (0.7 = 70 % Größe)
|
||||
# Anzeige-Skalierung (nur fürs Fenster)
|
||||
WINDOW_SCALE = 0.8
|
||||
|
||||
# Anzeige-Modi
|
||||
MODE_OVERLAY, MODE_FLOWER_MASK, MODE_BOMB_MASK, MODE_TURTLE_MASK = 0,1,2,3
|
||||
MODE_OVERLAY, MODE_TEXT_ONLY = 0, 1
|
||||
mode = MODE_OVERLAY
|
||||
|
||||
# ===== Implementation =====
|
||||
# Wichtig: Die Detection/Parameter kommen aus der Env, um Drift zu vermeiden.
|
||||
from flower_game_env import FlowerGameEnv # Datei muss als flower_game_env.py vorliegen
|
||||
|
||||
def centroid(mask):
|
||||
cnt = int(cv2.countNonZero(mask))
|
||||
if cnt == 0: return None, None, 0
|
||||
M = cv2.moments(mask)
|
||||
if M["m00"] == 0: return None, None, cnt
|
||||
return int(M["m10"]/M["m00"]), int(M["m01"]/M["m00"]), cnt
|
||||
env = FlowerGameEnv(
|
||||
monitor_area,
|
||||
ui_exclude_rects=ui_exclude_rects,
|
||||
ref_size=REF_SIZE,
|
||||
)
|
||||
|
||||
|
||||
def bomb_centroids_filtered(mask):
|
||||
contours,_ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
out=[]
|
||||
for c in contours:
|
||||
area = float(cv2.contourArea(c))
|
||||
if area < BOMB_MIN_AREA:
|
||||
continue
|
||||
x,y,w,h = cv2.boundingRect(c)
|
||||
if w == 0 or h == 0:
|
||||
continue
|
||||
aspect = w/float(h)
|
||||
if not (1.0 - BOMB_ASPECT_TOL <= aspect <= 1.0 + BOMB_ASPECT_TOL):
|
||||
continue
|
||||
per = float(cv2.arcLength(c, True))
|
||||
if per <= 0:
|
||||
continue
|
||||
circularity = 4.0 * np.pi * area / (per * per)
|
||||
if circularity < BOMB_CIRC_MIN:
|
||||
continue
|
||||
hull = cv2.convexHull(c)
|
||||
hull_area = float(cv2.contourArea(hull))
|
||||
if hull_area <= 0:
|
||||
continue
|
||||
solidity = area / hull_area
|
||||
extent = area / float(w*h)
|
||||
if solidity < BOMB_SOLIDITY_MIN or extent < BOMB_EXTENT_MIN:
|
||||
continue
|
||||
M = cv2.moments(c)
|
||||
if M["m00"] == 0:
|
||||
continue
|
||||
cx = int(M["m10"]/M["m00"])
|
||||
cy = int(M["m01"]/M["m00"])
|
||||
out.append((cx, cy, int(area)))
|
||||
return out
|
||||
def _draw_overlay(frame_bgr, det, fps: float):
|
||||
"""Zeichnet exakt die Größen, die die Env auch nutzt (achsenweise Skalierung)."""
|
||||
h, w = det["frame_hw"]
|
||||
|
||||
# Rechteck-Halbachsen in Pixel aus achsenweisen nd-Schwellen
|
||||
eat_half_w_px = int(round((env.eat_x_nd * w) * 0.5))
|
||||
eat_half_h_px = int(round((env.eat_y_nd * h) * 0.5))
|
||||
coll_half_w_px = int(round((env.collision_x_nd * w) * 0.5))
|
||||
coll_half_h_px = int(round((env.collision_y_nd * h) * 0.5))
|
||||
|
||||
def detect_all(frame_bgr):
|
||||
hsv = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2HSV)
|
||||
mw = cv2.inRange(hsv, white_lower, white_upper)
|
||||
my = cv2.inRange(hsv, yellow_lower, yellow_upper)
|
||||
mw = cv2.morphologyEx(mw, cv2.MORPH_DILATE, kernel, iterations=1)
|
||||
my = cv2.morphologyEx(my, cv2.MORPH_DILATE, kernel, iterations=1)
|
||||
mf = cv2.bitwise_and(mw, my)
|
||||
mf = cv2.morphologyEx(mf, cv2.MORPH_CLOSE, kernel, iterations=1)
|
||||
fx, fy, _ = centroid(mf)
|
||||
tx, ty = det["turtle_xy"]
|
||||
fx, fy = det["flower_xy"]
|
||||
bombs = det["bombs_xy"]
|
||||
|
||||
mb = cv2.inRange(hsv, black_lower, black_upper)
|
||||
bombs = bomb_centroids_filtered(mb)
|
||||
# Nearest Bomb (aus state_norm, schon normiert)
|
||||
n_tx, n_ty, n_fx, n_fy, nbx, nby = det["state_norm"]
|
||||
nb_px = (int(round(nbx * w)), int(round(nby * h))) if (len(bombs) > 0) else None
|
||||
|
||||
g1 = cv2.inRange(hsv, green1_lower, green1_upper)
|
||||
g2 = cv2.inRange(hsv, green2_lower, green2_upper)
|
||||
mg = cv2.bitwise_or(g1, g2)
|
||||
mg = cv2.morphologyEx(mg, cv2.MORPH_OPEN, kernel, iterations=1)
|
||||
mg = cv2.morphologyEx(mg, cv2.MORPH_DILATE, kernel, iterations=1)
|
||||
tx, ty, _ = centroid(mg)
|
||||
|
||||
masks = {"flower": mf, "bomb": mb, "turtle": mg}
|
||||
return (fx,fy), bombs, (tx,ty), masks
|
||||
|
||||
|
||||
def draw_overlay(frame, flower, bombs, turtle, fps):
|
||||
fx, fy = flower
|
||||
tx, ty = turtle
|
||||
# Flower
|
||||
if fx is not None:
|
||||
cv2.circle(frame, (fx,fy), 8, (0,255,255), 2)
|
||||
cv2.putText(frame, "Flower", (fx+10, fy-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,255), 2)
|
||||
nearest = None
|
||||
if bombs and tx is not None:
|
||||
nearest = min(bombs, key=lambda b: np.hypot(b[0]-tx, b[1]-ty))
|
||||
for (bx,by,_) in bombs:
|
||||
color = (60,60,60); thick = 2
|
||||
if nearest and (bx,by)==(nearest[0],nearest[1]):
|
||||
color = (0,0,255); thick = 3
|
||||
cv2.circle(frame, (bx,by), 10, color, thick)
|
||||
cv2.circle(frame_bgr, (fx, fy), 8, (0, 255, 255), 2)
|
||||
cv2.putText(frame_bgr, "Flower", (fx+10, fy-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,255), 2)
|
||||
|
||||
# Bomben (alle grau, nächste rot)
|
||||
for (bx, by, _a) in bombs:
|
||||
cv2.circle(frame_bgr, (bx, by), 10, (60, 60, 60), 2)
|
||||
if nb_px is not None:
|
||||
cv2.circle(frame_bgr, nb_px, 12, (0, 0, 255), 3)
|
||||
|
||||
# Turtle + Zonenrechtecke
|
||||
if tx is not None:
|
||||
cv2.circle(frame, (tx,ty), 8, (0,200,0), 2)
|
||||
cv2.putText(frame, "Turtle", (tx+10, ty-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,200,0), 2)
|
||||
cv2.circle(frame, (tx,ty), EAT_RADIUS, (0,255,0), 1)
|
||||
cv2.circle(frame, (tx,ty), COLL_RADIUS, (0,0,255), 1)
|
||||
cv2.putText(frame, f"FPS: {fps:.1f}", (20,40), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,255), 2)
|
||||
return frame
|
||||
cv2.circle(frame_bgr, (tx, ty), 8, (0, 200, 0), 2)
|
||||
cv2.putText(frame_bgr, "Turtle", (tx+10, ty-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,200,0), 2)
|
||||
cv2.rectangle(frame_bgr, (tx - eat_half_w_px, ty - eat_half_h_px),
|
||||
(tx + eat_half_w_px, ty + eat_half_h_px), (0,255,0), 1)
|
||||
cv2.rectangle(frame_bgr, (tx - coll_half_w_px, ty - coll_half_h_px),
|
||||
(tx + coll_half_w_px, ty + coll_half_h_px), (0,0,255), 1)
|
||||
|
||||
# HUD
|
||||
min_area_px = int(round(env.bomb_min_area_frac * h * w))
|
||||
hud_lines = [
|
||||
f"FPS: {fps:.1f}",
|
||||
f"state = [tx={n_tx:.3f}, ty={n_ty:.3f}, fx={n_fx:.3f}, fy={n_fy:.3f}, bx={nbx:.3f}, by={nby:.3f}]",
|
||||
f"eat_x_nd={env.eat_x_nd:.5f} eat_y_nd={env.eat_y_nd:.5f} coll_x_nd={env.collision_x_nd:.5f} coll_y_nd={env.collision_y_nd:.5f}",
|
||||
f"bomb_min_area_frac={env.bomb_min_area_frac:.7f} (-> min_area_px≈{min_area_px}) ref_size={env.w_ref}x{env.h_ref}",
|
||||
]
|
||||
y = 28
|
||||
for line in hud_lines:
|
||||
cv2.putText(frame_bgr, line, (16, y), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (255,255,255), 2)
|
||||
y += 24
|
||||
|
||||
def colorize(mask):
|
||||
return cv2.applyColorMap(
|
||||
cv2.normalize(mask, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8),
|
||||
cv2.COLORMAP_JET
|
||||
)
|
||||
return frame_bgr
|
||||
|
||||
|
||||
def main():
|
||||
@@ -144,31 +90,35 @@ def main():
|
||||
sct = mss.mss()
|
||||
prev = time.time()
|
||||
fps = 0.0
|
||||
|
||||
while True:
|
||||
raw = np.array(sct.grab(monitor_area))
|
||||
raw = np.array(sct.grab(monitor_area)) # BGRA
|
||||
frame = cv2.cvtColor(raw, cv2.COLOR_BGRA2BGR)
|
||||
flower, bombs, turtle, masks = detect_all(frame)
|
||||
|
||||
# Detection mit exakt derselben Logik wie in der Env
|
||||
det = env._detect_entities(frame)
|
||||
|
||||
now = time.time()
|
||||
dt = now - prev; prev = now
|
||||
if dt > 0: fps = 1.0/dt
|
||||
if dt > 0:
|
||||
fps = 1.0 / dt
|
||||
|
||||
if mode == MODE_OVERLAY:
|
||||
out = draw_overlay(frame.copy(), flower, bombs, turtle, fps)
|
||||
elif mode == MODE_FLOWER_MASK:
|
||||
out = colorize(masks["flower"])
|
||||
elif mode == MODE_BOMB_MASK:
|
||||
out = colorize(masks["bomb"])
|
||||
elif mode == MODE_TURTLE_MASK:
|
||||
out = colorize(masks["turtle"])
|
||||
# --- hier skalieren ---
|
||||
out = _draw_overlay(frame.copy(), det, fps)
|
||||
else:
|
||||
h, w = det["frame_hw"]
|
||||
out = np.zeros((h, w, 3), dtype=np.uint8)
|
||||
out = _draw_overlay(out, det, fps)
|
||||
|
||||
if WINDOW_SCALE != 1.0:
|
||||
out = cv2.resize(out, (int(out.shape[1]*WINDOW_SCALE), int(out.shape[0]*WINDOW_SCALE)))
|
||||
cv2.imshow("Debug Viewer", out)
|
||||
out = cv2.resize(out, (int(out.shape[1] * WINDOW_SCALE), int(out.shape[0] * WINDOW_SCALE)))
|
||||
cv2.imshow("Env-State Viewer (axes-normalized)", out)
|
||||
|
||||
key = cv2.waitKey(1) & 0xFF
|
||||
if key == ord('q'): break
|
||||
elif key == ord('0'): mode = MODE_OVERLAY
|
||||
elif key == ord('1'): mode = MODE_FLOWER_MASK
|
||||
elif key == ord('2'): mode = MODE_BOMB_MASK
|
||||
elif key == ord('3'): mode = MODE_TURTLE_MASK
|
||||
elif key == ord('1'): mode = MODE_TEXT_ONLY
|
||||
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user