From b6ef14b5594fa845f52c7451f8612a7935517aeb Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Wed, 26 Feb 2025 03:36:59 -0700 Subject: [PATCH] Successfully implemented multi-core OCR functionality. --- .../data_collector.cpython-312.pyc | Bin 14019 -> 16876 bytes Modules/data_collector.py | 138 +++++++++++++----- .../identification_overlay.cpython-312.pyc | Bin 4961 -> 5078 bytes .../General Purpose/identification_overlay.py | 46 +++--- Workflows/Testing/Identification_Overlay.json | 57 ++++++++ 5 files changed, 176 insertions(+), 65 deletions(-) create mode 100644 Workflows/Testing/Identification_Overlay.json diff --git a/Modules/__pycache__/data_collector.cpython-312.pyc b/Modules/__pycache__/data_collector.cpython-312.pyc index 254d7f928eae3ddf785027ef3c88fe819f16cf93..09dbaf9757998301c21c1da94a6ee0410cab47ff 100644 GIT binary patch delta 5590 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 E2SpFVd;kCd delta 3329 zcmbtWeQZX|)Oh ztf`1r)Nwjd&*?=2XMg}>s)$iEaVF8snX_|sq(HQA7SYOCMH^=m?VMe7aE`2xjueVc z&M6jgMPe~mEV?)s1QZaM!8Ig$W!5ESwUJ60}OvIjSy-E=Y939U(% z*9v)q#;m=h>K7@vYVHlqF$g!!H8ZOq?3oMZPpDw;+TXa(@A&`6`KcL znp^=`=i`S&{G6o$I1W&!&WD~Y)1%ww&6Gw)m)BNyLZE2&sR2mjC748hLaXE{41V%Q z@iJ^_iSAct8M=f%VMrJigQ7cF3_zS#jEWvj7FeMMohfK3)G2!GGxn>`tIk2Z43C6K zF`>T|I9&;Iq96nk7KP^32WtS3?#Km86o6jz*)@uZr)4u*Z!bY1i>>0kCfA9CRW5o! z1hOk-96y2mgIA7SWMGW1K^C!C69uoBIbS$EhKD*GB7iYluM6*X@d z#ji3ubFQ5At8-~W@ckdDfnwqP152t0{%GR<<>5}hjO-=rtspUX!%(bopNW}@SOnznA!J8ECDR7#~r366; zm-`Ih%?a=G-rlV4e%?C*N5B!)GhhVz3PwNBvUuzolEY$nRN&eE;b>3}$D*tpV|hUq zf-*Z2lX!M077r6V&W59G0Da6BCZ)g#8xKl?5M}v*9AHPn@<41@W``tUNQwo8csv{p zvHdZL6$3}uAwj~X7>EXi#_XPbaUss`#VkPz;9Y7q?(XxknA{zRAKkU_+icAi0`S6+ z5amfAoYOGovT-4TvkJ%Xsq?Y54gIUIiT&MXQqiFd z9gw8JQ8eRpI5YX(M}h(_HWu}jNey^aMor2?hl=c0jTn$Z;b=x13rc<=icJAc>x;HY z{g@|(2$`0`p#eFgc`hc)F;VgpOdG?XevJ;T2xV+fkM0tha+#}KM(YY+f^`0Qo>LCQ(XEB;JzN|OFQXB4X`-S zuF`L*>uAeuG+pXQVyL|4XSFl6X~r|Io!D`!$Te=frL#}jKhTxlww7ME)~BuYslNI4 zo!2ROnd6k%=!gS za}LRySvOmdE^k@zwB{gYX8o);UEaFjX`9%3%T{*X=1bdrsWr0$>ALk-m_MvZclOTr z?Vk^X<_8a^0|(Q6k@@K1MF74FyC|$SQQg#CGV7+2SjXUIg4S)Jz5u|!m0C0bN8{pZ zU@o0!-1oh}S$zD+qh@mHGO3C-J@CwnIPrn+a6J=1-u?%TK>ZKp<;>U(IU+Gf@* zc$yx-%d`Kl;ztX1ELCg;6?Kb_rHa42sk0%!r|ijA{QbPE`KE7ME%@!Ku12hW=jkfJ z>h~R84Om^R&EIZNU2QRKXH@S~5ZmuF^mYUKrRO7f0KLK+iwIwdd=xOh>+E;P7 zx5y{C2Thf?8@y@8JMByL&2GEKtVcJ?t6>LHS3Id52S*^6-wS+sb9*Yna4!!O;Md`G z*^!++I5hDeC5?TCobTbkfTDSstTN?1_`(4E=G-g*@C2Hyc5B|nQQ{ZS#p+SB%QLRN#yD?y%84$y zff{SP=s=ANoo~vgcEh=`n%%JaC^$>?WX~U;RwAiNMi(t1Y@_cqR=`{6g~rury6Ml9bPmbQ6)=TPH1DMDfVsakpMZ65 zlMqZW7L^0xXgs6Br<3$LiSuJDaxvc|z!0-k zN%V5N+j)`TWN}6<#tsXlJc7K5-fKUo`6o8xWvI2|m}y#?8opt5PBp*s4Pv4{b@Y7| zn`>Uz1fdr3>noEdNRXcsK`N6-+R|kru40if`2E31ARZ42k%-^#gVI@y#z~5u61j^> z^*Qky;_zbe 1: + strip_height = self.height() // self.num_slices + pen.setColor(QColor(150, 150, 150, 100)) # Light gray, semi-transparent + pen.setWidth(1) + painter.setPen(pen) + + for i in range(1, self.num_slices): # Do not draw the last one at the bottom + painter.drawLine(0, i * strip_height, self.width(), i * strip_height) + def set_draw_positions(self, positions, color, thickness): """ Updates the overlay positions and visual settings. @@ -230,6 +261,27 @@ class OCRRegionWidget(QWidget): self.line_thickness = thickness self.update() + def update_draw_positions(self, positions, color, thickness): + """ + Updates the overlay positions and redraws only if the positions have changed. + This prevents unnecessary flickering. + """ + if positions == self.previous_positions: + return # No change, do not update + + self.previous_positions = positions # Store last known positions + self.draw_positions = positions + self.box_color = QColor(*color) + self.line_thickness = thickness + self.update() # Redraw only if needed + + def set_num_slices(self, num_slices): + """ + Updates the number of horizontal slices for visualization. + """ + self.num_slices = num_slices + self.update() + def _resize_handles(self): w, h = self.width(), self.height() return [ @@ -254,19 +306,23 @@ class OCRRegionWidget(QWidget): 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 + 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 + 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()] + regions[self.region_id]["bbox"] = [self.x(), self.y(), self.width(), self.height()] collector_mutex.unlock() self.update() @@ -277,5 +333,7 @@ class OCRRegionWidget(QWidget): collector_mutex.lock() if self.region_id in regions: - regions[self.region_id]['bbox'] = [new_x, new_y, self.width(), self.height()] + regions[self.region_id]["bbox"] = [new_x, new_y, self.width(), self.height()] collector_mutex.unlock() + + diff --git a/Nodes/General Purpose/__pycache__/identification_overlay.cpython-312.pyc b/Nodes/General Purpose/__pycache__/identification_overlay.cpython-312.pyc index 2970cf3023833664de7cfae10a2ed65750baac25..ec927062a04fa745e6a83af3316b91ea2d437e0e 100644 GIT binary patch delta 1703 zcmZ`(Uu;uV7(b`C?M`p+y)9#1*LE#;W9!z8Q1IW%-wl;cMr=X=BY%=>?Y)djX`6Fz z86&M=!UIkcg!6*&#Ta8Cn-Q}IF)_MktX|;n(l` zo!|Ms^PTg3{Uvy#OZr|Ec|gD4{`_i4mCi~zxc}@)dHrr(!@8V^r{zQ@eIPlM!P6(cjG4Opg-Tz~+OU3{10Y3fxhx)H}lh{F*w%CEAnXR==M zCEqKBsj2U#Z~~OwKEl~`yN!CR*1I2a;9Oj#_y-U z1#6+f28@Op13;dus|tub5Zrd#l5ZoQ2yM_teiU53$6_t1c(&`1eaWXsGaU8ks_>so zOPcz53c?e$OSLR%#XQvE2r!nBese4NLUg-e-kNX7qr5pUjxE+xkjVSuvu?4z3sQak zEN`?BMGPI6@_b$xm&VLB9)c0D5*XF)WK0LZh;~my{jT9MfHfZZ!@V$e#y zll+72%=A+DgS|ZNpb#?QP@N5lcoVaGDO9+_@ht9RmPOB|k_PUt+D0y$((q=o))838 z`mEBF%c^lhQ?NFa%%m3wqvBCp&O@`8Jn!5jmjmsyfp94hF0SdH32dQ*_cI&D&Jyapj=JW}1sLen{joXiq0eQweu;6$Q@_!_&iC?nnX7lcJpE;p?h-O5P$A?Yo*ct*D|())0`uk7)T4l>gBkG_}Q z+*DWl)(E)5+oJ-w($yUefU9j=UC}VO+Upts;M<54wQwiYJ4Hi{vxX#huOnbL`6xY;<}#DQYl3VLA;JV9&6YB z+Vdi&XTUmK_fxoc5|mwiCt_u1_la!_W}l_|&iV#R&)tc99S_20&}2!!TKtM!|((27pNMT1^XA- CiKYzz delta 1650 zcmZWpOKclO7@omDz9(uFqapXO3c|yU0=XjQYyaQz}MdrkzpEjB4nv zuBC0uLTT5=YTk6mRb4%2<&bJmB5dhX+oS>Y7;@>kLoYb4o=H0$RNj={c|0Du~3E=V1v<4Z0<-XW^@>vj7}qNY`(3MZ@6LD zMFRZiuzO*ihY+@sk6`P4u}a<4Dap2oD%&)XdOu|L3;nW-d#!Npr*0U2_6qnlBgON!{93H;9|* zn>bFvtUv%p68>^<47pks+gXI&sWL}?5hIP;sY2ODQ;6LJhxd>*F)8n3H+NH*-a(`2 zA}6ILWsq*2w<%l#s{&}-M9xc&EYLkie`}8$$iG4#3Ckwr$Sl8!d?^o*>$2EC*FcZy zdWU|CzM@|QZlKBlP~hgMV{8=zWKfRELVYigJ;5$cI4_dz4K3t`ERe}y6BL=&L8-1K zQEQD=3ji4MbC&BmwfBp10XlFhM1;`ZCSSo{2o(4^fAwxLNKS=z?+g~if_ytX$5&Yh zrb0cy^?IB!F9Iw;VEAj1oCY_3B!|Ntfj}`p<)1xSEQ(bAl*u!}qDV&&PK4q0f3456wqv?6X&j4fE z+3abifif-~%Cyd0)Xv!#k&_6~7D_kvlUt3w$Jrz0aDAjS7hQBcU&_t3FtvJwPKavP zhQa${uMKyRc4a_0Ko6bwX$W5TMLWnF%0Xq-55&*|p?6v6{Y}`i>L>Gxsz{s|{Ug$L zv*XuD@0H`L5_zcXfD&nG>YI5Y0Hvc8Y_9l0Jo%t=Xt{H!6jVMOxjJ(5@< zcW2hPhPbpO#3~XHqYs3^Wnu76%UALF_|lQrm(ISsWaaJ)lg}zgAW&jY0Tla6UA@b} z_>~hMkFRocyIu)yoJ32J)@#QZ8C|c0DLKRR)l$pmYbnO6RhE&lQd|4AVMfOOaZb=s z@3wXy8w7Xv%PAgw-`bywfO|?L)dzkU45uKs2p~gVPBn9jO^{(kPW5n$-H>6QoZ7`L z?t~N*Vp-6%j6Q)htxT>r@7CFWlUHoKi%R8?rll?2ani`LG%W$~UY2OqDu=7-XA_PY zDD0qum9;j$+z|IwwHW)i1(AO7mU~Tvs (255,0,0) + color = tuple(map(int, color_text.split(","))) except ValueError: - color = (0, 0, 255) # Default to blue if invalid input + color = (0, 0, 255) - # Parse thickness thickness_text = self.get_property("thickness") try: - thickness = max(1, int(thickness_text)) # Ensure at least 1px thickness + thickness = max(1, int(thickness_text)) except ValueError: - thickness = 2 # Default thickness + thickness = 2 + + try: + num_slices = max(1, int(threads_slices_text)) # Ensure at least 1 slice + except ValueError: + num_slices = 1 if not search_term: return - # Get detected word positions using the selected OCR engine detected_positions = data_collector.find_word_positions( - self.region_id, search_term, offset_x, offset_y, margin, ocr_engine + self.region_id, search_term, offset_x, offset_y, margin, ocr_engine, num_slices ) - # Draw detected word boxes with custom color & thickness + # Ensure slice count is updated visually in the region widget + data_collector.update_region_slices(self.region_id, num_slices) + data_collector.draw_identification_boxes(self.region_id, detected_positions, color=color, thickness=thickness) + diff --git a/Workflows/Testing/Identification_Overlay.json b/Workflows/Testing/Identification_Overlay.json new file mode 100644 index 0000000..834a649 --- /dev/null +++ b/Workflows/Testing/Identification_Overlay.json @@ -0,0 +1,57 @@ +{ + "graph":{ + "layout_direction":0, + "acyclic":true, + "pipe_collision":false, + "pipe_slicing":true, + "pipe_style":1, + "accept_connection_types":{}, + "reject_connection_types":{} + }, + "nodes":{ + "0x20c129abb30":{ + "type_":"bunny-lab.io.identification_overlay_node.IdentificationOverlayNode", + "icon":null, + "name":"Identification Overlay", + "color":[ + 13, + 18, + 23, + 255 + ], + "border_color":[ + 74, + 84, + 85, + 255 + ], + "text_color":[ + 255, + 255, + 255, + 180 + ], + "disabled":false, + "selected":false, + "visible":true, + "width":271.0, + "height":330.40000000000003, + "pos":[ + 44.64929777820301, + 256.49596595988965 + ], + "layout_direction":0, + "port_deletion_allowed":false, + "subgraph_session":{}, + "custom":{ + "search_term":"Aibatt", + "offset_value":"-10,-10", + "margin":"10", + "polling_freq":"50", + "ocr_engine":"GPU", + "overlay_color":"255,255,255", + "thickness":"5" + } + } + } +} \ No newline at end of file