diff --git a/coin.py b/coin.py
new file mode 100755
index 0000000..2deab1e
--- /dev/null
+++ b/coin.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+############################################################
+### Project: coin
+### File: __init__.py
+### Description: main file of coin
+### Version: 1.0
+############################################################
+import sys, os, glob
+import PyQt6
+import gui
+import tess
+
+def main():
+ model_names = tess.get_tess_model_names()
+
+ if len(model_names) == 0:
+ print("[ERR] No tesseract model found at", MODELS_PATH, file=sys.stderr)
+ sys.exit(1)
+
+ print("Available models:\n", model_names)
+
+ app = PyQt6.QtWidgets.QApplication(sys.argv)
+ main_window = gui.coin_gui(model_names)
+ main_window.show()
+ sys.exit(app.exec())
+
+if __name__ == '__main__':
+ main()
diff --git a/constants.py b/constants.py
new file mode 100644
index 0000000..d91c755
--- /dev/null
+++ b/constants.py
@@ -0,0 +1,55 @@
+############################################################
+### Project: coin
+### File: constants.py
+### Description: defines all the constants
+### Version: 1.0
+############################################################
+# Change this if tesseract or coin can't find any data
+MODELS_PATH = '/usr/share/tessdata/'
+
+# Sane values for scaling
+SCALE_MIN = 0.2
+SCALE_MAX = 5.0
+SCALE_DEFAULT = 1.0
+# How much (in decimal) to change the scale for every degree
+SCALE_DELTA = 8 * 360 * 1
+
+# Sane values for text recognition
+WIDTH_MIN = 10
+HEIGHT_MIN = 10
+
+# Table info
+TABLE_COL_CNT = 5
+TABLE_COL_GET = 0
+TABLE_COL_DEL = 1
+TABLE_COL_UPC = 2
+TABLE_COL_NAME = 3
+TABLE_COL_PRICE = 4
+TABLE_HEADERS = [" Get ", " Del ", "UPC", "Item Name", "Price"]
+
+# Cookies for upc.py
+COOKIE_DICT_LIST = [
+ {
+ "name": "PHPSESSID",
+ "value": "9n1ic479r1bteiv758gm9hk65p",
+ "path": "/",
+ "domain": "stocktrack.ca"
+ },
+ {
+ "name": "cf_chl_3",
+ "value": "1d706187484b25c",
+ "path": "/",
+ "domain": "stocktrack.ca"
+ },
+ {
+ "name": "cf_clearance",
+ "value": "Wp8tAMUKLdS3a4Y9AT09BIlZKx4x120uC1QzBQTUluQ-1710517775-1.0.1.1-hMEP8oeggZHBkylkwkQfi2p57H6zUUvGG40d_M4vGqOqg2Zh7wZsg6KrGl3XkDUn3mXAqyZrTqlQfd5pgHCZWQ",
+ "path": "/",
+ "domain": "stocktrack.ca"
+ },
+ {
+ "name": "fp",
+ "value": "26f4acb9b23415f921bba6977b68d55f",
+ "path": "/",
+ "domain": "stocktrack.ca"
+ }]
diff --git a/gui.py b/gui.py
index e4b98e6..8346165 100644
--- a/gui.py
+++ b/gui.py
@@ -1,5 +1,9 @@
-# This module handles the GUI of coin
-import pytesseract
+############################################################
+### Project: coin
+### File: gui.py
+### Description: handles the GUI of coin
+### Version: 1.0
+############################################################
import cv2, os, sys
from PIL import Image
import PyQt6
@@ -9,161 +13,86 @@ from PyQt6.QtWidgets import *
from PyQt6 import uic
from PyQt6 import QtCore, QtGui, QtWidgets
import glob
-import upc
-from upc import get_name_from_upc
-
-# [!!!] Change this if tesseract or coin can't find any data
-MODELS_PATH = '/usr/share/tessdata/'
-
-# [!!!] Sane values for scaling
-SCALE_MIN = 0.3
-SCALE_MAX = 4.0
-# How much (in decimal) to change the scale for every degree
-SCALE_DELTA = 8 * 360 * 1
-
-# [!!!] Sane values for recognition
-WIDTH_MIN = 10
-HEIGHT_MIN = 10
-
-# Column Information
-TABLE_COL_CNT = 5
-TABLE_COL_GET = 0
-TABLE_COL_DEL = 1
-TABLE_COL_UPC = 2
-TABLE_COL_NAME = 3
-TABLE_COL_PRICE = 4
-
-# Automatically finds all available language models
-models_list = glob.glob(MODELS_PATH + "*.traineddata")
-model_names = []
-for path in models_list:
- base_name = os.path.basename(path)
- base_name = os.path.splitext(base_name)[0]
- model_names.append(base_name)
-if len(model_names) == 0:
- print("No tesseract models found at", MODELS_PATH, "!", file=sys.stderr)
- sys.exit(0)
+from upc import *
+from constants import *
+import tess
class UPCWorker(QObject):
finished = pyqtSignal()
update_name = pyqtSignal(list)
-
- def __init__(self, upcList):
- super().__init__()
- self.upcList = upcList
+ # requires: upc_list is a list of list of two elements with the
+ # first element being the UPC's row number and the second being a
+ # string, containing the UPC
+ def __init__(self, upc_lst):
+ super().__init__()
+ self.upc_lst = upc_lst
+
+ # get_items_name(): get the names of all items using
+ # get_name_from_upc from the list of upc_list. Emits a pair of
+ # values stored in a list, the first element is the row number
+ # and the second is the item's name
def get_items_name(self):
- for upc in self.upcList:
+ for upc in self.upc_lst:
name = get_name_from_upc(upc[1])
self.update_name.emit([upc[0], name])
self.finished.emit()
-class coin_app(QtWidgets.QMainWindow):
- def __init__(self):
+class coin_gui(QtWidgets.QMainWindow):
+ # requires: model_names must be valid and not empty
+ def __init__(self, model_names):
+ print("Initializing GUI...")
+
QtWidgets.QMainWindow.__init__(self)
self.ui = uic.loadUi('coin.ui', self)
- self.image = None
- self.ui.openButton.clicked.connect(self.open)
+ self.ui.openButton.clicked.connect(self.open_image)
self.ui.getNameButton.clicked.connect(self.get_all)
self.ui.saveFileButton.clicked.connect(self.save_file)
self.ui.saveDbButton.clicked.connect(self.save_database)
- self.rubberBand = QRubberBand(QRubberBand.Shape.Rectangle, self)
+ self.rubber_band = QRubberBand(QRubberBand.Shape.Rectangle, self)
self.ui.photo.setMouseTracking(True)
self.ui.photo.installEventFilter(self)
self.ui.photo.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignTop)
-
- self.model = model_names[0]
- print("Model selected as:", self.model)
- self.models.addItems(model_names)
- self.models.currentTextChanged.connect(self.update_now)
- self.models.setCurrentIndex(model_names.index(self.model))
-
+ self.image = None
self.scale = 1.0
self.items = None
- self.upcCheckTimer = QTimer(self)
- self.upcCheckTimer.timeout.connect(self.pushUPCToThread)
- self.upcCheckTimer.start(1500)
+ if len(model_names) == 0:
+ print("[ERR] No tesseract model given to coin_gui!", file=sys.stderr)
+ sys.exit(1)
+ self.model_names = model_names
+ self.update_model(self.model_names[0])
+ self.models.addItems(self.model_names)
+ self.models.currentTextChanged.connect(self.update_model)
+ self.models.setCurrentIndex(self.model_names.index(self.model))
+
+ self.upc_chk_timer = QTimer(self)
+ self.upc_chk_timer.timeout.connect(self.push_upc_to_thread)
+ self.upc_chk_timer.start(1500)
print("Initialized timer!")
- self.upcThread = QThread()
- self.upcWorker = None
- self.upcCheckList = []
+ self.upc_thread = None
+ self.upc_worker = None
+ self.upc_chk_lst = []
- def pushUPCToThread(self):
- if len(self.upcCheckList) > 0 and self.upcWorker is None:
- self.upcWorker = UPCWorker(self.upcCheckList)
- self.upcWorker.moveToThread(self.upcThread)
-
- self.upcWorker.update_name.connect(self.updateItemName)
- self.upcWorker.finished.connect(self.collectUPCWorker)
- self.upcThread.finished.connect(self.collectUPCThread)
-
- self.upcThread.started.connect(self.upcWorker.get_items_name)
- self.upcThread.start()
-
- print("Lookup thread started!")
-
- self.upcCheckList = []
-
- def collectUPCWorker(self):
- self.upcWorker.deleteLater()
- self.upcWorker = None
-
- def collectUPCThread(self):
- self.upcThread.deleteLater()
-
- def updateItemName(self, name):
- itemName = QStandardItem(name[1])
- itemName.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
- self.items.setItem(name[0], TABLE_COL_NAME, itemName)
- self.itemsTable.resizeColumnToContents(TABLE_COL_NAME)
- self.itemsTable.resizeRowToContents(name[0])
-
- def update_now(self, value):
- self.model = value
- print("Model selected as:", self.model)
-
- def set_table_header(self):
- item = QStandardItem(" Get ")
- item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
- item.setEditable(False)
- self.items.setItem(0, TABLE_COL_GET, item)
- item = QStandardItem(" Del ")
- item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
- item.setEditable(False)
- self.items.setItem(0, TABLE_COL_DEL, item)
- item = QStandardItem("UPC")
- item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
- item.setEditable(False)
- self.items.setItem(0, TABLE_COL_UPC, item)
- item = QStandardItem("Item Name")
- item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
- item.setEditable(False)
- self.items.setItem(0, TABLE_COL_NAME, item)
- item = QStandardItem("Price")
- item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
- item.setEditable(False)
- self.items.setItem(0, TABLE_COL_PRICE, item)
- self.itemsTable.resizeColumnsToContents()
-
- def open(self):
+ # open_image(): prompts to open an image, if an error occurrs, the
+ # image within the photo view will not be updated, otherwise, the
+ # image will be updated and stored in self.pixmap
+ def open_image(self):
filename = QFileDialog.getOpenFileName(self, 'Select File')
if filename[0] == "":
print("No file was selected or opened!")
return None
- if self.items is not None:
- self.items.deleteLater()
-
print("Opening file: ", filename[0])
self.image = cv2.imread(str(filename[0]))
if self.image is None:
print("Error: image is empty!", file=sys.stderr)
+ print("No file was opened!")
return None
frame = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
@@ -171,11 +100,12 @@ class coin_app(QtWidgets.QMainWindow):
frame.strides[0], QImage.Format.Format_RGB888)
self.pixmap = QPixmap.fromImage(image)
- self.ui.photo.setPixmap(self.pixmap)
- self.scale = 1.0
- print("Updated photo!")
- print("Photo scale set to:", self.scale)
+ self.scale = SCALE_DEFAULT
+ self.update_scale()
+ if self.items is not None:
+ self.items.deleteLater()
+
self.items = QStandardItemModel()
self.itemsTable.setModel(self.items)
self.items.setColumnCount(TABLE_COL_CNT)
@@ -187,6 +117,8 @@ class coin_app(QtWidgets.QMainWindow):
return None
+ # save_file(): prompt to save a file, will write to the file in
+ # .csv format
def save_file(self):
filename = QFileDialog.getSaveFileName(self, 'Select File')
@@ -203,53 +135,107 @@ class coin_app(QtWidgets.QMainWindow):
print(name, file=out, end=", ")
print(self.items.item(i,TABLE_COL_PRICE).text().replace("\n", " "),
file=out)
- out.close()
+ out.close()
self.statusBar().showMessage("Saved to: " + filename[0])
+ # save_database(): saves to a database
def save_database(self):
print("Not implemented!")
- def scale_update(self):
+ # set_table_header(): sets the headers of the table when a new
+ # image is opened
+ def set_table_header(self):
+ for i in range(TABLE_COL_CNT):
+ item = QStandardItem(TABLE_HEADERS[i])
+ item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
+ item.setEditable(False)
+ self.items.setItem(0, i, item)
+
+ self.itemsTable.resizeColumnsToContents()
+
+ # update_scale(): update the image with the new scale
+ def update_scale(self):
self.ui.photo.setPixmap(self.pixmap.scaled(
int(self.scale * self.pixmap.width()),
int(self.scale * self.pixmap.height())))
- print("Photo scale set to:", self.scale)
+ print("Photo scale set to:", self.scale)
self.statusBar().showMessage("Photo scale set to: " + str(self.scale))
- def image_to_text(self, cropped_image):
- gray = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2GRAY)
- gray = cv2.medianBlur(gray, 1)
- crop = Image.fromarray(gray)
- text = pytesseract.image_to_string(crop, lang=self.model).strip()
- print("Text selected:", text)
- return text
+ # push_upc_to_thread(): runs a new thread when there are items in
+ # self.upc_chk_lst and self.upc_thread is available
+ def push_upc_to_thread(self):
+ if len(self.upc_chk_lst) > 0 and self.upc_worker is None:
+ self.upc_thread = QThread()
+
+ self.upc_worker = UPCWorker(self.upc_chk_lst)
+ self.upc_worker.moveToThread(self.upc_thread)
- def get_row(self):
- button = self.sender()
- row = self.itemsTable.indexAt(button.pos()).row()
- upc = self.items.item(row, TABLE_COL_UPC).text()
- self.upcCheckList.append([row, upc])
- print("Started getting name of UPC:", upc)
- self.statusBar().showMessage("Started getting name of UPC: " + upc)
- self.pushUPCToThread()
+ self.upc_worker.update_name.connect(self.update_item_name)
+ self.upc_worker.finished.connect(self.upc_thread.quit)
+ self.upc_worker.finished.connect(self.delete_upc_worker)
+ self.upc_thread.finished.connect(self.delete_upc_thread)
+ self.upc_thread.started.connect(self.upc_worker.get_items_name)
+ self.upc_thread.start()
+
+ print("Lookup thread started!")
+
+ self.upc_chk_lst = []
+
+ # delete_upc_worker(): wrapper for self.upc_worker.deleteLater()
+ def delete_upc_worker(self):
+ self.upc_worker.deleteLater()
+ self.upc_worker = None
+
+ # delete_upc_thread(): wrapper for self.upc_thread.deleteLater()
+ def delete_upc_thread(self):
+ print("Lookup thread is finished!")
+ self.upc_thread.deleteLater()
+
+ # update_item_name(name): name is a two-element list with the
+ # first element being the row in which is item is located, and
+ # the second being a string containing the item's name
+ def update_item_name(self, name):
+ item = QStandardItem(name[1])
+ item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
+ self.items.setItem(name[0], TABLE_COL_NAME, item)
+ self.itemsTable.resizeColumnToContents(TABLE_COL_NAME)
+ self.itemsTable.resizeRowToContents(name[0])
+
+ # get_all(): get the names of items in every row that doesn't have
+ # a name in it
def get_all(self):
for i in range(1, self.items.rowCount()):
- if self.items.item(i, TABLE_COL_NAME) is None or self.items.item(i, TABLE_COL_NAME).text() == "N/A":
+ if (self.items.item(i, TABLE_COL_NAME) is None or
+ self.items.item(i, TABLE_COL_NAME).text() == "N/A"):
upc = self.items.item(i, TABLE_COL_UPC).text()
print("Started getting name of UPC:", upc)
self.statusBar().showMessage("Started getting name of UPC: " + upc)
- self.upcCheckList.append([i, upc])
- self.pushUPCToThread()
+ self.upc_chk_lst.append([i, upc])
+ self.push_upc_to_thread()
+ # get_item_at_row(): get the name of the item at the row where the
+ # "Get" button was clicked
+ def get_item_at_row(self):
+ button = self.sender()
+ row = self.itemsTable.indexAt(button.pos()).row()
+ upc = self.items.item(row, TABLE_COL_UPC).text()
+ self.upc_chk_lst.append([row, upc])
+ print("Started getting name of UPC:", upc)
+ self.statusBar().showMessage("Started getting name of UPC: " + upc)
+ self.push_upc_to_thread()
+
+ # del_row(): delete the row where the "Del" button was clicked
def del_row(self):
button = self.sender()
index = self.itemsTable.indexAt(button.pos())
self.items.removeRow(index.row())
print("Removed row", index.row())
+ self.statusBar().showMessage("Removed row " + str(index.row()))
+ # populate_buttons(): put buttons on the table when creating a new row
def populate_buttons(self):
del_button = QPushButton("Del")
self.itemsTable.setIndexWidget(
@@ -261,17 +247,22 @@ class coin_app(QtWidgets.QMainWindow):
self.itemsTable.setIndexWidget(
self.items.index(self.items.rowCount() - 1, TABLE_COL_GET),
get_button)
- get_button.clicked.connect(self.get_row)
+ get_button.clicked.connect(self.get_item_at_row)
+ # update_model(): update self.model to the one selected
+ def update_model(self, value):
+ self.model = value
+ print("Model selected as:", self.model)
+
+ # add_upc(text): adds a new row containing text in the UPC column
def add_upc(self, text: str):
if text == "":
print("No text was recognized, will not add a new item!")
return None
- self.statusBar().showMessage("Text selected: " + text)
+
item = QStandardItem(text)
item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.items.setItem(self.items.rowCount(), TABLE_COL_UPC, item)
-
item = QStandardItem("N/A")
item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.items.setItem(self.items.rowCount() - 1, TABLE_COL_NAME, item)
@@ -280,69 +271,92 @@ class coin_app(QtWidgets.QMainWindow):
self.items.setItem(self.items.rowCount() - 1, TABLE_COL_PRICE, item)
self.populate_buttons()
+
self.itemsTable.resizeColumnToContents(TABLE_COL_UPC)
return None
+ # eventFilter(source, event): handles a few things differently
def eventFilter(self, source, event):
- # Handling the selection box
- if event.type() == QEvent.Type.MouseButtonPress and source is self.ui.photo:
- self.org = self.mapFromGlobal(event.globalPosition())
- self.top_left = event.position()
- self.rubberBand.setGeometry(QRect(self.org.toPoint(), QSize()))
- self.rubberBand.show()
+ if (event.type() == QEvent.Type.MouseButtonPress and
+ source is self.ui.photo):
+ self.rubber_band_show(event)
return True
- elif event.type() == QEvent.Type.MouseMove and source is self.ui.photo:
- if self.rubberBand.isVisible():
- pos = self.mapFromGlobal(event.globalPosition()).toPoint()
- pos = QPoint(int(max(pos.x(), 0)),
- int(max(pos.y(), 0)))
- self.rubberBand.setGeometry(
- QRect(self.org.toPoint(),
- pos).normalized())
- return True
-
- elif event.type() == QEvent.Type.MouseButtonRelease and source is self.ui.photo:
- pos = event.position()
- self.top_left = QPoint(int(max(min(pos.x(), self.top_left.x()), 0)),
- int(max(min(pos.y(), self.top_left.y()), 0)))
- if self.rubberBand.isVisible():
- self.rubberBand.hide()
- rect = self.rubberBand.geometry()
- self.x1 = int(self.top_left.x() / self.scale)
- self.y1 = int(self.top_left.y() / self.scale)
- width = rect.width() / self.scale
- height = rect.height() / self.scale
- self.x2 = int(self.x1 + width)
- self.y2 = int(self.y1 + height)
- else:
- return False
- if width >= WIDTH_MIN and height >= HEIGHT_MIN and self.image is not None:
- print("Cropped image:", self.x1, self.y1, self.x2, self.y2)
- self.crop = self.image[self.y1:self.y2, self.x1:self.x2]
- # cv2.imwrite("cropped.png", self.crop)
- self.text = self.image_to_text(self.crop)
- self.add_upc(self.text)
- ##self.ui.textEdit()
- return True
-
- # Resizing the photo
- elif event.type() == QEvent.Type.Wheel and self.image is not None and source is self.ui.photo:
- modifiers = QApplication.keyboardModifiers()
- if modifiers == Qt.KeyboardModifier.ControlModifier:
- self.scale = self.scale + event.angleDelta().y() / SCALE_DELTA
- if self.scale < SCALE_MIN:
- self.scale = SCALE_MIN
- if self.scale > SCALE_MAX:
- self.scale = SCALE_MAX
- self.scale_update()
- return True
- elif event.type() == QEvent.Type.MouseButtonDblClick and source is self.ui.photo:
- self.open()
+ elif (event.type() == QEvent.Type.MouseMove and
+ source is self.ui.photo and self.rubber_band.isVisible()):
+ self.rubber_band_redraw(event)
return True
+
+ elif (event.type() == QEvent.Type.MouseButtonRelease and
+ source is self.ui.photo and self.rubber_band.isVisible()):
+ return self.rubber_band_select(event)
+
+ elif (event.type() == QEvent.Type.Wheel and
+ self.image is not None and source is self.ui.photo and
+ QApplication.keyboardModifiers() ==
+ Qt.KeyboardModifier.ControlModifier):
+ self.image_resize(event)
+ return True
+
+ elif (event.type() == QEvent.Type.MouseButtonDblClick and
+ source is self.ui.photo):
+ self.open_image()
+ return True
+
return False
-app = QtWidgets.QApplication(sys.argv)
-mainWindow = coin_app()
-mainWindow.show()
-sys.exit(app.exec())
+ # rubber_band_show(event): shows the rubber band for selection
+ def rubber_band_show(self, event):
+ self.org = self.mapFromGlobal(event.globalPosition())
+ self.top_left = event.position()
+ self.rubber_band.setGeometry(QRect(self.org.toPoint(), QSize()))
+ self.rubber_band.show()
+
+ # rubber_band_redraw(event): resizes the rubber band for selection
+ def rubber_band_redraw(self, event):
+ pos = self.mapFromGlobal(event.globalPosition()).toPoint()
+ pos = QPoint(int(max(pos.x(), 0)),
+ int(max(pos.y(), 0)))
+ self.rubber_band.setGeometry(
+ QRect(self.org.toPoint(),
+ pos).normalized())
+
+ # rubber_band_select(event): processes the rubber band for selection
+ def rubber_band_select(self, event):
+ pos = event.position()
+ self.top_left = QPoint(int(max(min(pos.x(), self.top_left.x()), 0)),
+ int(max(min(pos.y(), self.top_left.y()), 0)))
+
+ self.rubber_band.hide()
+ rect = self.rubber_band.geometry()
+ self.x1 = int(self.top_left.x() / self.scale)
+ self.y1 = int(self.top_left.y() / self.scale)
+ width = rect.width() / self.scale
+ height = rect.height() / self.scale
+ self.x2 = int(self.x1 + width)
+ self.y2 = int(self.y1 + height)
+
+ if (width >= WIDTH_MIN and height >= HEIGHT_MIN and
+ self.image is not None):
+ print("Cropped image:", self.x1, self.y1, self.x2, self.y2)
+ crop = self.image[self.y1:self.y2, self.x1:self.x2]
+
+ text = tess.image_to_text(self.model, crop)
+ print("Text selected:", text)
+ self.statusBar().showMessage("Text selected: " + text)
+ self.add_upc(text)
+ return True
+
+ return False
+
+ # image_resize(event): resize the image when scrolling with Ctrl
+ def image_resize(self, event):
+ self.scale = self.scale + event.angleDelta().y() / SCALE_DELTA
+
+ if self.scale < SCALE_MIN:
+ self.scale = SCALE_MIN
+
+ if self.scale > SCALE_MAX:
+ self.scale = SCALE_MAX
+
+ self.update_scale()
diff --git a/tess.py b/tess.py
new file mode 100644
index 0000000..707cfcd
--- /dev/null
+++ b/tess.py
@@ -0,0 +1,31 @@
+############################################################
+### Project: coin
+### File: tess.py
+### Description: handles all pytesseract-related operations
+### Version: 1.0
+############################################################
+import sys, os, glob
+import cv2
+from PIL import Image
+import pytesseract
+from constants import *
+
+# get_tess_model_names(models_path): automatically finds all available
+# language models in models_path
+def get_tess_model_names(models_path=MODELS_PATH):
+ models_list = glob.glob(models_path + "*.traineddata")
+ model_names = []
+ for path in models_list:
+ base_name = os.path.basename(path)
+ base_name = os.path.splitext(base_name)[0]
+ model_names.append(base_name)
+ return model_names
+
+# image_to_text(model, cropped_image): use the model with the name
+# model to try to recognize the text in cropped_image
+def image_to_text(model, cropped_image):
+ gray = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2GRAY)
+ gray = cv2.medianBlur(gray, 1)
+ crop = Image.fromarray(gray)
+ text = pytesseract.image_to_string(crop, lang=model).strip()
+ return text
diff --git a/upc.py b/upc.py
index 5c9826a..986a50f 100644
--- a/upc.py
+++ b/upc.py
@@ -1,10 +1,18 @@
+############################################################
+### Project: coin
+### File: upc.py
+### Description: scapes the item's name by using the its UPC
+### Version: 1.0
+############################################################
import time
from seleniumbase import Driver
-# from selenium import webdriver
+from constants import *
driver = Driver(uc=True)
driver.implicitly_wait(5)
+# get_name_from_upc(upc, wait_interval, max_tries): will try to get
+# the item's name from stocktrack.ca.
def get_name_from_upc(upc: str, wait_interval=1, max_tries=30) -> str:
url = "https://stocktrack.ca/wm/index.php?s=wm&upc=" + upc
driver.get(url)
@@ -13,59 +21,39 @@ def get_name_from_upc(upc: str, wait_interval=1, max_tries=30) -> str:
print("Removed leading 0's:", upc)
- # Change the cookies here to match that of yours when you lookup
- # any item on stocktrack.ca to bypass the Cloudflare checks
- driver.add_cookie({
- "name": "PHPSESSID",
- "value": "9n1ic479r1bteiv758gm9hk65p",
- "path": "/",
- "domain": "stocktrack.ca"
- })
- driver.add_cookie({
- "name": "cf_chl_3",
- "value": "1d706187484b25c",
- "path": "/",
- "domain": "stocktrack.ca"
- })
- driver.add_cookie({
- "name": "cf_clearance",
- "value": "Wp8tAMUKLdS3a4Y9AT09BIlZKx4x120uC1QzBQTUluQ-1710517775-1.0.1.1-hMEP8oeggZHBkylkwkQfi2p57H6zUUvGG40d_M4vGqOqg2Zh7wZsg6KrGl3XkDUn3mXAqyZrTqlQfd5pgHCZWQ",
- "path": "/",
- "domain": "stocktrack.ca"
- })
- driver.add_cookie({
- "name": "fp",
- "value": "26f4acb9b23415f921bba6977b68d55f",
- "path": "/",
- "domain": "stocktrack.ca"
- })
+ for cookie in COOKIE_DICT_LIST:
+ driver.add_cookie(cookie)
driver.refresh()
name = ""
- str_s = "target=\"_blank\">"
- str_t = "
UPC: " + upc + "
"
- str_tt = "
SKU:"
- times = 0
- while times < max_tries:
- if __debug__:
- print("Iteration No. ", times)
+ pattern_front = "target=\"_blank\">"
+ pattern_back_upc = "
UPC: " + upc + "
"
+ pattern_back_sku = "
SKU:"
- times = times + 1
+ tries = 0
+
+ while tries < max_tries:
+ if __debug__:
+ print("Iteration No.", tries)
+
+ tries = tries + 1
time.sleep(wait_interval)
page = str(driver.execute_script(
"return document.getElementsByTagName('html')[0].innerHTML"))
- t = page.find(str_t)
- s = page.rfind(str_s, 0, t)
- tt = page.rfind(str_tt, 0, t)
+
+ back_upc_idx = page.find(pattern_back_upc)
+ front_idx = page.rfind(pattern_front, 0, back_upc_idx)
+ back_sku_idx = page.rfind(pattern_back_sku, 0, back_upc_idx)
if __debug__:
p = open("page.html", "w")
print(page, file=p)
- if t == -1 or s == -1:
+ if back_upc_idx == -1 or front_idx == -1:
continue
else:
- name = page[s + len(str_s) : tt]
+ name = page[front_idx + len(pattern_front) : back_sku_idx]
break
+
return name.replace(" ", "\n")