import cv2 import numpy as np import re from vision_agent import EldenVision class UISelector: def __init__(self): self.vision = EldenVision(2) 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()