79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
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
|