Skip to content

Commit

Permalink
Merge pull request #40 from locaal-ai/roy.move_sources
Browse files Browse the repository at this point in the history
Refactor: move source files to folder
  • Loading branch information
royshil authored Oct 2, 2024
2 parents 8c8f66c + 0f542a3 commit d6bc58d
Show file tree
Hide file tree
Showing 60 changed files with 114 additions and 151 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ jobs:
- name: Build device enumeration module on Windows
if: matrix.os == 'windows-latest'
run: |
cd win32DeviceEnum
cd src/win32DeviceEnum
python setup.py build_ext --inplace
cd ..
cd ../..
- name: Build with PyInstaller (MacOS)
if: matrix.os == 'macos-x86' || matrix.os == 'macos-arm64'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check-format.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ jobs:
run: pip install black

- name: Check formatting
run: black --check . --exclude '/ui_.*\.py'
run: black --check ./src --exclude '/ui_.*\.py'
13 changes: 11 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/locaal-ai/scoresight)](https://github.com/locaal-ai/scoresight/releases)
[![Discord](https://img.shields.io/discord/1200229425141252116)](https://discord.gg/8pG2tC923N)

ScoreSight is an OCR (Optical Character Recognition) application designed to extract text from real-time updating streams like scoreboards, applications, videos and games.
ScoreSight is an OCR (Optical Character Recognition) application designed to extract text from real-time updating streams like scoreboards, applications, videos and games. It is the best **free** real-time OCR tool on planet Earth for scoreboards and games.

It is the best **free** real-time OCR tool on planet Earth for scoreboards and games.
<center>

**Download**

[![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white)](https://github.com/locaal-ai/scoresight/releases/latest/download/scoresight-windows-0.0.14.zip)
[![macOS](https://img.shields.io/badge/mac%20x86-000000?style=for-the-badge&)](https://github.com/locaal-ai/scoresight/releases/download/0.0.14/scoresight-macos-x86-0.0.14.dmg)
[![macOS](https://img.shields.io/badge/mac%20M1/2/3-0a0a0a?style=for-the-badge&)](https://github.com/locaal-ai/scoresight/releases/download/0.0.14/scoresight-macos-arm64-0.0.14.dmg)
[![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://github.com/locaal-ai/scoresight/releases/latest/download/scoresight-linux-0.0.14.tar)

</center>

<center>
<a href="https://youtu.be/wMNolI0w0tE" target="_blank"><img src="./scoresight_getting_started.png" width="50%"/></a>
Expand Down
Binary file added icons/scoresight_logo_jf_blanco.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ python-dotenv
requests
tesserocr
uvicorn
websockets==9.1
82 changes: 42 additions & 40 deletions scoresight.spec
Original file line number Diff line number Diff line change
Expand Up @@ -49,58 +49,60 @@ datas = [
]

sources = [
'api_output.py',
'camera_info.py',
'camera_view.py',
'camera_thread.py',
'defaults.py',
'file_output.py',
'frame_stabilizer.py',
'get_camera_info.py',
'http_server.py',
'log_view.py',
'main.py',
'mainwindow.py',
'ndi.py',
'ocr_training_data.py',
'obs_websocket.py',
'resizable_rect.py',
'sc_logging.py',
'screen_capture_source.py',
'source_view.py',
'storage.py',
'tesseract.py',
'text_detection_target.py',
'training_dojo.py',
'video_settings.py',
'ui_about.py',
'ui_connect_obs.py',
'ui_log_view.py',
'ui_mainwindow.py',
'ui_ocr_training_data_dialog.py',
'ui_screen_capture.py',
'ui_training_dojo.py',
'ui_update_available.py',
'ui_url_source.py',
'ui_video_settings.py',
'update_check.py',
'vmix_output.py',
'src/api_output.py',
'src/camera_info.py',
'src/camera_view.py',
'src/camera_thread.py',
'src/defaults.py',
'src/file_output.py',
'src/frame_stabilizer.py',
'src/get_camera_info.py',
'src/http_server.py',
'src/log_view.py',
'src/main.py',
'src/mainwindow.py',
'src/ndi.py',
'src/ocr_training_data.py',
'src/obs_websocket.py',
'src/resizable_rect.py',
'src/resource_path.py',
'src/sc_logging.py',
'src/screen_capture_source.py',
'src/source_view.py',
'src/storage.py',
'src/tesseract.py',
'src/text_detection_target.py',
'src/training_dojo.py',
'src/video_settings.py',
'src/ui_about.py',
'src/ui_connect_obs.py',
'src/ui_log_view.py',
'src/ui_mainwindow.py',
'src/ui_ocr_training_data_dialog.py',
'src/ui_screen_capture.py',
'src/ui_training_dojo.py',
'src/ui_update_available.py',
'src/ui_url_source.py',
'src/ui_video_settings.py',
'src/update_check.py',
'src/vmix_output.py',
]

if args.win:
datas += [('win32DeviceEnum/win32DeviceEnumBind.cp311-win_amd64.pyd', './win32DeviceEnum')]
sources += ['win32DeviceEnum/enum_devices_dshow.py', 'screen_capture_source_windows.py']
datas += [('src/win32DeviceEnum/win32DeviceEnumBind.cp311-win_amd64.pyd', './src/win32DeviceEnum')]
sources += ['src/win32DeviceEnum/enum_devices_dshow.py', 'src/screen_capture_source_windows.py']
if args.mac_osx:
sources += ['screen_capture_source_mac.py']
sources += ['src/screen_capture_source_mac.py']

numpy_datas, numpy_binaries, numpy_hiddenimports = collect_all('numpy')
ws_hiddenimports=['websockets', 'websockets.legacy']

a = Analysis(
sources,
pathex=[],
binaries=numpy_binaries,
datas=datas + numpy_datas,
hiddenimports=numpy_hiddenimports,
hiddenimports=numpy_hiddenimports + ws_hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
Expand Down
2 changes: 1 addition & 1 deletion scripts/compile_ui.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Get-ChildItem -Filter *.ui | ForEach-Object {
Get-ChildItem -Filter src/*.ui | ForEach-Object {
$uiFile = $_.FullName
$pyFile = [System.IO.Path]::ChangeExtension($uiFile, ".py")
# add "ui_" prefix to the file name
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions camera_view.py → src/camera_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

class CameraView(QGraphicsView):
first_frame_received_signal = Signal()
error_signal = Signal(str)

def __init__(
self,
Expand Down Expand Up @@ -141,6 +142,7 @@ def error_event(self, error):
self.error_text.setPos(
0, self.height() - self.error_text.boundingRect().height() - 10
)
self.error_signal.emit(error)

def setFourCornersForHomography(self, corners: list[tuple[int]]):
if corners is None or len(corners) != 4:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion http_server.py → src/http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@

from text_detection_target import TextDetectionTargetWithResult
from sc_logging import logger, file_handler
from resource_path import resource_path

load_dotenv(os.path.abspath(os.path.join(os.path.dirname(__file__), ".env")))
load_dotenv(resource_path(".env"))

PORT = 18099
http_results = []
Expand Down
File renamed without changes.
File renamed without changes.
9 changes: 3 additions & 6 deletions main.py → src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
)

from mainwindow import MainWindow
from resource_path import resource_path
from sc_logging import logger
from http_server import stop_http_server

Expand All @@ -28,15 +29,11 @@

# Load the translation file based on the locale
translator = QTranslator()
locale_file = path.abspath(
path.join(path.dirname(__file__), "translations", f"scoresight_{locale}.qm")
)
locale_file = resource_path("translations", f"scoresight_{locale}.qm")
# check if the file exists
if not path.exists(locale_file):
# load the default translation file
locale_file = path.abspath(
path.join(path.dirname(__file__), "translations", "scoresight_en_US.qm")
)
locale_file = resource_path("translations", "scoresight_en_US.qm")
if translator.load(locale_file):
app.installTranslator(translator)

Expand Down
85 changes: 23 additions & 62 deletions mainwindow.py → src/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from get_camera_info import get_camera_info
from http_server import start_http_server, update_http_server
from ocr_training_data import OCRTrainingDataDialog
from resource_path import resource_path
from screen_capture_source import ScreenCapture
from source_view import ImageViewer
from defaults import (
Expand Down Expand Up @@ -102,13 +103,7 @@ def __init__(self, translator: QTranslator, parent: QObject):
self.setWindowTitle(f"ScoreSight - v{os.getenv('LOCAL_RELEASE_TAG')}")
if platform.system() == "Windows":
# set the icon
self.setWindowIcon(
QIcon(
path.abspath(
path.join(path.dirname(__file__), "icons/Windows-icon-open.ico")
)
)
)
self.setWindowIcon(QIcon(resource_path("icons", "Windows-icon-open.ico")))

self.menubar = self.menuBar()
file_menu = self.menubar.addMenu("File")
Expand Down Expand Up @@ -336,11 +331,7 @@ def __init__(self, translator: QTranslator, parent: QObject):

for box_name in [box["name"] for box in default_boxes] + custom_boxes_names:
item = QTableWidgetItem(
QIcon(
path.abspath(
path.join(path.dirname(__file__), "icons/circle-x.svg")
)
),
QIcon(resource_path("icons", "circle-x.svg")),
box_name,
)
item.setData(Qt.ItemDataRole.UserRole, "unchecked")
Expand Down Expand Up @@ -508,9 +499,7 @@ def changeEvent(self, event):
super().changeEvent(event)

def changeLanguage(self, locale):
locale_file = path.abspath(
path.join(path.dirname(__file__), "translations", f"scoresight_{locale}.qm")
)
locale_file = resource_path("translations", f"scoresight_{locale}.qm")
logger.info(f"Changing language to {locale_file}")
if not self.translator.load(locale_file):
logger.error(f"Could not load translation for {locale_file}")
Expand Down Expand Up @@ -848,25 +837,11 @@ def detectionTargetsChanged(self, detectionTargets):

if not box.settings["templatefield"]:
# this is a detection target
item.setIcon(
QIcon(
path.abspath(
path.join(path.dirname(__file__), "icons/circle-check.svg")
)
)
)
item.setIcon(QIcon(resource_path("icons", "circle-check.svg")))
item.setData(Qt.ItemDataRole.UserRole, "checked")
else:
# this is a template field
item.setIcon(
QIcon(
path.abspath(
path.join(
path.dirname(__file__), "icons/template-field.svg"
)
)
)
)
item.setIcon(QIcon(resource_path("icons", "template-field.svg")))
item.setData(Qt.ItemDataRole.UserRole, "templatefield")

self.updatevMixTable(detectionTargets)
Expand Down Expand Up @@ -1150,8 +1125,8 @@ def sourceChanged(self, index):
self.source_name = None
self.ui.groupBox_sb_info.setEnabled(False)
self.ui.tableWidget_boxes.setEnabled(False)
self.ui.pushButton_fourCorner.setEnabled(False)
self.ui.pushButton_binary.setEnabled(False)
self.ui.widget_viewTools.setEnabled(False)
self.ui.widget_cropPanel.setEnabled(False)
if self.ui.comboBox_camera_source.currentIndex() == 0:
self.reset_playing_source()
return
Expand Down Expand Up @@ -1308,29 +1283,30 @@ def sourceSelectionSucessful(self):
self.ui.toolButton_videoSettings.setEnabled(
camera_info.type == CameraInfo.CameraType.OPENCV
)
self.ui.pushButton_fourCorner.setEnabled(True)
self.ui.pushButton_binary.setEnabled(True)
self.ui.pushButton_fourCorner.toggled.connect(
self.image_viewer.toggleFourCorner
)
self.ui.pushButton_binary.clicked.connect(self.image_viewer.toggleBinary)
if self.image_viewer.timerThread:
self.image_viewer.timerThread.ocr_result_signal.connect(self.ocrResult)
self.image_viewer.timerThread.update_error.connect(self.updateError)
self.image_viewer.first_frame_received_signal.connect(
self.cameraConnectedEnableUI
)
self.image_viewer.error_signal.connect(self.updateError)
self.ocrModelChanged(fetch_data("scoresight.json", "ocr_model", 1))

# set the image viewer to the layout frame_for_source_view_label
self.ui.frame_for_source_view_label.layout().addWidget(self.image_viewer)

def cameraConnectedEnableUI(self):
self.ui.pushButton_fourCorner.toggled.connect(
self.image_viewer.toggleFourCorner
)
self.ui.pushButton_binary.clicked.connect(self.image_viewer.toggleBinary)
if self.image_viewer.timerThread:
self.image_viewer.timerThread.ocr_result_signal.connect(self.ocrResult)
self.image_viewer.timerThread.update_error.connect(self.updateError)

# enable groupBox_sb_info
self.ui.groupBox_sb_info.setEnabled(True)
self.ui.tableWidget_boxes.setEnabled(True)
self.ui.frame_source_view.setEnabled(True)
self.ui.widget_viewTools.setEnabled(True)
self.ui.widget_cropPanel.setEnabled(True)

# load the boxes from scoresight.json
self.detectionTargetsStorage.loadBoxesFromStorage()
Expand All @@ -1342,6 +1318,7 @@ def updateError(self, error):
logger.error(error)
self.ui.frame_source_view.setEnabled(True)
self.ui.widget_viewTools.setEnabled(False)
self.ui.widget_cropPanel.setEnabled(False)

def ocrResult(self, results: list[TextDetectionTargetWithResult]):
# update template fields
Expand Down Expand Up @@ -1468,9 +1445,7 @@ def addBox(self):

store_custom_box_name(new_box_name)
item = QTableWidgetItem(
QIcon(
path.abspath(path.join(path.dirname(__file__), "icons/circle-x.svg"))
),
QIcon(resource_path("icons", "circle-x.svg")),
new_box_name,
)
item.setData(Qt.ItemDataRole.UserRole, "unchecked")
Expand Down Expand Up @@ -1533,13 +1508,7 @@ def makeBox(self):
return
# create a new box on self.image_viewer with the name of the selected item from the tableWidget_boxes
# change the list icon to green checkmark
item.setIcon(
QIcon(
path.abspath(
path.join(path.dirname(__file__), "icons/circle-check.svg")
)
)
)
item.setIcon(QIcon(resource_path("icons/circle-check.svg")))
item.setData(Qt.ItemDataRole.UserRole, "checked")
self.listItemClicked(item)

Expand All @@ -1562,9 +1531,7 @@ def removeBox(self):
if not item:
return
# change the list icon to red x
item.setIcon(
QIcon(path.abspath(path.join(path.dirname(__file__), "icons/circle-x.svg")))
)
item.setIcon(QIcon(resource_path("icons", "circle-x.svg")))
item.setData(Qt.ItemDataRole.UserRole, "unchecked")
self.listItemClicked(item)
self.detectionTargetsStorage.remove_item(item.text())
Expand All @@ -1580,13 +1547,7 @@ def makeTemplateField(self, toggled: bool):

# create a new box on self.image_viewer with the name of the selected item from the tableWidget_boxes
# change the list icon to green checkmark
item.setIcon(
QIcon(
path.abspath(
path.join(path.dirname(__file__), "icons/template-field.svg")
)
)
)
item.setIcon(QIcon(resource_path("icons", "template-field.svg")))
item.setData(Qt.ItemDataRole.UserRole, "templatefield")

self.detectionTargetsStorage.add_item(
Expand Down
Loading

0 comments on commit d6bc58d

Please sign in to comment.