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 = (154, 160, 48, 329) self.player_fp_roi = (160, 166, 49, 160) self.player_sp_roi = (166, 173, 49, 217) 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