88 lines
3.9 KiB
Python
88 lines
3.9 KiB
Python
import cv2
|
|
import numpy as np
|
|
import re
|
|
from vision_agent import EldenVision
|
|
|
|
class UISelector:
|
|
def __init__(self):
|
|
self.vision = EldenVision(0)
|
|
self.window_name = "FLUID CALIBRATOR: TAB=Switch, R=Mode, S=SAVE, Q=Quit"
|
|
cv2.namedWindow(self.window_name, cv2.WINDOW_NORMAL)
|
|
cv2.resizeWindow(self.window_name, 1280, 1280)
|
|
cv2.setMouseCallback(self.window_name, self.on_mouse)
|
|
|
|
self.rois = [
|
|
list(self.vision.player_hp_roi),
|
|
list(self.vision.player_fp_roi),
|
|
list(self.vision.player_sp_roi),
|
|
list(self.vision.boss_hp_roi)
|
|
]
|
|
self.names = ["HP (Red)", "FP (Blue)", "SP (Green)", "BOSS"]
|
|
self.colors = [(255, 0, 0), (255, 255, 0), (0, 255, 255), (0, 255, 0)]
|
|
self.types = ['red', 'blue', 'green', 'red']
|
|
|
|
self.active_idx = 0
|
|
self.mode = 'MOVE'
|
|
self.dragging = False
|
|
self.start_mouse = (0, 0)
|
|
self.start_roi = []
|
|
|
|
def on_mouse(self, event, x, y, flags, param):
|
|
if event == cv2.EVENT_LBUTTONDOWN:
|
|
self.dragging = True
|
|
self.start_mouse = (x, y)
|
|
self.start_roi = list(self.rois[self.active_idx])
|
|
elif event == cv2.EVENT_MOUSEMOVE:
|
|
if not self.dragging: return
|
|
dx, dy = x - self.start_mouse[0], y - self.start_mouse[1]
|
|
roi = self.rois[self.active_idx]
|
|
if self.mode == 'MOVE':
|
|
roi[0], roi[1], roi[2], roi[3] = self.start_roi[0]+dy, self.start_roi[1]+dy, self.start_roi[2]+dx, self.start_roi[3]+dx
|
|
else:
|
|
roi[1], roi[3] = self.start_roi[1]+dy, self.start_roi[3]+dx
|
|
elif event == cv2.EVENT_LBUTTONUP:
|
|
self.dragging = False
|
|
|
|
def save_to_code(self):
|
|
file_path = "vision_agent.py"
|
|
with open(file_path, 'r') as f: content = f.read()
|
|
# Regex update to preserve logic but change coordinates
|
|
content = re.sub(r'self.player_hp_roi = \(.*?\)', f'self.player_hp_roi = {tuple(self.rois[0])}', content)
|
|
content = re.sub(r'self.player_fp_roi = \(.*?\)', f'self.player_fp_roi = {tuple(self.rois[1])}', content)
|
|
content = re.sub(r'self.player_sp_roi = \(.*?\)', f'self.player_sp_roi = {tuple(self.rois[2])}', content)
|
|
content = re.sub(r'self.boss_hp_roi = \(.*?\)', f'self.boss_hp_roi = {tuple(self.rois[3])}', content)
|
|
with open(file_path, 'w') as f: f.write(content)
|
|
print(f"\n[!!!] COORDINATES UPDATED in {file_path}")
|
|
|
|
def run(self):
|
|
while True:
|
|
obs, hp, fp, sp, boss = self.vision.get_state()
|
|
# AI sees RGB, but OpenCV needs BGR for imshow
|
|
frame_rgb = obs[:, :, -3:].copy()
|
|
frame_bgr = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2BGR)
|
|
|
|
# HUD
|
|
draw = frame_bgr
|
|
cv2.putText(draw, f"ACTIVE: {self.names[self.active_idx]} ({self.mode})", (10, 30), 0, 0.7, self.colors[self.active_idx], 2)
|
|
|
|
for i, roi in enumerate(self.rois):
|
|
cv2.rectangle(draw, (roi[2], roi[0]), (roi[3], roi[1]), self.colors[i], 4 if i==self.active_idx else 1)
|
|
# We can use the RGB frame for percent check, but color_type expects BGR-style logic or we adjust it
|
|
# Actually, vision_agent.get_bar_percent uses HSV, which we pre-calculate.
|
|
# For the tool, we just show the numbers returned by get_state.
|
|
|
|
cv2.putText(draw, f"HP: {hp:.0f}% FP: {fp:.0f}% SP: {sp:.0f}%", (10, 610), 0, 0.6, (255, 255, 255), 2)
|
|
|
|
cv2.imshow(self.window_name, draw)
|
|
key = cv2.waitKey(1) & 0xFF
|
|
if key == ord('q'): break
|
|
elif key == ord('r'): self.mode = 'RESIZE' if self.mode == 'MOVE' else 'MOVE'
|
|
elif key == ord('\t'): self.active_idx = (self.active_idx + 1) % 4
|
|
elif key == ord('s'): self.save_to_code()
|
|
|
|
self.vision.stop()
|
|
cv2.destroyAllWindows()
|
|
|
|
if __name__ == "__main__":
|
|
UISelector().run()
|