Skip to content

Commit

Permalink
Update requirements.txt, camera_view.py, INSTALL.md, http_server.py, …
Browse files Browse the repository at this point in the history
….github/workflows/build.yaml, README.md, and docs/vmix.md files
  • Loading branch information
royshil committed Apr 25, 2024
1 parent b58e583 commit 590f52b
Show file tree
Hide file tree
Showing 16 changed files with 173 additions and 21 deletions.
21 changes: 10 additions & 11 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,16 @@ jobs:
brew install tesseract
pip install --no-binary tesserocr tesserocr
# - name: Install pyinstaller for Windows
# if: matrix.os == 'windows-latest'
# # $env:PYINSTALLER_COMPILE_BOOTLOADER="True"
# run: |
# Invoke-WebRequest -Uri https://github.com/pyinstaller/pyinstaller/archive/refs/tags/v6.5.0.zip -OutFile pyinstaller-6.5.0.zip
# Expand-Archive -Path pyinstaller-6.5.0.zip -DestinationPath .
# cd pyinstaller-6.5.0
# python -m pip install .
# cd ..
# Remove-Item -Recurse -Force pyinstaller-6.5.0
# Remove-Item -Force pyinstaller-6.5.0.zip
- name: Install pyinstaller for Windows
if: matrix.os == 'windows-latest'
run: |
Invoke-WebRequest -Uri https://github.com/pyinstaller/pyinstaller/archive/refs/tags/v6.6.0.zip -OutFile pyinstaller-6.6.0.zip
Expand-Archive -Path pyinstaller-6.6.0.zip -DestinationPath .
cd pyinstaller-6.6.0
python -m pip install .
cd ..
Remove-Item -Recurse -Force pyinstaller-6.6.0
Remove-Item -Force pyinstaller-6.6.0.zip
- name: Install dependencies
run: |
Expand Down
8 changes: 8 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ To install on Windows, simply click the .zip file and then the .exe setup instal

Once the setup is complete, ScoreSight will be available as an application.

If you get an error of a virus (which is a false alarm) like so

![alt text](docs/image-14.png)

Make sure to disable real-time protection

![alt text](docs/image-15.png)

## Mac OS

On Mac OS ScoreSight comes as packaged .app application which doesn't need installation.
Expand Down
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ See the [releases](https://github.com/occ-ai/scoresight/releases) page for downl

See the [Install Guide](INSTALL.md) for help with installation.

## Build from Source
## Running and Building from Source

### Prerequisites

Expand Down Expand Up @@ -54,16 +54,41 @@ There are some extra steps for installation on Windows:
- Download and install https://visualstudio.microsoft.com/visual-cpp-build-tools/ C++ Build Tools
- Build the win32DeviceEnum pyd by `$ cd win32DeviceEnum && python.exe setup.py build_ext --inplace`

## Usage
### Running from source

1. Launch the application:
1. Once everything is installed launch the application:

```shell
python main.py
```

2. Follow the on-screen instructions to load an image of the scoreboard and extract the text.

### Build an executable

You may want to build a distributable .exe or .app or even an installer, this is possible with [PyInstaller](https://github.com/pyinstaller/pyinstaller).

To build the executable run PyInstaller.

#### MacOS

```
pyinstaller --clean --noconfirm scoresight.spec -- --mac_osx
```

#### Windows

```
pyinstaller --clean --noconfirm scoresight.spec -- --win
```

#### Linux

```
pyinstaller --clean --noconfirm scoresight.spec
```


## Contributing

Contributions are welcome! If you would like to contribute to this project, please follow these steps:
Expand Down
2 changes: 1 addition & 1 deletion camera_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
QGraphicsScene,
QGraphicsPixmapItem,
)
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QImage, QPixmap, QPainter
from PyQt6.QtCore import QThread, pyqtSignal
import cv2
Expand Down
81 changes: 81 additions & 0 deletions docs/http_server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Using the ScoreSight HTTP Server

Get your scoreboard information in the browser for a simple integration into many streaming software, like OBS.

This feature is only available on ScoreSight Pro.

To get started, set up your scoreboard with the information you want to extract. See the Setup Process Guide for instructions.

Enable the HTTP Server from the bottom-right section of ScoreSight: "Start HTTP Server"

You can then open any browser and enter "http://localhost:18099/scoresight" as the URL. A simple scoreboard will appear. You may now use this URL in your streaming software.

All the scoreboard information will be delivered as JSON in http://localhost:18099/json . This can be used as API in any other software or even HTML pages.

If you want to create a more customized HTML scoreboard you are able to do so. Create a ".html" file anywhere on your disk and use the template example below to fetch data automatically from ScoreSight into the browser.

Here is a simple HTML example that uses the JSON output:

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scoreboard</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
.scoreboard { display: flex; justify-content: normal; align-items: center; margin-top: 20px; }
.team { width: 25%; }
.info { background: #f0f0f0; padding: 20px; border-radius: 10px; }
.team-name { font-size: 24px; margin-bottom: 10px; }
.score { font-size: 48px; margin-bottom: 10px; }
.timer { font-size: 78px; margin: 0 20px; }
.fouls { font-size: 24px; }
</style>
</head>
<body>
<script>
function updateScoreboard() {
fetch('http://localhost:18099/json')
.then(response => response.json())
.then(data => {
const homeScore = data.find(item => item.name === 'Home Score').text;
const awayScore = data.find(item => item.name === 'Away Score').text;
const time = data.find(item => item.name === 'Time').text;
const homeFouls = data.find(item => item.name === 'Home Fouls').text;
const awayFouls = data.find(item => item.name === 'Away Fouls').text;
document.querySelector('.team.home .score').textContent = homeScore;
document.querySelector('.team.away .score').textContent = awayScore;
document.querySelector('.timer').textContent = time;
document.querySelector('.team.home .fouls').textContent = `Fouls: ${homeFouls}`;
document.querySelector('.team.away .fouls').textContent = `Fouls: ${awayFouls}`;
})
.catch(error => console.error('Error:', error));
}
setInterval(updateScoreboard, 100);
</script>

<div class="scoreboard">
<div class="team home">
<div class="info">
<div class="team-name">Home Team</div>
<div class="score">0</div>
<div class="fouls">Fouls: 0</div>
</div>
</div>
<div class="timer">00:00</div>
<div class="team away">
<div class="info">
<div class="team-name">Away Team</div>
<div class="score">0</div>
<div class="fouls">Fouls: 0</div>
</div>
</div>
</div>

</body>
</html>
```
Binary file added docs/image-10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions docs/vmix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# vMix Integration

ScoreSight can interact directly with vMix through an API, providing a smooth and fast connection to vMix scoreboard Titles. Here is how to get it up and running.

First make sure vMix is accepting connections. This can be verified in the vMix Settings -> Web Controller screen. (Enable the TCP API option)

![alt text](image-8.png)

In a vMix input add a Title that fits your needs, for example this scoreboard (which is available in vMix):

![alt text](image-9.png)

Right click and open the Title Editor:

![alt text](image-10.png)

Note the names of the various texts in the Title, these would be controlled by ScoreSight.

In ScoreSight setup your scoreboard with detection boxes:

![alt text](image-11.png)

Go on the vMix tab and update or inspect the connection information like host and port (8099 is the vMix default), and choose the vMix Input according to your vMix setup. Next, set the mapping between ScoreSight detections and the vMix Title texts according to the information in the Title Editor (seen above).

![alt text](image-12.png)

Make sure the mappings are exactly as they appear in the Title Editor.

Once the mapping is complete the information will be updated on vMix automatically.

![alt text](image-13.png)

Consult the vMix guide on their API for reference: vMix User Guide

ScoreSight will be sending information using the SetText function.
11 changes: 7 additions & 4 deletions http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,13 @@ async def shutdown():

def stop_http_server():
logger.info("Stopping server...")
conn = http.client.HTTPConnection("localhost", PORT)
conn.request("GET", "/shutdown")
conn.close()
logger.info("Server stopped")
try:
conn = http.client.HTTPConnection("localhost", PORT)
conn.request("GET", "/shutdown")
conn.close()
logger.info("Server stopped")
except Exception as e:
pass


def update_http_server(results: list[TextDetectionTargetWithResult]):
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ obsws-python
opencv-python
pillow
platformdirs
pyinstaller
pyqt6
pyinstaller==6.6.0
pyqt6==6.6.1
PyQt6-Qt6==6.7.0
python-dotenv
requests
tesserocr
Expand Down

0 comments on commit 590f52b

Please sign in to comment.