Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,7 @@ desktop.ini
others/

.claude/
.history/
.history/
settings.json
settings.*.json

11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@

“YORU” (Your Optimal Recognition Utility) is an open-source animal behavior recognition system using Python. YORU can detect animal behaviors, not only single-animal behaviors but also social behaviors. YORU also provides online/offline analysis and closed-loop manipulation.

## Versions

| Channel | Version | Notes |
|---------|---------|-------|
| **Latest Release** | [v1.1.1](https://github.com/Kamikouchi-lab/YORU/releases/tag/v1.1.1) | Stable release recommended for general use |
| **Latest Beta** | [v2.0.0-beta.1](https://github.com/Kamikouchi-lab/YORU/releases/tag/v2.0.0-beta.1) | Preview of the next major version — may contain bugs |

> To use the beta version, check out the corresponding tag:
> ```
> git checkout v2.0.0-beta.1
> ```

## Features

Expand Down
35 changes: 35 additions & 0 deletions libs/train_ultralytics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import argparse


def parse_args():
parser = argparse.ArgumentParser(description="Train YOLOv8/YOLO11 with Ultralytics")
parser.add_argument("--weights", type=str, default="yolov8s.pt", help="initial weights")
parser.add_argument("--data", type=str, required=True, help="path to dataset YAML")
parser.add_argument("--epochs", type=int, default=300)
parser.add_argument("--imgsz", type=int, default=640)
parser.add_argument("--batch", type=int, default=16)
parser.add_argument("--project", type=str, default="runs/train", help="output project dir")
parser.add_argument("--name", type=str, default="exp", help="run name")
parser.add_argument("--patience", type=int, default=50)
return parser.parse_args()


def main():
args = parse_args()

from ultralytics import YOLO

model = YOLO(args.weights)
model.train(
data=args.data,
epochs=args.epochs,
imgsz=args.imgsz,
batch=args.batch,
project=args.project,
name=args.name,
patience=args.patience,
)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "yoru"
version = "0.1.0"
version = "1.1.1"
description = "YORU - Your Own Research Utility for real-time behavioral analysis"
readme = "README.md"
requires-python = ">=3.9,<3.10"
Expand Down
14 changes: 14 additions & 0 deletions web/gui_home.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
</div>
</div>

<div id="error-display" style="display:none; margin:16px; padding:12px; background:#2d1111; border:1px solid #cc3333; border-radius:6px; color:#ff6666; max-height:300px; overflow-y:auto; font-size:13px;">
<h3 style="margin:0 0 8px 0; color:#ff4444;">Error Log</h3>
</div>

<script type="text/javascript">
function runProgram1() {
Expand Down Expand Up @@ -64,6 +67,17 @@
function showFileDialog() {
eel.show_file_dialog();
}

eel.expose(displayError);
function displayError(guiName, errorMsg) {
var errorDiv = document.getElementById('error-display');
var timestamp = new Date().toLocaleTimeString();
var entry = document.createElement('div');
entry.className = 'error-entry';
entry.innerHTML = '<strong>[' + timestamp + '] ' + guiName + '</strong><pre>' + errorMsg + '</pre>';
errorDiv.prepend(entry);
errorDiv.style.display = 'block';
}
</script>

<script type="text/javascript">
Expand Down
121 changes: 121 additions & 0 deletions working-example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# YORU Working Environment

## Date
2026-03-26

## OS
- Windows 11 Home (10.0.26200)

## Conda
- Conda version: 26.1.1
- Environment name: `yoru`
- Environment location: `C:\Users\kamik\anaconda3\envs\yoru`

## Python
- Python 3.9.25

## GPU / CUDA
| Item | Value |
|------|-------|
| GPU | NVIDIA GeForce RTX 5070 Ti |
| GPU Memory | 16,303 MiB |
| NVIDIA Driver | 581.42 |
| CUDA (Driver) | 13.0 |
| CUDA (PyTorch runtime) | 12.8 |
| cuDNN | 9.10.02 |
| PyTorch | 2.8.0+cu128 |
| torchvision | 0.23.0+cu128 |

## Installed Packages

| Package | Version |
|---------|---------|
| bottle | 0.13.4 |
| bottle-websocket | 0.2.9 |
| certifi | 2026.2.25 |
| cffi | 2.0.0 |
| charset-normalizer | 3.4.6 |
| colorama | 0.4.6 |
| contourpy | 1.3.0 |
| cycler | 0.12.1 |
| dearpygui | 1.11.1 |
| deprecation | 2.1.0 |
| Eel | 0.16.0 |
| exceptiongroup | 1.3.1 |
| filelock | 3.19.1 |
| fonttools | 4.60.2 |
| fsspec | 2025.10.0 |
| future | 1.0.0 |
| gevent | 25.9.1 |
| gevent-websocket | 0.10.1 |
| gitdb | 4.0.12 |
| GitPython | 3.1.43 |
| greenlet | 3.2.4 |
| hightime | 0.2.2 |
| idna | 3.11 |
| ImageIO | 2.37.2 |
| imgui | 2.0.0 |
| importlib_resources | 6.5.2 |
| iniconfig | 2.1.0 |
| Jinja2 | 3.1.6 |
| kiwisolver | 1.4.7 |
| labelImg | 1.8.6 |
| lazy-loader | 0.5 |
| lxml | 6.0.2 |
| MarkupSafe | 3.0.2 |
| matplotlib | 3.7.5 |
| mpmath | 1.3.0 |
| mss | 9.0.1 |
| munkres | 1.1.4 |
| networkx | 3.2.1 |
| nidaqmx | 0.9.0 |
| numpy | 1.24.4 |
| opencv-python | 4.10.0.82 |
| packaging | 26.0 |
| pandas | 2.0.3 |
| pillow | 10.3.0 |
| pip | 26.0.1 |
| pluggy | 1.6.0 |
| psutil | 5.9.8 |
| py-cpuinfo | 9.0.0 |
| pycparser | 2.23 |
| pyFirmata | 1.1.0 |
| pyglet | 2.0.15 |
| pynput | 1.7.7 |
| PyOpenGL | 3.1.7 |
| PyOpenGL-accelerate | 3.1.7 |
| pyparsing | 3.3.2 |
| PyQt5 | 5.15.11 |
| PyQt5-Qt5 | 5.15.2 |
| PyQt5_sip | 12.17.1 |
| pyserial | 3.5 |
| pytest | 7.4.0 |
| python-dateutil | 2.9.0.post0 |
| pytz | 2026.1.post1 |
| PyWavelets | 1.6.0 |
| pywin32 | 306 |
| PyYAML | 6.0.1 |
| requests | 2.32.3 |
| scikit-image | 0.21.0 |
| scipy | 1.10.1 |
| seaborn | 0.13.2 |
| setuptools | 80.9.0 |
| six | 1.17.0 |
| smmap | 5.0.3 |
| sympy | 1.14.0 |
| thop | 0.1.1.post2209072238 |
| tifffile | 2024.8.30 |
| tomli | 2.4.1 |
| torch | 2.8.0+cu128 |
| torchvision | 0.23.0+cu128 |
| tqdm | 4.66.4 |
| typing_extensions | 4.15.0 |
| tzdata | 2025.3 |
| ultralytics | 8.2.52 |
| ultralytics-thop | 2.0.0 |
| urllib3 | 2.6.3 |
| wheel | 0.45.1 |
| whichcraft | 0.6.1 |
| zipp | 3.23.0 |
| zope.event | 6.0 |
| zope.interface | 8.0.1 |
57 changes: 40 additions & 17 deletions yoru/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import subprocess
import sys
import threading
from pathlib import Path
from tkinter import Tk, filedialog

Expand All @@ -25,6 +26,28 @@
condition_file_path = default_condition_file_path


def _run_gui_subprocess(command, gui_name):
"""GUIサブプロセスを実行し、エラーがあればEel経由でフロントに通知する"""
proc = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
stdout, stderr = proc.communicate()
if proc.returncode != 0:
error_msg = stderr.strip() if stderr.strip() else stdout.strip()
eel.displayError(gui_name, error_msg)


def _launch_gui(command, gui_name):
"""バックグラウンドスレッドでGUIサブプロセスを起動する"""
thread = threading.Thread(
target=_run_gui_subprocess, args=(command, gui_name), daemon=True
)
thread.start()


def create_default_json():
log_dir = "./logs"
log_file_path = f"{log_dir}/condition_file_log.json"
Expand Down Expand Up @@ -57,17 +80,17 @@ def load_condition_file():
@eel.expose
def run_cam_gui_YMH():
global condition_file_path
if os.path.isfile(condition_file_path):
subprocess.Popen(
[
sys.executable,
"-c",
f"from yoru import realtime_yoru_GUI; realtime_yoru_GUI.main(r'{condition_file_path}')",
],
creationflags=subprocess.CREATE_NEW_CONSOLE,
)
else:
print("not find config file")
if not os.path.isfile(condition_file_path):
eel.displayError("Real-time GUI", "Config file not found: " + condition_file_path)
return
_launch_gui(
[
sys.executable,
"-c",
f"from yoru import realtime_yoru_GUI; realtime_yoru_GUI.main(r'{condition_file_path}')",
],
"Real-time GUI",
)


@eel.expose
Expand Down Expand Up @@ -112,25 +135,25 @@ def print_file_path():

@eel.expose
def run_analysis_gui():
subprocess.Popen(
_launch_gui(
[sys.executable, "-c", "from yoru import analysis_GUI; analysis_GUI.main()"],
creationflags=subprocess.CREATE_NEW_CONSOLE,
"Analysis GUI",
)


@eel.expose
def run_train_gui():
subprocess.Popen(
_launch_gui(
[sys.executable, "-c", "from yoru import train_GUI; train_GUI.main()"],
creationflags=subprocess.CREATE_NEW_CONSOLE,
"Train GUI",
)


@eel.expose
def run_evaluate_gui():
subprocess.Popen(
_launch_gui(
[sys.executable, "-c", "from yoru import evaluation_GUI; evaluation_GUI.main()"],
creationflags=subprocess.CREATE_NEW_CONSOLE,
"Evaluate GUI",
)


Expand Down
Loading