Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d1fcec9
Remove asserts and docstrings for smaller build
Avasam Jun 11, 2025
fd9fe7e
Try out arm64 builds
Avasam Jun 11, 2025
208770c
Add --no-sync to all embed `uv run` commands
Avasam Jun 11, 2025
b363ee7
Update scripts/lint.ps1
Avasam Jun 11, 2025
33d7602
Merge branch 'main' into Try-out-arm64-builds
Avasam Jun 11, 2025
0820796
Forgot 1
Avasam Jun 11, 2025
0e8379f
Merge branch 'Try-out-arm64-builds' of https://github.com/Toufool/Aut…
Avasam Jun 11, 2025
54be122
missed another
Avasam Jun 11, 2025
0e7e112
missed in workflow file
Avasam Jun 11, 2025
b17f10b
Set no-sync through CI env
Avasam Jun 11, 2025
27575e0
Try to get uv to use Arm64 Python
Avasam Jun 12, 2025
4066bae
Fix typo
Avasam Jun 12, 2025
13f1af7
Fix dev deps
Avasam Jun 12, 2025
82fd1e6
Update lock file
Avasam Jun 12, 2025
493c752
Bump PySide6-Essentials to >=6.9.0
Avasam Jun 12, 2025
a1df793
Resolve pkg_resources warning spam during build
Avasam Jun 12, 2025
380f105
Fallback to cv2.img_hash when scipy can't be found
Avasam Jun 12, 2025
3103b13
Add aarch64 check
Avasam Jun 12, 2025
7ebb7e2
Bump numpy
Avasam Jun 12, 2025
3214e57
Fix pyright
Avasam Jun 12, 2025
281d8c8
Bump + auto resolution for PySide6-Essentials
Avasam Jun 12, 2025
fa23837
Update docs
Avasam Jun 12, 2025
1e4d716
simplify tool.uv.sources
Avasam Jun 12, 2025
2ae50b8
don't install uv-secure with dev deps
Avasam Jun 12, 2025
b8426f9
Ensure both opencv aren't installed at the same time
Avasam Jun 13, 2025
729fdef
Merge branch 'main' of https://github.com/Toufool/AutoSplit into Try-…
Avasam Jun 13, 2025
c7099c6
fix opencv install
Avasam Jun 13, 2025
dd5ad3a
Fix typo
Avasam Jun 13, 2025
667b93d
update marker for opencv-python-headless
Avasam Jun 13, 2025
6fdfc52
windows as well
Avasam Jun 13, 2025
6e86944
Run uv sync
Avasam Jun 13, 2025
757492d
Stop trying to build windows on arm
Avasam Jun 13, 2025
62d3acd
Run uv sync
Avasam Jun 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug-or-crash-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ If AutoSplit showed an exception traceback, please paste it here:
### Version (please complete the following information)

- OS: [e.g. Windows 10.0.19045]
- Architecture: [x64 or ARM64]
- AutoSplit: [e.g. v2.0.0]

### AutoSplit Profile and Split Images
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/lint-and-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@ jobs:
fail-fast: false
# Only the Python version we plan on shipping matters.
matrix:
os: [windows-latest, ubuntu-22.04]
# OpenCV doesn't support windows-11-arm yet https://github.com/opencv/opencv-python/issues/806
os: [windows-latest, ubuntu-22.04, ubuntu-22.04-arm]
python-version: ["3.13"]
steps:
- uses: actions/checkout@v4
# region https://github.com/pyinstaller/pyinstaller/issues/9012
- name: Set up Python for PyInstaller tk issue
# region pyinstaller/pyinstaller#9012 + astral-sh/uv#12906
- name: Set up Python for PyInstaller tk and ARM64 issue
if: ${{ startsWith(matrix.os, 'ubuntu') }}
uses: actions/setup-python@v5
with:
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ To understand how to use AutoSplit and how it works in-depth, please read the [t

### Compatibility

- Windows 10 and 11.
- Windows 10 and 11. (x64 only)
- Linux (still in early development)
- Should work on Ubuntu 20.04+ (Only tested on Ubuntu 22.04)
- Both x64 and ARM64 architectures \* (see [Known Limitations](#known-limitations) for ARM64)
- Should work on Ubuntu 22.04+
- Wayland is not currently supported
- WSL2/WSLg requires an additional Desktop Environment, external X11 server, and/or systemd
- If you'd like to run the project directly in Python from the source code, refer to the [build instructions](/docs/build%20instructions.md).
Expand All @@ -73,6 +74,7 @@ See the [installation instructions](https://github.com/Toufool/LiveSplit.AutoSpl
- Linux support is incomplete and we're [looking for contributors](../../issues?q=is%3Aissue+is%3Aopen+label%3A"help+wanted"+label%3ALinux+).
- Incompatible with LiveSplitOne on Linux (see <https://github.com/LiveSplit/LiveSplitOne/issues/1025>)
- Antivirus false positives. Please read <https://github.com/pyinstaller/pyinstaller/blob/develop/.github/ISSUE_TEMPLATE/antivirus.md>
- The Perceptual Hash Comparison Method similarity may differ by 3.125% on ARM64. (this will be solved eventually, we have to use a fallback method for now)

## Resources

Expand Down
15 changes: 10 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ dependencies = [
"PyAutoGUI >=0.9.52",
"PyWinCtl >=0.0.42", # py.typed
"keyboard @ git+https://github.com/boppreh/keyboard.git", # Fix install on macos and linux-ci https://github.com/boppreh/keyboard/pull/568
"numpy >=2.1", # Python 3.13 support
"opencv-python-headless >=4.10", # NumPy 2 support
"numpy >=2.3", # Windows ARM64 wheels
"packaging >=20.0", # py.typed
# When needed, dev builds can be found at https://download.qt.io/snapshots/ci/pyside/dev?C=M;O=D
"PySide6-Essentials <6.8.1", # Has typing issue with QMessageBox.warning https://bugreports.qt.io/browse/PYSIDE-2939
# "PySide6-Essentials >=6.8.2", # Fixed typing issue with QMessageBox.warning
"scipy >=1.14.1", # Python 3.13 support
"PySide6-Essentials", # Let package resolution find the minimum for wheels (>=6.9.0 on Windows ARM64; <6.8.1 on ubuntu-22.04-arm (glibc 2.39))
"tomli-w >=1.1.0", # Typing fixes

# scipy is used for pHash calculation as a smaller, but still fast implementation.
# However, scipy is not available on all environments yet.
# In those cases, we're falling back to opencv-contrib-python's cv2.img_hash
"opencv-contrib-python-headless >=4.10; platform_machine == 'aarch64'", # NumPy 2 support
"opencv-python-headless >=4.10; platform_machine != 'aarch64'", # NumPy 2 support
"scipy >=1.14.1; platform_machine != 'aarch64'", # Python 3.13 support

#
# Build and compile resources
"pyinstaller >=6.14.0", # Mitigate issues with pkg_resources deprecation warning
Expand Down Expand Up @@ -55,6 +59,7 @@ dev = [
"ruff >=0.11.13",
#
# Types
"opencv-contrib-python-headless",
"scipy-stubs >=1.14.1.1",
"types-PyAutoGUI",
"types-PyScreeze; sys_platform == 'linux'",
Expand Down
62 changes: 35 additions & 27 deletions src/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import Levenshtein
import numpy as np
from cv2.typing import MatLike
from scipy import fft

from utils import (
BGRA_CHANNEL_COUNT,
Expand Down Expand Up @@ -90,27 +89,40 @@ def compare_template(source: MatLike, capture: MatLike, mask: MatLike | None = N
return 1 - (min_val / max_error)


def __cv2_phash(image: MatLike, hash_size: int = 8, highfreq_factor: int = 4):
"""Implementation copied from https://github.com/JohannesBuchner/imagehash/blob/38005924fe9be17cfed145bbc6d83b09ef8be025/imagehash/__init__.py#L260 .""" # noqa: E501
# OpenCV has its own pHash comparison implementation in `cv2.img_hash`,
# but it requires contrib/extra modules and is inaccurate
# unless we precompute the size with a specific interpolation.
# See: https://github.com/opencv/opencv_contrib/issues/3295#issuecomment-1172878684
#
# pHash = cv2.img_hash.PHash.create()
# source = cv2.resize(source, (8, 8), interpolation=cv2.INTER_AREA)
# capture = cv2.resize(capture, (8, 8), interpolation=cv2.INTER_AREA)
# source_hash = pHash.compute(source)
# capture_hash = pHash.compute(capture)
# hash_diff = pHash.compare(source_hash, capture_hash)

img_size = hash_size * highfreq_factor
image = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)
image = cv2.resize(image, (img_size, img_size), interpolation=cv2.INTER_AREA)
dct = fft.dct(fft.dct(image, axis=0), axis=1)
dct_low_frequency = dct[:hash_size, :hash_size]
median = np.median(dct_low_frequency)
return dct_low_frequency > median
try:
from scipy import fft

def __cv2_scipy_compute_phash(image: MatLike, hash_size: int, highfreq_factor: int = 4):
"""Implementation copied from https://github.com/JohannesBuchner/imagehash/blob/38005924fe9be17cfed145bbc6d83b09ef8be025/imagehash/__init__.py#L260 .""" # noqa: E501
img_size = hash_size * highfreq_factor
image = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)
image = cv2.resize(image, (img_size, img_size), interpolation=cv2.INTER_AREA)
dct = fft.dct(fft.dct(image, axis=0), axis=1)
dct_low_frequency = dct[:hash_size, :hash_size]
median = np.median(dct_low_frequency)
return dct_low_frequency > median

def __cv2_phash(source: MatLike, capture: MatLike, hash_size: int = 8): # pyright: ignore[reportRedeclaration]
source_hash = __cv2_scipy_compute_phash(source, hash_size)
capture_hash = __cv2_scipy_compute_phash(capture, hash_size)
hash_diff = np.count_nonzero(source_hash != capture_hash)
return 1 - (hash_diff / 64.0)

except ModuleNotFoundError:

def __cv2_phash(source: MatLike, capture: MatLike, hash_size: int = 8):
# OpenCV has its own pHash comparison implementation in `cv2.img_hash`,
# but it requires contrib/extra modules and is inaccurate
# unless we precompute the size with a specific interpolation.
# See: https://github.com/opencv/opencv_contrib/issues/3295#issuecomment-1172878684
#
phash = cv2.img_hash.PHash.create()
source = cv2.resize(source, (hash_size, hash_size), interpolation=cv2.INTER_AREA)
capture = cv2.resize(capture, (hash_size, hash_size), interpolation=cv2.INTER_AREA)
source_hash = phash.compute(source)
capture_hash = phash.compute(capture)
hash_diff = phash.compare(source_hash, capture_hash)
return 1 - (hash_diff / 64.0)


def compare_phash(source: MatLike, capture: MatLike, mask: MatLike | None = None):
Expand All @@ -130,11 +142,7 @@ def compare_phash(source: MatLike, capture: MatLike, mask: MatLike | None = None
source = cv2.bitwise_and(source, source, mask=mask)
capture = cv2.bitwise_and(capture, capture, mask=mask)

source_hash = __cv2_phash(source)
capture_hash = __cv2_phash(capture)
hash_diff = np.count_nonzero(source_hash != capture_hash)

return 1 - (hash_diff / 64.0)
return __cv2_phash(source, capture)


def extract_and_compare_text(capture: MatLike, texts: Iterable[str], methods_index: Iterable[int]):
Expand Down
Loading