From 0515f8feebfe0d0d15511e60253285d2d8afa7d0 Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Wed, 26 Feb 2025 01:57:47 -0700 Subject: [PATCH] Enabled GPU Acceleration for Identification Node. --- Installation Requirements.txt | 5 ++ .../data_collector.cpython-312.pyc | Bin 13762 -> 14564 bytes Modules/data_collector.py | 66 +++++++++++------- .../identification_overlay.cpython-312.pyc | Bin 3995 -> 4179 bytes .../General Purpose/identification_overlay.py | 18 +++-- 5 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 Installation Requirements.txt diff --git a/Installation Requirements.txt b/Installation Requirements.txt new file mode 100644 index 0000000..94ef1d6 --- /dev/null +++ b/Installation Requirements.txt @@ -0,0 +1,5 @@ +We need to run the following commands to install the prerequisites for the project. + + +This command is used to install pytorch and torchvision for the purposes of GPU-accelerated vision tasks. +pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 diff --git a/Modules/__pycache__/data_collector.cpython-312.pyc b/Modules/__pycache__/data_collector.cpython-312.pyc index f99d78d41f91fdbad54aa5b13dcd4e5eefd81f24..107d0944c578b79ecfebb370ae1ad1b1545a2489 100644 GIT binary patch delta 4331 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 diff --git a/Modules/data_collector.py b/Modules/data_collector.py index 5f9df55..0f598df 100644 --- a/Modules/data_collector.py +++ b/Modules/data_collector.py @@ -6,13 +6,22 @@ import re import sys import numpy as np import cv2 + +# Vision-related Imports import pytesseract +import easyocr +import torch + from PIL import Image, ImageGrab, ImageFilter from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import QRect, QPoint, Qt, QMutex, QTimer from PyQt5.QtGui import QPainter, QPen, QColor, QFont +# Initialize EasyOCR with CUDA support +reader_cpu = easyocr.Reader(['en'], gpu=False) +reader_gpu = easyocr.Reader(['en'], gpu=True if torch.cuda.is_available() else False) + pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe" DEFAULT_WIDTH = 180 @@ -29,11 +38,11 @@ app_instance = None def _ensure_qapplication(): """ Ensures that QApplication is initialized before creating widgets. + Must be called from the main thread. """ global app_instance - if QApplication.instance() is None: - app_instance = QApplication(sys.argv) - threading.Thread(target=app_instance.exec_, daemon=True).start() + if app_instance is None: + 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)): @@ -102,11 +111,11 @@ def _preprocess_image(image): return thresh.filter(ImageFilter.MedianFilter(3)) -def find_word_positions(region_id, word, offset_x=0, offset_y=0, margin=5): +def find_word_positions(region_id, word, offset_x=0, offset_y=0, margin=5, ocr_engine="CPU"): """ Finds positions of a specific word within the OCR region. Applies user-defined offset and margin adjustments. - Returns a list of bounding box coordinates relative to the OCR box. + Uses Tesseract (CPU) or EasyOCR (GPU) depending on the selected engine. """ collector_mutex.lock() if region_id not in regions: @@ -136,28 +145,36 @@ def find_word_positions(region_id, word, offset_x=0, offset_y=0, margin=5): scale_x = orig_width / proc_width scale_y = orig_height / proc_height - data = pytesseract.image_to_data(processed, config='--psm 6 --oem 1', output_type=pytesseract.Output.DICT) - word_positions = [] - for i in range(len(data['text'])): - if re.search(rf"\b{word}\b", data['text'][i], re.IGNORECASE): - # Scale the detected coordinates back to region-relative positions - x_scaled = int(data['left'][i] * scale_x) - y_scaled = int(data['top'][i] * scale_y) - w_scaled = int(data['width'][i] * scale_x) - h_scaled = int(data['height'][i] * scale_y) - # Apply user-configured margin - x_margin = max(0, x_scaled - margin) - y_margin = max(0, y_scaled - margin) - w_margin = w_scaled + (margin * 2) - h_margin = h_scaled + (margin * 2) + if ocr_engine == "CPU": + # Use Tesseract (CPU) + data = pytesseract.image_to_data(processed, config='--psm 6 --oem 1', output_type=pytesseract.Output.DICT) - # Apply user-configured offset - x_final = x_margin + offset_x - y_final = y_margin + offset_y + for i in range(len(data['text'])): + if re.search(rf"\b{word}\b", data['text'][i], re.IGNORECASE): + x_scaled = int(data['left'][i] * scale_x) + y_scaled = int(data['top'][i] * scale_y) + w_scaled = int(data['width'][i] * scale_x) + h_scaled = int(data['height'][i] * scale_y) - word_positions.append((x_final, y_final, w_margin, h_margin)) + word_positions.append((x_scaled + offset_x, y_scaled + offset_y, w_scaled + (margin * 2), h_scaled + (margin * 2))) + + else: + # Use EasyOCR (GPU) - Convert PIL image to NumPy array + image_np = np.array(processed) + results = reader_gpu.readtext(image_np) + + for (bbox, text, _) in results: + if re.search(rf"\b{word}\b", text, re.IGNORECASE): + (x_min, y_min), (x_max, y_max) = bbox[0], bbox[2] + + x_scaled = int(x_min * scale_x) + y_scaled = int(y_min * scale_y) + w_scaled = int((x_max - x_min) * scale_x) + h_scaled = int((y_max - y_min) * scale_y) + + word_positions.append((x_scaled + offset_x, y_scaled + offset_y, w_scaled + (margin * 2), h_scaled + (margin * 2))) return word_positions except Exception as e: @@ -165,9 +182,6 @@ def find_word_positions(region_id, word, offset_x=0, offset_y=0, margin=5): return [] - - - def draw_identification_boxes(region_id, positions, color=(0, 0, 255)): """ Draws non-interactive rectangles at specified positions within the given OCR region. diff --git a/Nodes/General Purpose/__pycache__/identification_overlay.cpython-312.pyc b/Nodes/General Purpose/__pycache__/identification_overlay.cpython-312.pyc index 8fbc8dd0ce6dceebd89d397eede6ae2c9749d523..681be49ec0bcdd97f04baea83b80522c2d24443a 100644 GIT binary patch delta 1432 zcmYjRO>7%Q6rS;V*R#9!#;)TePEy-7Z4$Rp>ZCtOqzWjO2mzWl{Xw)K7ULbK+uB|; zyJ_plRtxH(NJu4`OAs7-Kq$yTwCaH#5ES)BFNsoUv{E@$NZeWyP$dp9v#ASncz*NV z_r3S_y*K_Wxth}MhC&Kp2mk#2%n!kNtqZ<7-@mWd2PS|aT?R$~3r&Fo062wez6_e% zn7{JVD^;shGAlEwBEj#^;!2@5n95g-l#NTc;G_=cj;3&B#;o8W<#$e<%0L&rl(+Ge zWniXD)5py+CK*Vt!xi`@{m^&UUk7JodczluYet(9HX<{=r7f-05HPRGz5SXIZu)pk z03a};b)ZX|HvpWrmUbpgA1N^y&33r{ z>bSBb?CPR*4Go-wV8ZW=_SO>qSJ>969K(smYTE=|L}cz8(H&5G&hdX(903DTR= z*~}UW-bXzvsAu8z#lBmy+u|*48TH&l6P_c!g5nErbTbk797+*JCEfHk%C-$M zl@;jZiIWk?F#QJ&N_)6FONZrAxQm+d4t3-Ud-1?(|JZ7BoPH`FRrz=E9a{el(r*HN zv{#v+2bFgEwIcf(e)_I*XjE)9y*1mn*^C=vLz00LU{vqag%+w2s6!jp5PhhOM#Q>Q z57hmw*)|Z}sqPy_hP}6^Ok~IHO$bRm~GT{p4e3guGO|+{e(;?&BC2~Ww zXjTmUyhRMXYT2g4MrV@&Y6X)QWirfRJd>+h#UdZGgD*I)TFw*plDrGyLv+zo_l0L# z&8y4ZVqk|oKm5Pww#*o*)*;@gb~Dr5z@&jIj#)Gdd0qxh_*8mWMj`7QCZ&9Blws^A zv_CW&UW>)=$NE-ceb?%%vAtIm`c7zi|5`A7b?T$3h1V9lu8-Y%lD}Ogs`Ggpd6q e^sj3GDi1*F0Z2Xo=?!TT!qe~?`V)AH7wKR9-)oWp delta 1253 zcmYLIO>7%Q6rS<^?|S`%lQeOg*hxW&^W&6+PyrF37=c=7R7VKZP*^RQjl1sJ>&|Y7 zH*%ndp7;@pMx3aC69PH6a%rVjv^{VrNUm~;R*E>HN>l$f8&)p0Pa7ELjU~otk3tO}k>@TqKMl(>INZS*0;dK8E+9OwLE{rBSQ_44$Q8 z%hx&@fO3>FJiv;CX%g@m@;;wp$MXTm^^xoR7IB58I7^y~hl00O zvoKajOBjkO*ecm>)vytkNWVA(1@gN1tvF1n8zbbFo{k%aUA29~U}boFfMlhM*M5+$ zLXp+|0Fk$p6Y)_BX^LO1U@@To;kM~^1OO_AdA zI;eB!z&gySvXP8p)3=6PZhFrz0;b#~UyqaVCc#ehG z-NMwWT}8&ai;+=tJ=>=Z_waF&*E283c#_fBA))53u6mYl_*UHywTg*LcC};32a$T% zMFFkmGrd2>W-@!QaJ%K>(ctp zV7(=$_eJt`EDeXrjo9pnFtRWYZjWh&1h_LFE9l(aC}c9B6^6LGgRn3};_<>oHXH3L z<8fBCZWt?$>3J)b;}{0*%oIDCjrYr)f)vJQBEbTKRQ!7d?DoENd2u%}cKOsk-y@9u zHK_^{|MU+D7a*SQ@^evgGoJk@el{rjbNQnGwv9@b?_u^s!)VuAaIuBi5QNeh7p*y# zhuKGLcfNh>_n?!KbtjbPD{az?c!`>