From 6888b55612dd9eb8443e298dc4d9c219612246f3 Mon Sep 17 00:00:00 2001 From: Nicole Rappe <nicole.rappe@bunny-lab.io> Date: Sun, 16 Feb 2025 21:07:26 -0700 Subject: [PATCH] Fixed On-Screen OCR region Overlay --- .../data_collector.cpython-312.pyc | Bin 11112 -> 10299 bytes Modules/data_collector.py | 186 ++++++++---------- .../Flyff/Resources/bars_template.png | Bin ...lyff_character_status_node.cpython-312.pyc | Bin 5005 -> 5251 bytes Nodes/Flyff/flyff_character_status_node.py | 53 +++-- 5 files changed, 108 insertions(+), 131 deletions(-) rename bars_template.png => Nodes/Flyff/Resources/bars_template.png (100%) diff --git a/Modules/__pycache__/data_collector.cpython-312.pyc b/Modules/__pycache__/data_collector.cpython-312.pyc index bb082f31f103164178cd6209590e8da85690ec89..2cfb3154669bcf66305291adf2b72ceea8d6040a 100644 GIT binary patch literal 10299 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 L@Sg;#@$UZ@-k24E literal 11112 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 E57<SoU;qFB diff --git a/Modules/data_collector.py b/Modules/data_collector.py index 2144aa8..bc2e29e 100644 --- a/Modules/data_collector.py +++ b/Modules/data_collector.py @@ -3,12 +3,13 @@ import threading import time import re +import sys import numpy as np import cv2 import pytesseract from PIL import Image, ImageGrab, ImageFilter -from PyQt5.QtWidgets import QWidget, QApplication +from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import QRect, QPoint, Qt, QMutex, QTimer from PyQt5.QtGui import QPainter, QPen, QColor, QFont @@ -21,19 +22,37 @@ LABEL_HEIGHT = 20 collector_mutex = QMutex() regions = {} -overlay_window = None + +app_instance = None + +def _ensure_qapplication(): + """ + Ensures that QApplication is initialized before creating widgets. + """ + global app_instance + if QApplication.instance() is None: + print("Starting QApplication in a separate thread.") + app_instance = QApplication(sys.argv) + threading.Thread(target=app_instance.exec_, daemon=True).start() def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT): + """ + Creates an OCR region with a visible, resizable box on the screen. + """ + print(f"Creating OCR Region: {region_id} at ({x}, {y}, {w}, {h})") + + _ensure_qapplication() # Ensure QApplication is running first + collector_mutex.lock() if region_id in regions: collector_mutex.unlock() return regions[region_id] = { 'bbox': [x, y, w, h], - 'raw_text': "" + 'raw_text': "", + 'widget': OCRRegionWidget(x, y, w, h, region_id) } collector_mutex.unlock() - _ensure_overlay() def get_raw_text(region_id): collector_mutex.lock() @@ -69,6 +88,8 @@ def _update_ocr_loop(): regions[rid]['raw_text'] = raw_text collector_mutex.unlock() + print(f"OCR Text for {rid}: {raw_text}") + time.sleep(0.7) def _preprocess_image(image): @@ -77,130 +98,87 @@ def _preprocess_image(image): thresh = scaled.point(lambda p: 255 if p > 200 else 0) return thresh.filter(ImageFilter.MedianFilter(3)) -def _ensure_overlay(): - """ - Creates the overlay window if none exists. - If no QApplication instance is running yet, schedule the creation after - the main application event loop starts (to avoid "Must construct a QApplication first" errors). - """ - global overlay_window - if overlay_window is not None: - return +class OCRRegionWidget(QWidget): + def __init__(self, x, y, w, h, region_id): + super().__init__() - # If there's already a running QApplication, create overlay immediately. - if QApplication.instance() is not None: - overlay_window = OverlayCanvas() - overlay_window.show() - else: - # Schedule creation for when the app event loop is up. - def delayed_create(): - global overlay_window - if overlay_window is None: - overlay_window = OverlayCanvas() - overlay_window.show() - - QTimer.singleShot(0, delayed_create) - -class OverlayCanvas(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - screen_geo = QApplication.primaryScreen().geometry() - self.setGeometry(screen_geo) - self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) + self.setGeometry(x, y, w, h) + self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool) self.setAttribute(Qt.WA_TranslucentBackground, True) + self.setAttribute(Qt.WA_TransparentForMouseEvents, False) self.drag_offset = None self.selected_handle = None - self.selected_region_id = None + self.region_id = region_id + + print(f"OCR Region Widget Created at {x}, {y}, {w}, {h}") + + self.show() def paintEvent(self, event): painter = QPainter(self) pen = QPen(QColor(0, 0, 255)) - pen.setWidth(5) + pen.setWidth(3) painter.setPen(pen) - collector_mutex.lock() - region_copy = {rid: data['bbox'][:] for rid, data in regions.items()} - collector_mutex.unlock() + # Draw main rectangle + painter.drawRect(0, 0, self.width(), self.height()) - for rid, bbox in region_copy.items(): - x, y, w, h = bbox - painter.drawRect(x, y, w, h) - painter.setFont(QFont("Arial", 12, QFont.Bold)) - painter.setPen(QColor(0, 0, 255)) - painter.drawText(x, y - 5, f"OCR Region: {rid}") + # Draw resize handles + painter.setBrush(QColor(0, 0, 255)) + for handle in self._resize_handles(): + painter.drawRect(handle) + + def _resize_handles(self): + w, h = self.width(), self.height() + return [ + QRect(0, 0, HANDLE_SIZE, HANDLE_SIZE), # Top-left + QRect(w - HANDLE_SIZE, h - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE) # Bottom-right + ] def mousePressEvent(self, event): if event.button() == Qt.LeftButton: - collector_mutex.lock() - all_items = list(regions.items()) - collector_mutex.unlock() - - for rid, data in all_items: - x, y, w, h = data['bbox'] - handles = self._resize_handles(x, y, w, h) - for i, handle_rect in enumerate(handles): - if handle_rect.contains(event.pos()): - self.selected_handle = i - self.selected_region_id = rid - return - if QRect(x, y, w, h).contains(event.pos()): - self.drag_offset = event.pos() - QPoint(x, y) - self.selected_region_id = rid + for i, handle in enumerate(self._resize_handles()): + if handle.contains(event.pos()): + self.selected_handle = i return - def mouseMoveEvent(self, event): - if not self.selected_region_id: - return - collector_mutex.lock() - if self.selected_region_id not in regions: - collector_mutex.unlock() - return - bbox = regions[self.selected_region_id]['bbox'] - collector_mutex.unlock() + self.drag_offset = event.pos() - x, y, w, h = bbox + def mouseMoveEvent(self, event): if self.selected_handle is not None: - # resizing - if self.selected_handle == 0: # top-left - new_w = w + (x - event.x()) - new_h = h + (y - event.y()) - new_x = event.x() - new_y = event.y() - if new_w < 10: new_w = 10 - if new_h < 10: new_h = 10 - collector_mutex.lock() - if self.selected_region_id in regions: - regions[self.selected_region_id]['bbox'] = [new_x, new_y, new_w, new_h] - collector_mutex.unlock() - elif self.selected_handle == 1: # bottom-right - new_w = event.x() - x - new_h = event.y() - y - if new_w < 10: new_w = 10 - if new_h < 10: new_h = 10 - collector_mutex.lock() - if self.selected_region_id in regions: - regions[self.selected_region_id]['bbox'] = [x, y, new_w, new_h] - collector_mutex.unlock() + w, h = self.width(), self.height() + if self.selected_handle == 0: # Top-left + new_w = w + (self.x() - event.globalX()) + new_h = h + (self.y() - event.globalY()) + new_x = event.globalX() + new_y = event.globalY() + if new_w < 20: new_w = 20 + if new_h < 20: new_h = 20 + self.setGeometry(new_x, new_y, new_w, new_h) + elif self.selected_handle == 1: # Bottom-right + new_w = event.globalX() - self.x() + new_h = event.globalY() - self.y() + if new_w < 20: new_w = 20 + if new_h < 20: new_h = 20 + self.setGeometry(self.x(), self.y(), new_w, new_h) + + collector_mutex.lock() + if self.region_id in regions: + regions[self.region_id]['bbox'] = [self.x(), self.y(), self.width(), self.height()] + collector_mutex.unlock() + self.update() elif self.drag_offset: - # dragging - new_x = event.x() - self.drag_offset.x() - new_y = event.y() - self.drag_offset.y() + new_x = event.globalX() - self.drag_offset.x() + new_y = event.globalY() - self.drag_offset.y() + self.move(new_x, new_y) + collector_mutex.lock() - if self.selected_region_id in regions: - regions[self.selected_region_id]['bbox'][0] = new_x - regions[self.selected_region_id]['bbox'][1] = new_y + if self.region_id in regions: + regions[self.region_id]['bbox'] = [new_x, new_y, self.width(), self.height()] collector_mutex.unlock() - self.update() def mouseReleaseEvent(self, event): self.selected_handle = None self.drag_offset = None - self.selected_region_id = None - - def _resize_handles(self, x, y, w, h): - return [ - QRect(x - HANDLE_SIZE//2, y - HANDLE_SIZE//2, HANDLE_SIZE, HANDLE_SIZE), # top-left - QRect(x + w - HANDLE_SIZE//2, y + h - HANDLE_SIZE//2, HANDLE_SIZE, HANDLE_SIZE) # bottom-right - ] diff --git a/bars_template.png b/Nodes/Flyff/Resources/bars_template.png similarity index 100% rename from bars_template.png rename to Nodes/Flyff/Resources/bars_template.png diff --git a/Nodes/Flyff/__pycache__/flyff_character_status_node.cpython-312.pyc b/Nodes/Flyff/__pycache__/flyff_character_status_node.cpython-312.pyc index fa3bce4df7419ac6a8d5d8ad797194cd1380c04e..3192abdb659b64b895a81563a4a6881051ecb2b6 100644 GIT binary patch delta 1852 zcmZuxTSy#N7(QoqE@x+Fc6Gg=M$O>08_lYywb;})ST7AttKvh@gk{;8+BNI$_RNSE z##nj*11Ta0T1#8nJXH}IXbL4SKDG~q5Q(j2h*U}-p--vWzVxN%%sN>G2j;*3|2OlW z|NNgcei%`IQB@hxr{st4C%#)z%i-8cV|x?=9qM8VP5H<CQ}UP$0S5+vE`0=aWcW6G zECYbCz#JFx&)-^EtmL}om7khc_M>4fp4PSLtRA-vQ!}l&HBIiodOvi;;nC!jfyqPo zC-*6L_ebtAT(qikl>pc{5^N9)c{UqNR(o=uPilGDlO}6DDbHzkU0(B~4VaT4p#HAY z$~StUd9Ih|)8;^=f_%;YRm<9zd`eppDRu;NI%{C;rzQu*V###Uip8)<z7?)QiSS}u z2Nsx5uviNmiLuPI<w%K4I&CB@N6q3)!Z1ymnx%GuHV#{)QyhmHSrHqgFwHh)NH)b@ zxJRN=HR+N{=&Skm%A3else1e|D&0X1Tc}|hz3@9ymerf;gVNS*)OIL>(n@k=iN7T? zyL?mLK^0r5Vh7c1p_*?xc4|AfYCE^li_g7fTc~Wc_*YbYKv6-0Be%I?d4&GyXTXM& zkX+*{$Zyi;<vo_f0@$PTwr_*W$q<ky!RiKGuzk8%PHmoJAz%k^ho$Di0I&m-A@UT} zck(A~o<GlZ<Q;&=7lb^BbOJ=Nl@lP!5r}vUgxd1OJ?Rt>DG!29fT*^50z^FmLB~L- z%`2Vfr-1l#Ab#2|`2<MN4&rlGp_gn2b0B9zc1Rbm({5u<7Z;coxc<7U1;~B57Aj<4 zPL!4m<wh!*p3vUz9ns!QrVX>3j0So%zayL3RMJW@6B{<1%sRf5k#>YEPNprg5vYMt zazC&JTgi-aNjyit!CWRkEAfIyO5uZWWUX^sVUtx>akoi51DgjRC>(?)yA!0Ozm8uI zQ<6BkYwiy)7uy>L9}pbutvoh5(1zZGxVO?z?gd*2=c^(@D0H6tQu5B+^`6#KA00pL z3!n?+VyFm)$TNR2(j}XBP49(@s!mHny5APvh})r}#nU2WJzygmp?r00w&&DHaQ>34 z9X-AARLambdi#?ZJ(-}|oMvT?7NC}RH;&^8%fPu!Xln1^%oIC~=<@>e>PUP>TVy9R zYRp>Q5ed_?1h|ipentiu8D!)QMv56>cW9m;9O~8_*n$gO?K0IcTNLwrKNDHtywG>W z4XS@Df-t+Tjxu3bF&v+XSriV}Qxkp}(9MO1m?)CXf?6@k#Eaxf!7Kh&CN@(-x(d%n zcB$|_I7FbhW~V5+RTN#b?%Y_v@vx|82|YsUQf76Q?w`Gmm&nJ3_h1`&HQX1_SOvFu zGg%IoRJ2gtWTWvKc8jyE>8{Qo*$kK0o!xJ36vpAdBd|<p$8DZ7qBv44re_j#v0fnm zg_~_<Xl~f*j1F798EoYCt8_V|Pp1qMi!6=(u3LB=<mxau2VIzQgL?2JRoQo#5lWu< lAcTMOJme1)0Oehv?SjT#aP|+-ddOdcuzhv*AHcX<>VL>%e3<|M delta 1657 zcma)6TTEO<7@pZZw>@VM%d$n>wzPwk%fdowu`v>XRxDy8$dek{WOLYafJ2u(o0+rH zC5PfIUJ@@M<AX`9>60npp{b1zCi?E>r9>MNOk+&?)Te6E_~3*89J(o+Xv!q#oB3zH z`M<fH@2$*-9p;awsUs*~z4PVlKdWXMPpo$Iw=ZZ@8b%THJhGLyk*zw>^{8MWG!?5v zGMd$o5z_fhscH3!)J-}koJI1oLz(LpGXpy5A!8OJMUS|}QrTxmy|ORrUY)Fd(T&OK zM(;|Nlq|{|MqHoFIn)6v@#h?vWII`%5MmW=!W^Fw+w!g4f>pF;9ooUj*kqQB!#4`w z=~pL-mCt+Bc8jxx3gqu0rwYs?<r2&alQZHiLT2ZJPi9=FU^BAl`g5dSXoV}V$!k`j z?C>OR<0tWNkvsTCD}Yo%nKb`ax_c-FyUx^Y$*f#*DAgd^(sDVs==!-FmH7|yIjryw z<rx1!IjbCo;iVRyY)B`noPE&6HW6=BN9217ikZBm0$C*@+Mngu)I-hN(BHJFwQp$c zKWm*K>tpkM^X6lHx3putMLU28_@MSp^ti9`mm&wJY$=G^avCzPM*yHK8-YQe^o^Ye zp}?3otL=xit*pbviBheXrP?{X&uELvyJeIbnRpPdk%{k7M%g6;b3z$)w~SgNV+Ll8 zjJZb{ZI=wp31wnCGBdUYhZd`msSE08m!H@<5;(NFJ<244ge{+kqo)yDUKWvl{<$#H zdC6$S2LHs!^SbyT*7%F@G%v(ka3}vLeie7|r_3`-78Kc={9V(E-f2qT_}e^yvm+QK z$1oFrBX1miTv}@Y$UnHQaD`$>{D$}E`EX)H3eddD--xF8^~6DbJ=V<cCK4<7GqrlP z7y;wI9zn#829ZlhJfchJvQ&LS|I3$cC6GeC{3t#jGL$oL&`L;GA4M12vSYR$Xuvlv zM;|Vw63>`R7XPlkd1bm1I>T(io3;wXcNZKg+@j)@DOs?fWtB<=H*fjiKBRNnqmET@ zS#PP50Yi9DGAbPeEjlD%SingErvyAJASECUuq2I54v;N;l!|AuB#jS4NRwfER5S&1 zNe1f?thNcrtU%9JeAe-E)LP65uc1evi@qR0=2w!fN~dTJ@b8m@sV>1bOVrCdjDe4U zGx9`3Ps=Une;sY>Xx|f?sosrL?^XZW#kGq+rH0<qz!6S7&7Fp?aW_AlI&BD>*-8Hj z_fn1fGY~WJR8CTnK6I%N>iOrX^pWF#^tH)n@m~`-E%(#zDkGzBskxl(<-y2K@Ly8d z8Fk#V%LRu~S#ZR@!YpfOXHvLy?U{v;G(__-E<{;7z`ZEO_;*Rg()|X6_1lQtMjgMR SzHR9o#{HjO_!Egb%=0gxJXzuZ diff --git a/Nodes/Flyff/flyff_character_status_node.py b/Nodes/Flyff/flyff_character_status_node.py index afd9701..3a2b5ef 100644 --- a/Nodes/Flyff/flyff_character_status_node.py +++ b/Nodes/Flyff/flyff_character_status_node.py @@ -1,46 +1,44 @@ #!/usr/bin/env python3 """ -Flyff Character Status Node (New Version): - - Has no inputs/outputs. - - Creates an OCR region in data_collector. - - Periodically grabs raw text from that region, parses it here in the node, - and sets data_manager's HP, MP, FP, EXP accordingly. - - Also updates its own text fields with the parsed values. +Flyff Character Status Node: +- Creates an OCR region in data_collector. +- Periodically grabs raw text from that region and updates status. """ import re from OdenGraphQt import BaseNode from PyQt5.QtWidgets import QMessageBox +from PyQt5.QtCore import QTimer # Corrected import from Modules import data_manager, data_collector class FlyffCharacterStatusNode(BaseNode): - __identifier__ = 'bunny-lab.io.flyff_character_status_node' - NODE_NAME = 'Flyff - Character Status' + __identifier__ = "bunny-lab.io.flyff_character_status_node" + NODE_NAME = "Flyff - Character Status" def __init__(self): super(FlyffCharacterStatusNode, self).__init__() - # Prevent duplicates + if data_manager.character_status_collector_exists: QMessageBox.critical(None, "Error", "Only one Flyff Character Status Collector node is allowed.") raise Exception("Duplicate Character Status Node.") data_manager.character_status_collector_exists = True - # Add text fields for display - self.add_text_input('hp', 'HP', text="HP: 0/0") - self.add_text_input('mp', 'MP', text="MP: 0/0") - self.add_text_input('fp', 'FP', text="FP: 0/0") - self.add_text_input('exp', 'EXP', text="EXP: 0%") + self.add_text_input("hp", "HP", text="HP: 0/0") + self.add_text_input("mp", "MP", text="MP: 0/0") + self.add_text_input("fp", "FP", text="FP: 0/0") + self.add_text_input("exp", "EXP", text="EXP: 0%") - # Create a unique region id for this node (or just "character_status") self.region_id = "character_status" data_collector.create_ocr_region(self.region_id, x=250, y=50, w=180, h=130) - # Start the data_collector background thread (if not already started) data_collector.start_collector() - - # Set the node name self.set_name("Flyff - Character Status") + # Set up a timer to periodically update character stats + self.timer = QTimer() + self.timer.timeout.connect(self.process_input) + self.timer.start(1000) # Update every second + def parse_character_stats(self, raw_text): """ Extract HP, MP, FP, EXP from the raw OCR text lines. @@ -52,6 +50,8 @@ class FlyffCharacterStatusNode(BaseNode): exp_value = 0.0 if len(lines) >= 4: + print("Processing OCR Lines:", lines) # Debugging output + # line 1: HP hp_match = re.search(r"(\d+)\s*/\s*(\d+)", lines[0]) if hp_match: @@ -82,15 +82,14 @@ class FlyffCharacterStatusNode(BaseNode): def process_input(self): """ - Called periodically by the global timer in your main application (borealis.py). + Called periodically to update character status from OCR. """ - # Grab raw text from data_collector raw_text = data_collector.get_raw_text(self.region_id) + print("Raw OCR Text:", raw_text) # Debugging OCR text reading - # Parse it hp_c, hp_t, mp_c, mp_t, fp_c, fp_t, exp_v = self.parse_character_stats(raw_text) - # Update data_manager + # Update the data manager with the parsed values data_manager.set_data_bulk({ "hp_current": hp_c, "hp_total": hp_t, @@ -101,8 +100,8 @@ class FlyffCharacterStatusNode(BaseNode): "exp": exp_v }) - # Update the node's text fields - self.set_property('hp', f"HP: {hp_c}/{hp_t}") - self.set_property('mp', f"MP: {mp_c}/{mp_t}") - self.set_property('fp', f"FP: {fp_c}/{fp_t}") - self.set_property('exp', f"EXP: {exp_v}%") + # Update the node's UI text fields + self.set_property("hp", f"HP: {hp_c}/{hp_t}") + self.set_property("mp", f"MP: {mp_c}/{mp_t}") + self.set_property("fp", f"FP: {fp_c}/{fp_t}") + self.set_property("exp", f"EXP: {exp_v}%")