From 5c23653d595608fd1c1c3334b2f6786b72ffdd2d Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Wed, 26 Feb 2025 02:23:38 -0700 Subject: [PATCH] Fully Customizable GPU Accelerated Identification Nodes --- .../data_collector.cpython-312.pyc | Bin 14312 -> 14019 bytes Modules/data_collector.py | 29 +++++++----------- ...lyff_character_status_node.cpython-312.pyc | Bin 5132 -> 5182 bytes Nodes/Flyff/flyff_character_status_node.py | 2 +- .../identification_overlay.cpython-312.pyc | Bin 4179 -> 4961 bytes .../General Purpose/identification_overlay.py | 29 +++++++++++++++--- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/Modules/__pycache__/data_collector.cpython-312.pyc b/Modules/__pycache__/data_collector.cpython-312.pyc index 2341494517f6f9553ec66384d6fbe41fc8ee5b77..254d7f928eae3ddf785027ef3c88fe819f16cf93 100644 GIT binary patch delta 2166 zcmZuyYitx%6rMY?v#-9EzDpmweQdWwx22R)LW~N9(iUo|r9@mX>vm_lUD)oHJJXip zDm7^o5+jl;Q6MBn(a`jV#Z}>t1mZ6PKOi)yBPx+-><<%c@fk=wXSTaF%1!p0bI&>V z-1E9;e~x`V?75niW#?e|ZeI#n-5hrpH>qV_A{MWo_Z%hNa^9d>&YvQ_RdT@;=c|_s z0ljh&V1rx?*eI9FB_LldSI8^j+r)DnoLoA^$z_UTMo3!ot(hQ_Gx0YG@@4Zp@Pd}q zeelhIA1W^Xz%Q)d4=r}yIVFzBC&DRr7D^hj)q*pQB{i#yMnPujJoRj zI@%;xAS$~e;i%%$hQh)9QAJhRq9_v!+ik8`q1)126)$zM7tBt33s6n)Q^V}6`6=}5MMOKP3(Xr-x?=zJ}%4%?CY`We$NSU0&7P|)+Gc}lD3QVc^%9;pjHH9qZGL|+ z5>QpYU$uca)n1dy_BzQfR#uVo?3>CnX3r7RoVApVReAYd!p>ItOmS|XmEADqF_&QB z3CEghirB;IOv1Cv-h8V}WC9vFps|vNm}aXnCTsT0Qtb!?y)Tz#)_B+zZywuPQ@CS- zo925c&IQR%v(VdYgtGv;6(0UGVOblZ@8i}C+g>HATV)y;?^A->zq`(j91FNh zivRnbK&E1`*lG7V^G)2n%5J%9?EPOB)ZHkko3l#np?eKq>STLsYchWoxY9;i25LbQ zyTRuZAG=lCC<;(7f&C%X9wr=2H2%;Qdn$9gM&y8|s4#;RS8Pn7k-&s2-Cf3r8VjqV zfke7a2xf3ZQCYQAN#+yn(kaq<0c}}>v8WaZM^#;bWYG73N8bfV z#q=RErcl$IG{JJ~H)= z^YAo~D!g@WW3mP~5h%hH6jTEIImO-QbHx0Gsti$DSZNUp7ji|>zL0GZ>wnL6iEg9E zj5ClDd;tc`0_85x*Z{gfTIxH9vvQ;pg4JSAvo3yllkDg{2KB71Aj;V?*IS* delta 2424 zcmZ`)eQX@X6`$F?U9au)M{M8OiS6?`clLRmi{p)kVHvJqN3w`JGL*J zZ;#o%7>5HR5d@);Vr7Cbl~PDswN0ZcL06&vg@kBTAtaTBaqcM!);M zVQ=LrNsGYNdCDW=dUZz(rN_s-@yWeLO<9fWOQ&qdQ|9^}X45wB6+`}q?ni097NHMe z9Rix>R@q6;SjL{P9Jeydtt7K;W_sq?=sbOS@OBis$AiL$eqC0#BfY(#)jy%qhxJh~0Q_1URojPDTpnxCXGaiw{1=;wZtn<&IkNa3mR3CC4OEe8V3 z9~5`CJVMutzqO3h*+RogLk`}|C^$?AUgl-bt7324h5^H*4zj$FCo5q-N_gm}Jd@(i z<8odW*@`ALPxI0RNw{s#@975qZbK=Ds~D&Tn>lflC#K?A%T8g+LD=9Z>~=}! z{RKzU-O6}8nNHYtJZ@{SzL{K47ISM(Tn% z4EV@2F_hh(DsU&45XKNX0iaH6kgi4eBY>+x;D4Pmoe5V3Y7fh}8v1r0OFHG6@J?;T zKE>-$@=qnnEj(vWxOKbYoM9=%ClVPm&1|ER{~3=c>?q4PZbdc$b;GzTXIbWU(Q(zA zf|Vepi}R6T^}j&bABc}55qa;)I?>QI&{yd{#8A_n%OUL$A zl{(acteJ3_?m$~#E*O1kf^nv&OmIbNER`%a^ik_kX6ul)xwNT|G98_s>04H`8wwA- zT=cgWDK+OQH)PMZTo4ikfA##0Cd z0CCOOM87F?_wG?=B6zC4D6!mXy;N{3#?#hlBK?5(ERP<~mI44aBixk^TS)xTdNwD7Be15*7Q%Kii4G{Qx3X{cl7FF@K@wVR4= z#NNdbUdIiroo|nmFQr@>HLmXk*Z;f=A^7idmIhX-f=iCq84<}KSs z;`eRax#Pb5ML&7ZcMIwWA>h-`hY>a+c(3Mmq-GJYWqY>rR-`c7y&reA4U?9cOS6sq nJ>a27?9Tyi$duA0mCzMpVfd2x?H$n-aZ0;p$G;*tdkTI41QJ5d diff --git a/Modules/data_collector.py b/Modules/data_collector.py index 82d9760..e7952fd 100644 --- a/Modules/data_collector.py +++ b/Modules/data_collector.py @@ -45,10 +45,10 @@ def _ensure_qapplication(): app_instance = QApplication(sys.argv) # Start in main thread -def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT, color=(255, 255, 0)): +def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT, color=(255, 255, 0), thickness=2): """ Creates an OCR region with a visible, resizable box on the screen. - The color parameter allows customization (default yellow, blue for overlays). + Allows setting custom color (RGB) and line thickness. """ _ensure_qapplication() @@ -60,7 +60,7 @@ def create_ocr_region(region_id, x=250, y=50, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT, regions[region_id] = { 'bbox': [x, y, w, h], 'raw_text': "", - 'widget': OCRRegionWidget(x, y, w, h, region_id, color) + 'widget': OCRRegionWidget(x, y, w, h, region_id, color, thickness) } collector_mutex.unlock() @@ -179,19 +179,19 @@ def find_word_positions(region_id, word, offset_x=0, offset_y=0, margin=5, ocr_e return [] -def draw_identification_boxes(region_id, positions, color=(0, 0, 255)): +def draw_identification_boxes(region_id, positions, color=(0, 0, 255), thickness=2): """ Draws non-interactive rectangles at specified positions within the given OCR region. """ collector_mutex.lock() if region_id in regions and 'widget' in regions[region_id]: widget = regions[region_id]['widget'] - widget.set_draw_positions(positions, color) + widget.set_draw_positions(positions, color, thickness) collector_mutex.unlock() class OCRRegionWidget(QWidget): - def __init__(self, x, y, w, h, region_id, color): + def __init__(self, x, y, w, h, region_id, color, thickness): super().__init__() self.setGeometry(x, y, w, h) @@ -203,6 +203,7 @@ class OCRRegionWidget(QWidget): self.selected_handle = None self.region_id = region_id self.box_color = QColor(*color) + self.line_thickness = thickness self.draw_positions = [] self.show() @@ -210,31 +211,23 @@ class OCRRegionWidget(QWidget): def paintEvent(self, event): painter = QPainter(self) pen = QPen(self.box_color) - pen.setWidth(5) + pen.setWidth(self.line_thickness) painter.setPen(pen) # Draw main rectangle painter.drawRect(0, 0, self.width(), self.height()) # Draw detected word overlays - pen.setWidth(2) - pen.setColor(QColor(0, 0, 255)) - painter.setPen(pen) - for x, y, w, h in self.draw_positions: painter.drawRect(x, y, w, h) - # Draw resize handles - painter.setBrush(self.box_color) - for handle in self._resize_handles(): - painter.drawRect(handle) - - def set_draw_positions(self, positions, color): + def set_draw_positions(self, positions, color, thickness): """ - Update the positions where identification boxes should be drawn. + Updates the overlay positions and visual settings. """ self.draw_positions = positions self.box_color = QColor(*color) + self.line_thickness = thickness self.update() def _resize_handles(self): 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 25f26b3a08f8d96f352d6391bba5992bff45ccf0..a694d0a8cafe13103279b9bf34b730d9525da1dc 100644 GIT binary patch delta 380 zcmeCt*r&mJnwOW00SG4C-k097k(Zl^ixbFW2I9}NHY+jpGjgPer%0@kT+KdtE3-SJ z)a1X+8~LSIGlKLmFfcMyGHA+7-pg{wl=?MqMF$ji;d#SY{#1M%l+o0XXQ8ClkduV$URli8h7VlpGk zMt;fFj3D(442%qw44P7t53=0hWx2&zaf`9?7GwD>#*EFESREPJ6o4wK6es)hO7g|W zXXa&=#K#K(g^IZ*JFstKzRD52`9HfJ3)4%c$@)A|jCzy1cvdhPY&PcI$t>jzR9EBz zB3wa)8;EcR5gwD-1cTUAK}`S2ae^9bdLX954YrjMkH<2}g<=g7ksR Yyv1RYo1apelWJF#IhjSoj0GeE0J2R>TmS$7 diff --git a/Nodes/Flyff/flyff_character_status_node.py b/Nodes/Flyff/flyff_character_status_node.py index 4498261..184f9dc 100644 --- a/Nodes/Flyff/flyff_character_status_node.py +++ b/Nodes/Flyff/flyff_character_status_node.py @@ -29,7 +29,7 @@ class FlyffCharacterStatusNode(BaseNode): self.add_text_input("exp", "EXP", text="EXP: 0%") self.region_id = "character_status" - data_collector.create_ocr_region(self.region_id, x=250, y=50, w=180, h=130) + data_collector.create_ocr_region(self.region_id, x=250, y=50, w=180, h=130, color=(255, 255, 0), thickness=2) data_collector.start_collector() self.set_name("Flyff - Character Status") diff --git a/Nodes/General Purpose/__pycache__/identification_overlay.cpython-312.pyc b/Nodes/General Purpose/__pycache__/identification_overlay.cpython-312.pyc index 681be49ec0bcdd97f04baea83b80522c2d24443a..2970cf3023833664de7cfae10a2ed65750baac25 100644 GIT binary patch delta 1545 zcmYjQT})F~96zVGy}cj3w;;6i18FHq8@ou{APdB+xn_=>HLuhD8X&ux32!85i{jaRGFeDp?Z0RVyK#~G&I9ngYW zy|z_r&_cJvc_;pX8HA14ZNCL0_^$nnBhrQp)sm5|IkusSmPX;`HwOolth2qPy``h8 z%j7o&X64rtsd)J9ieM9V;FM!u+p3KeS6CBHnJ{C*NfVwk9oEw*Ks<r=28cTFgNmW+bB;FERD@92l*|b4*PL z<{UXT=gisj8&#)WMs+y_fKe}r@jxrG#+Bo9;%zx^FMA=#NO-#|1Rvldu15GH!Jw0$ z=1+lZA5&iKnidJaJ_)9nQ(zJ*ZhX=8%8W>|kxYRKM|3tOY*B28>a<{$HUjx6gelO0 zuhN#G2!W#{bX&!&xKJPEwC5%>HZ+d*QRdLclL-Uux41Deo{XctG>m+q512J0iIk>J zrje$Or}c!9NT+nvig!w(5ee<4aa5xzrbkBfxS<;HDZ>=UhS1qW%DR*_a~tj{v%)gg z7ny>!rsYT~)RZ^3y=)BN4z{9$A70qA+|;?$)cM)LVpC5s&|9qCGaDl*fre%O_9g%JPx^}f z?pc|p1RnWTvseu&dc;^0vlxLCqhf3qv)BmTq&M*N5ZD zq^c?qb<_UPm3X<_HIBwpsG^Ro1fE?6CC`CNM@v=BmkzJn1CHh=J%VG$-@Z1-Bt*TH zctyltxjU!C=_6r;R5#;u!!~8e`~vn1poj5 delta 945 zcmYjPO-vI(6rR~-x7)4VQYw`{rLCadK%|I*Bu3FDA`&4nF%hGgG@U6FOP9#H&_AJUO$Z(K&qc_I=;?=FOY^dhA2Ycoz)n zfG@KBYW($q6{7)OSvh{XMFN8WtIGiUh`c5X0RT6(vSey=m6hc$^_e1$*`z?SPHZ%N zEk=st`66KpFwUOCH@e2v!u0dTMp9do`=D znI)AMFv_~5C>v1Q+fBuVvo0*Vu;juCSIJrhi&9b447-XwGfgPre}YqL-d^E_>0!+I*z$wOYv$xz3XX*YYI zcd9*tPO+DIAM9Wi{h_oAH|_@lFbr*2)|?=xy)|ht6s(7}Y$n()^E?}!@N@xYxDn3cys37P?B8XXnOe3b563S!3ZinhLKkXJCos~jIhP@6nE0?p0gJ#`oRQCFF z>o9Tn&q4mHX#2T2R$bH^br(;~CHc$64eKtUg-p4RXY4(|`fHb2L-?XE_fZ?)tF$u` z?lk|{;-xpEiL?PW`vd6&*fNZCtGsmt3QPpjDS4|4rc+F-OD_tocXcXGaf1kD3mMza zl0pF?KB1H1B*$}dYylYUhE`0 V5owAhD(Vn~6Y#0_3wVKN`U`!r<_!P< diff --git a/Nodes/General Purpose/identification_overlay.py b/Nodes/General Purpose/identification_overlay.py index 1f70b00..5cebf2c 100644 --- a/Nodes/General Purpose/identification_overlay.py +++ b/Nodes/General Purpose/identification_overlay.py @@ -3,12 +3,13 @@ Identification Overlay Node: - Creates an OCR region in data_collector with a blue overlay. - Detects instances of a specified word and draws adjustable overlays. -- Users can configure offset, margin, polling frequency, and select OCR engine. +- Users can configure offset, margin, polling frequency, overlay color, and thickness. """ import re from OdenGraphQt import BaseNode from PyQt5.QtCore import QTimer +from PyQt5.QtGui import QColor from Modules import data_collector @@ -25,10 +26,14 @@ class IdentificationOverlayNode(BaseNode): self.add_text_input("margin", "Margin", text="5") # Box Margin self.add_text_input("polling_freq", "Polling Frequency (ms)", text="500") # Polling Rate self.add_combo_menu("ocr_engine", "Type", items=["CPU", "GPU"]) - self.set_property("ocr_engine", "CPU") # Set default value after adding the menu + self.set_property("ocr_engine", "CPU") # Default to CPU mode + + # Custom overlay options + self.add_text_input("overlay_color", "Overlay Color (RGB)", text="0,0,255") # Default blue + self.add_text_input("thickness", "Line Thickness", text="2") # Default 2px self.region_id = "identification_overlay" - data_collector.create_ocr_region(self.region_id, x=250, y=50, w=300, h=200, color=(0, 0, 255)) + data_collector.create_ocr_region(self.region_id, x=250, y=50, w=300, h=200, color=(0, 0, 255), thickness=2) data_collector.start_collector() self.set_name("Identification Overlay") @@ -76,6 +81,20 @@ class IdentificationOverlayNode(BaseNode): except ValueError: margin = 5 # Default margin if invalid input + # Parse overlay color + color_text = self.get_property("overlay_color") + try: + color = tuple(map(int, color_text.split(","))) # Convert "255,0,0" -> (255,0,0) + except ValueError: + color = (0, 0, 255) # Default to blue if invalid input + + # Parse thickness + thickness_text = self.get_property("thickness") + try: + thickness = max(1, int(thickness_text)) # Ensure at least 1px thickness + except ValueError: + thickness = 2 # Default thickness + if not search_term: return @@ -84,5 +103,5 @@ class IdentificationOverlayNode(BaseNode): self.region_id, search_term, offset_x, offset_y, margin, ocr_engine ) - # Draw detected word boxes - data_collector.draw_identification_boxes(self.region_id, detected_positions, color=(0, 0, 255)) + # Draw detected word boxes with custom color & thickness + data_collector.draw_identification_boxes(self.region_id, detected_positions, color=color, thickness=thickness)