Initial commit — Elden Ring RL agent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
78
vision_agent.py
Normal file
78
vision_agent.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
from collections import deque
|
||||
import threading
|
||||
import time
|
||||
|
||||
class EldenVision:
|
||||
def __init__(self, device_index=2, stack_size=4):
|
||||
self.cap = cv2.VideoCapture(device_index, cv2.CAP_V4L2)
|
||||
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
|
||||
self.frame_rgb = None
|
||||
self.frame_hsv = None
|
||||
self.stopped = False
|
||||
self.lock = threading.Lock()
|
||||
|
||||
# PRESERVED USER CONFIGS
|
||||
self.player_hp_roi = (158, 164, 48, 329)
|
||||
self.player_fp_roi = (163, 169, 49, 160)
|
||||
self.player_sp_roi = (169, 176, 48, 216)
|
||||
self.boss_hp_roi = (427, 437, 149, 488)
|
||||
|
||||
self.stack_size = stack_size
|
||||
self.frame_stack = deque(maxlen=stack_size)
|
||||
|
||||
threading.Thread(target=self.update, args=(), daemon=True).start()
|
||||
while self.frame_rgb is None: time.sleep(0.1)
|
||||
|
||||
def update(self):
|
||||
while not self.stopped:
|
||||
ret, frame = self.cap.read()
|
||||
if ret and frame is not None:
|
||||
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
||||
with self.lock:
|
||||
self.frame_rgb = rgb
|
||||
self.frame_hsv = hsv
|
||||
else:
|
||||
time.sleep(0.001)
|
||||
|
||||
def detect_fog(self, frame_hsv=None):
|
||||
"""Detects the bright white/gold glow of a fog gate in center screen."""
|
||||
if frame_hsv is None:
|
||||
with self.lock: frame_hsv = self.frame_hsv.copy()
|
||||
|
||||
# Center ROI where fog usually appears
|
||||
center_crop = frame_hsv[250:450, 200:440]
|
||||
# Fog is very bright (High Value) and low saturation (White)
|
||||
white_mask = cv2.inRange(center_crop, np.array([0, 0, 200]), np.array([180, 50, 255]))
|
||||
return np.sum(white_mask > 0) > 5000 # Threshold for 'significant' fog
|
||||
|
||||
def get_bar_percent(self, hsv_frame, roi, color_type='red'):
|
||||
y1, y2, x1, x2 = roi
|
||||
crop = hsv_frame[y1:y2, x1:x2]
|
||||
if crop.size == 0: return 100.0
|
||||
if color_type == 'red':
|
||||
mask = cv2.inRange(crop, np.array([0, 120, 70]), np.array([10, 255, 255]))
|
||||
elif color_type == 'blue':
|
||||
mask = cv2.inRange(crop, np.array([100, 120, 70]), np.array([130, 255, 255]))
|
||||
elif color_type == 'green':
|
||||
mask = cv2.inRange(crop, np.array([40, 100, 50]), np.array([80, 255, 255]))
|
||||
count = np.sum(mask > 0)
|
||||
if count < 5: return 100.0 if color_type != 'boss' else 0.0
|
||||
return (count / mask.size) * 100
|
||||
|
||||
def get_state(self):
|
||||
with self.lock:
|
||||
fr_rgb = self.frame_rgb.copy()
|
||||
fr_hsv = self.frame_hsv.copy()
|
||||
p_hp = self.get_bar_percent(fr_hsv, self.player_hp_roi, 'red')
|
||||
p_fp = self.get_bar_percent(fr_hsv, self.player_fp_roi, 'blue')
|
||||
p_sp = self.get_bar_percent(fr_hsv, self.player_sp_roi, 'green')
|
||||
b_hp = self.get_bar_percent(fr_hsv, self.boss_hp_roi, 'red')
|
||||
self.frame_stack.append(fr_rgb)
|
||||
while len(self.frame_stack) < self.stack_size: self.frame_stack.append(fr_rgb)
|
||||
return np.concatenate(list(self.frame_stack), axis=-1), p_hp, p_fp, p_sp, b_hp
|
||||
|
||||
def stop(self): self.stopped = True
|
||||
Reference in New Issue
Block a user