descriptron-gui 2.0.2__tar.gz → 2.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/PKG-INFO +3 -3
- descriptron_gui-2.0.4/pyproject.toml +45 -0
- descriptron_gui-2.0.4/pyproject.toml.bak_pre_204_20260924_165335 +45 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/src/descriptron_gui/tools/descriptron-v2-v73.py +97 -11
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/.gitignore +0 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/LICENSE +0 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/NOTICE +0 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/README.md +0 -0
- /descriptron_gui-2.0.2/pyproject.toml → /descriptron_gui-2.0.4/pyproject.toml.bak_pre_203_20260924_145320 +0 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/src/descriptron_gui/__init__.py +0 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/src/descriptron_gui/cli.py +0 -0
- {descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/src/descriptron_gui/data/marmot.jpg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: descriptron-gui
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: The Descriptron annotation GUI: SAM2-assisted segmentation, keypoints and COCO export
|
|
5
5
|
Project-URL: Homepage, https://github.com/alexrvandam/Descriptron
|
|
6
6
|
Author: Alex R. Van Dam
|
|
@@ -14,8 +14,8 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
16
16
|
Requires-Python: >=3.9
|
|
17
|
-
Requires-Dist: descriptron-core==2.0.
|
|
18
|
-
Requires-Dist: descriptron-vision==2.0.
|
|
17
|
+
Requires-Dist: descriptron-core==2.0.4
|
|
18
|
+
Requires-Dist: descriptron-vision==2.0.4
|
|
19
19
|
Provides-Extra: dev
|
|
20
20
|
Requires-Dist: build>=1; extra == 'dev'
|
|
21
21
|
Requires-Dist: pytest>=7; extra == 'dev'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "descriptron-gui"
|
|
7
|
+
version = "2.0.4"
|
|
8
|
+
description = "The Descriptron annotation GUI: SAM2-assisted segmentation, keypoints and COCO export"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "Alex R. Van Dam" }]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Environment :: X11 Applications",
|
|
16
|
+
"Topic :: Scientific/Engineering :: Image Processing",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"License :: OSI Approved :: Apache Software License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
# tkinter is part of the standard library and so is not listed here, but it is
|
|
23
|
+
# not always packaged with Python on Linux: `apt install python3-tk` if the GUI
|
|
24
|
+
# fails to start. The GUI drives the analysis scripts directly, so it needs core
|
|
25
|
+
# as well as vision — it is not a thin front end.
|
|
26
|
+
dependencies = [
|
|
27
|
+
"descriptron-core==2.0.4",
|
|
28
|
+
"descriptron-vision==2.0.4",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = ["pytest>=7", "build>=1", "twine>=5"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
descriptron-gui = "descriptron_gui.cli:main"
|
|
36
|
+
|
|
37
|
+
[project.gui-scripts]
|
|
38
|
+
# on Windows this launches without a console window behind it
|
|
39
|
+
descriptron-gui-app = "descriptron_gui.cli:main"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/alexrvandam/Descriptron"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/descriptron_gui"]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "descriptron-gui"
|
|
7
|
+
version = "2.0.3"
|
|
8
|
+
description = "The Descriptron annotation GUI: SAM2-assisted segmentation, keypoints and COCO export"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "Alex R. Van Dam" }]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Environment :: X11 Applications",
|
|
16
|
+
"Topic :: Scientific/Engineering :: Image Processing",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"License :: OSI Approved :: Apache Software License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
# tkinter is part of the standard library and so is not listed here, but it is
|
|
23
|
+
# not always packaged with Python on Linux: `apt install python3-tk` if the GUI
|
|
24
|
+
# fails to start. The GUI drives the analysis scripts directly, so it needs core
|
|
25
|
+
# as well as vision — it is not a thin front end.
|
|
26
|
+
dependencies = [
|
|
27
|
+
"descriptron-core==2.0.3",
|
|
28
|
+
"descriptron-vision==2.0.3",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = ["pytest>=7", "build>=1", "twine>=5"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
descriptron-gui = "descriptron_gui.cli:main"
|
|
36
|
+
|
|
37
|
+
[project.gui-scripts]
|
|
38
|
+
# on Windows this launches without a console window behind it
|
|
39
|
+
descriptron-gui-app = "descriptron_gui.cli:main"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/alexrvandam/Descriptron"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/descriptron_gui"]
|
{descriptron_gui-2.0.2 → descriptron_gui-2.0.4}/src/descriptron_gui/tools/descriptron-v2-v73.py
RENAMED
|
@@ -13200,6 +13200,9 @@ def open_pal_popup():
|
|
|
13200
13200
|
chunk_size_var = tk.StringVar(value="0")
|
|
13201
13201
|
iou_threshold_var = tk.StringVar(value="0.5")
|
|
13202
13202
|
load_checkpoint_var = tk.StringVar(value="")
|
|
13203
|
+
# v21 opt-in robustness options (both OFF by default; image in the template's orientation when possible)
|
|
13204
|
+
orientation_search_var = tk.BooleanVar(value=False)
|
|
13205
|
+
flip_augment_var = tk.BooleanVar(value=False)
|
|
13203
13206
|
|
|
13204
13207
|
# Create scrollable frame for the popup
|
|
13205
13208
|
main_canvas = tk.Canvas(popup)
|
|
@@ -13226,12 +13229,12 @@ def open_pal_popup():
|
|
|
13226
13229
|
|
|
13227
13230
|
# Version and status info
|
|
13228
13231
|
status_parts = [f"Script: {pal_script_name}"]
|
|
13229
|
-
if version_str in ["v17", "v18"]:
|
|
13232
|
+
if version_str in ["v17", "v18", "v19", "v20", "v21"]:
|
|
13230
13233
|
status_parts.append("Multi-mask: [OK]")
|
|
13231
|
-
if version_str
|
|
13234
|
+
if version_str in ["v18", "v19", "v20", "v21"]:
|
|
13232
13235
|
status_parts.append("OOM-fix: [OK]")
|
|
13233
13236
|
status_parts.append("Cycle-consistency: [OK]")
|
|
13234
|
-
if version_str in ["v16", "v17"]:
|
|
13237
|
+
if version_str in ["v16", "v17", "v18", "v19", "v20", "v21"]:
|
|
13235
13238
|
status_parts.append(f"LoRA: {'[OK] Available' if lora_available else 'Install peft'}")
|
|
13236
13239
|
status_text = " | ".join(status_parts)
|
|
13237
13240
|
tk.Label(scrollable_popup, text=status_text, fg="blue", font=("Arial", 9)).grid(row=row, column=0, columnspan=3, pady=(0, 5))
|
|
@@ -13286,7 +13289,7 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13286
13289
|
tk.Button(json_frame, text="Browse", command=lambda: browse_file_pal(template_json_var, "Select Template COCO JSON", [("JSON Files", "*.json")])).grid(row=0, column=2, padx=5, pady=3)
|
|
13287
13290
|
|
|
13288
13291
|
# Info about multi-mask
|
|
13289
|
-
if version_str
|
|
13292
|
+
if version_str in ["v17", "v18", "v19", "v20", "v21"]:
|
|
13290
13293
|
tk.Label(json_frame, text="v17: Multiple masks (e.g., scape, antenna, eye) will ALL be trained and predicted",
|
|
13291
13294
|
fg="green", font=("Arial", 8)).grid(row=1, column=0, columnspan=3, sticky='w', padx=5)
|
|
13292
13295
|
else:
|
|
@@ -13370,7 +13373,7 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13370
13373
|
row += 1
|
|
13371
13374
|
|
|
13372
13375
|
# === LoRA Section (v16/v17 only) ===
|
|
13373
|
-
if version_str in ["v16", "v17"]:
|
|
13376
|
+
if version_str in ["v16", "v17", "v18", "v19", "v20", "v21"]:
|
|
13374
13377
|
lora_frame = tk.LabelFrame(scrollable_popup, text="LoRA Fine-tuning (v16+ - Optional)", padx=5, pady=5)
|
|
13375
13378
|
lora_frame.grid(row=row, column=0, columnspan=3, padx=10, pady=5, sticky='ew')
|
|
13376
13379
|
|
|
@@ -13404,7 +13407,7 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13404
13407
|
tk.Entry(output_frame, textvariable=num_points_var, width=5).grid(row=2, column=2, sticky='w', padx=2)
|
|
13405
13408
|
|
|
13406
13409
|
# V18 inference strategy options
|
|
13407
|
-
if version_str in ["v18"]:
|
|
13410
|
+
if version_str in ["v18", "v19", "v20", "v21"]:
|
|
13408
13411
|
v18_frame = tk.LabelFrame(output_frame, text="v18 Inference Strategy", padx=3, pady=3)
|
|
13409
13412
|
v18_frame.grid(row=3, column=0, columnspan=3, sticky='ew', padx=5, pady=5)
|
|
13410
13413
|
|
|
@@ -13435,6 +13438,15 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13435
13438
|
tk.Button(v18_frame, text="Browse", command=_browse_load_ckpt, width=8).grid(row=3, column=2, padx=2)
|
|
13436
13439
|
tk.Label(v18_frame, text="(skip training, use existing .pt for inference only)",
|
|
13437
13440
|
fg="gray", font=("Arial", 8)).grid(row=4, column=0, columnspan=3, sticky='w', padx=5)
|
|
13441
|
+
if version_str == "v21":
|
|
13442
|
+
tk.Checkbutton(v18_frame, text="Orientation search (specimens may be rotated; 4x slower)",
|
|
13443
|
+
variable=orientation_search_var).grid(row=5, column=0, columnspan=3, sticky='w')
|
|
13444
|
+
tk.Label(v18_frame, text="(tries 0/90/180/270 deg per image, keeps the most confident; cannot fix mirrored "
|
|
13445
|
+
"imaging - best practice is to image in the template's orientation)",
|
|
13446
|
+
fg="gray", font=("Arial", 8), wraplength=520, justify='left').grid(row=6, column=0, columnspan=3,
|
|
13447
|
+
sticky='w', padx=5)
|
|
13448
|
+
tk.Checkbutton(v18_frame, text="Flip augmentation during fine-tuning (original + h + v + hv copies)",
|
|
13449
|
+
variable=flip_augment_var).grid(row=7, column=0, columnspan=3, sticky='w')
|
|
13438
13450
|
|
|
13439
13451
|
row += 1
|
|
13440
13452
|
|
|
@@ -13498,7 +13510,7 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13498
13510
|
do_finetune = enable_finetune_var.get()
|
|
13499
13511
|
if do_finetune:
|
|
13500
13512
|
# === FIX: Allow COCO JSON mode for fine-tuning in v17 ===
|
|
13501
|
-
if mode == "json" and version_str not in ["v17", "v18"]:
|
|
13513
|
+
if mode == "json" and version_str not in ["v17", "v18", "v19", "v20", "v21"]:
|
|
13502
13514
|
messagebox.showerror("Error", "PAL fine-tuning with COCO JSON requires v17.\nPlease use Binary Mask mode or upgrade to sam2_pal_batch_v17.py")
|
|
13503
13515
|
return
|
|
13504
13516
|
# For mask mode, still require a mask file
|
|
@@ -13569,7 +13581,7 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13569
13581
|
command.extend(['--training_images_dir', training_images_dir_var.get()])
|
|
13570
13582
|
|
|
13571
13583
|
# LoRA options (v16/v17 only)
|
|
13572
|
-
if version_str in ["v16", "v17", "v18"] and use_lora_var.get() and lora_available:
|
|
13584
|
+
if version_str in ["v16", "v17", "v18", "v19", "v20", "v21"] and use_lora_var.get() and lora_available:
|
|
13573
13585
|
command.append('--use_lora')
|
|
13574
13586
|
command.extend(['--lora_rank', lora_rank_var.get()])
|
|
13575
13587
|
|
|
@@ -13584,7 +13596,7 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13584
13596
|
command.append('--interleave_template')
|
|
13585
13597
|
|
|
13586
13598
|
# V18 inference strategy options
|
|
13587
|
-
if version_str in ["v18"]:
|
|
13599
|
+
if version_str in ["v18", "v19", "v20", "v21"]:
|
|
13588
13600
|
if load_checkpoint_var.get() and os.path.exists(load_checkpoint_var.get()):
|
|
13589
13601
|
command.extend(['--load_checkpoint', load_checkpoint_var.get()])
|
|
13590
13602
|
if cycle_consistency_var.get():
|
|
@@ -13595,6 +13607,11 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13595
13607
|
iou_thr = float(iou_threshold_var.get() or "0.5")
|
|
13596
13608
|
if iou_thr != 0.5:
|
|
13597
13609
|
command.extend(['--iou_threshold', str(iou_thr)])
|
|
13610
|
+
if version_str == "v21":
|
|
13611
|
+
if orientation_search_var.get():
|
|
13612
|
+
command.extend(['--orientation_search', 'rot4'])
|
|
13613
|
+
if do_finetune and flip_augment_var.get():
|
|
13614
|
+
command.extend(['--flip_augment', 'all'])
|
|
13598
13615
|
|
|
13599
13616
|
# === FIX: Save settings to YAML file ===
|
|
13600
13617
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
@@ -13636,6 +13653,8 @@ This forces the model to learn REAL tracking, not just memorization."""
|
|
|
13636
13653
|
'chunk_size': chunk_size_var.get(),
|
|
13637
13654
|
'iou_threshold': iou_threshold_var.get(),
|
|
13638
13655
|
'load_checkpoint': load_checkpoint_var.get(),
|
|
13656
|
+
'orientation_search': orientation_search_var.get(),
|
|
13657
|
+
'flip_augment': flip_augment_var.get(),
|
|
13639
13658
|
},
|
|
13640
13659
|
'command': ' '.join(command),
|
|
13641
13660
|
}
|
|
@@ -14442,6 +14461,10 @@ def open_biorag_popup():
|
|
|
14442
14461
|
if not _sh.which("claude"):
|
|
14443
14462
|
messagebox.showerror("Error", "Claude Code CLI ('claude') not found on PATH. Install and log in, or choose the 'api' backend.")
|
|
14444
14463
|
return
|
|
14464
|
+
if llm_backend_var.get() == "api" and not _descriptron_key_gui("ANTHROPIC_API_KEY", parent=popup): # v2.0.4
|
|
14465
|
+
if not messagebox.askyesno("No API key", "No ANTHROPIC_API_KEY is set, so the species descriptions "
|
|
14466
|
+
"cannot be written. Run anyway (matrix, key and evidence sheets only)?"):
|
|
14467
|
+
return
|
|
14445
14468
|
|
|
14446
14469
|
script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "measure",
|
|
14447
14470
|
"run_full_pipeline_v2.py" if workflow_var.get() == "v2" else "run_full_pipeline.py")
|
|
@@ -15473,6 +15496,45 @@ next_image_button.grid(row=2, column=13, padx=0, pady=0)
|
|
|
15473
15496
|
DINOLAND_ENV = os.environ.get("DINOLAND_ENV", "biorag")
|
|
15474
15497
|
|
|
15475
15498
|
|
|
15499
|
+
def _descriptron_key_gui(name, parent=None, model_id=None):
|
|
15500
|
+
"""v2.0.4: make sure `name` (ANTHROPIC_API_KEY or HF_TOKEN) is available to the programs this GUI
|
|
15501
|
+
launches: environment, then ~/.config/descriptron/credentials, then — first use only — a dialog.
|
|
15502
|
+
For HF_TOKEN nothing is asked when the DINOv3 weights are already cached (or cannot be checked).
|
|
15503
|
+
Switched off entirely by DESCRIPTRON_NO_KEY_PROMPT=1. Keys are never logged."""
|
|
15504
|
+
import sys as _sys
|
|
15505
|
+
here = os.path.dirname(os.path.abspath(__file__))
|
|
15506
|
+
if os.path.join(here, "measure") not in _sys.path:
|
|
15507
|
+
_sys.path.append(os.path.join(here, "measure"))
|
|
15508
|
+
try:
|
|
15509
|
+
import descriptron_credentials as _c
|
|
15510
|
+
except ImportError:
|
|
15511
|
+
try:
|
|
15512
|
+
from descriptron_core.cli import tools_dir as _td
|
|
15513
|
+
_sys.path.append(str(_td()))
|
|
15514
|
+
import descriptron_credentials as _c
|
|
15515
|
+
except Exception:
|
|
15516
|
+
return None
|
|
15517
|
+
_c.load_into_environment()
|
|
15518
|
+
if name == "HF_TOKEN":
|
|
15519
|
+
if not model_id or os.path.isdir(os.path.expanduser(model_id)) or os.environ.get("HF_HUB_OFFLINE") == "1":
|
|
15520
|
+
return None
|
|
15521
|
+
try:
|
|
15522
|
+
from huggingface_hub import try_to_load_from_cache
|
|
15523
|
+
if isinstance(try_to_load_from_cache(model_id, "config.json"), str):
|
|
15524
|
+
return None
|
|
15525
|
+
except Exception:
|
|
15526
|
+
return None
|
|
15527
|
+
|
|
15528
|
+
def _ask(n, purpose, where):
|
|
15529
|
+
from tkinter import simpledialog
|
|
15530
|
+
return simpledialog.askstring(
|
|
15531
|
+
"Descriptron: key needed",
|
|
15532
|
+
f"{n} is needed for {purpose}.\n\nGet one at:\n{where}\n\n"
|
|
15533
|
+
f"It is saved, readable by you only, in\n{_c.credentials_path()}\n"
|
|
15534
|
+
f"so you are asked only once. Leave empty to skip.", show="*", parent=parent)
|
|
15535
|
+
return _c.ensure_key(name, ask=_ask)
|
|
15536
|
+
|
|
15537
|
+
|
|
15476
15538
|
def _dinoland_build_cmd(v, script_path, env=None):
|
|
15477
15539
|
"""Turn the DINOLand dialog values into the dinov3_landmark_transfer_v51.py command.
|
|
15478
15540
|
Kept separate from the Tk code so it can be unit-tested without a display."""
|
|
@@ -15491,6 +15553,10 @@ def _dinoland_build_cmd(v, script_path, env=None):
|
|
|
15491
15553
|
cmd += ["--batch_n", str(int(v["batch_n"]))]
|
|
15492
15554
|
if v.get("emit_refs"):
|
|
15493
15555
|
cmd.append("--emit_refs")
|
|
15556
|
+
if v.get("mirror_refs"):
|
|
15557
|
+
cmd.append("--mirror_refs")
|
|
15558
|
+
if v.get("rotate_refs"):
|
|
15559
|
+
cmd += ["--orientation_search", "rot4"] # v52+ (same flag name as SAM2-PAL)
|
|
15494
15560
|
else: # pair
|
|
15495
15561
|
cmd += ["--imgB", v["imgB"]]
|
|
15496
15562
|
if v.get("maskB"):
|
|
@@ -15542,6 +15608,8 @@ def run_dinoland_script():
|
|
|
15542
15608
|
facet = tk.StringVar(value="token"); align = tk.StringVar(value="mask")
|
|
15543
15609
|
preview = tk.StringVar(value="original"); fig_per_page = tk.StringVar(value="12")
|
|
15544
15610
|
emit_refs = tk.BooleanVar(value=True); extra = tk.StringVar()
|
|
15611
|
+
mirror_refs = tk.BooleanVar(value=False)
|
|
15612
|
+
rotate_refs = tk.BooleanVar(value=False)
|
|
15545
15613
|
|
|
15546
15614
|
IMG_TYPES = [("Images", "*.jpg *.jpeg *.png *.tif *.tiff"), ("All Files", "*.*")]
|
|
15547
15615
|
JSON_TYPES = [("COCO keypoints JSON", "*.json"), ("All Files", "*.*")]
|
|
@@ -15607,6 +15675,20 @@ def run_dinoland_script():
|
|
|
15607
15675
|
tk.OptionMenu(of, align, "mask", "feature").pack(side=tk.LEFT)
|
|
15608
15676
|
tk.OptionMenu(of, preview, "original", "letterbox").pack(side=tk.LEFT)
|
|
15609
15677
|
tk.Checkbutton(of, text="emit per-image COCO + refs_confirmed.txt", variable=emit_refs).pack(side=tk.LEFT, padx=8)
|
|
15678
|
+
row += 1
|
|
15679
|
+
tk.Checkbutton(input_window, variable=mirror_refs,
|
|
15680
|
+
text="Batch: specimens may be mirror images (wings, legs, left/right parts) - "
|
|
15681
|
+
"also use a flipped copy of every reference").grid(row=row, column=1, sticky='w', padx=5, pady=3)
|
|
15682
|
+
row += 1
|
|
15683
|
+
if (Path(__file__).parent / 'dinov3_landmark_transfer_v52.py').is_file():
|
|
15684
|
+
tk.Checkbutton(input_window, variable=rotate_refs,
|
|
15685
|
+
text="Batch: specimens may be turned or upside-down - orientation search over "
|
|
15686
|
+
"0/90/180/270 deg (not sure how specimens were imaged? tick both boxes)"
|
|
15687
|
+
).grid(row=row, column=1, sticky='w', padx=5, pady=3)
|
|
15688
|
+
row += 1
|
|
15689
|
+
tk.Label(input_window, text="Tip: 5 or more references from different species transfer best "
|
|
15690
|
+
"(Diaphorina wings: 61% -> 70% of landmarks within 5% of wing length).",
|
|
15691
|
+
fg="gray30").grid(row=row, column=1, sticky='w', padx=5)
|
|
15610
15692
|
add_row("Extra arguments:", extra)
|
|
15611
15693
|
|
|
15612
15694
|
def submit():
|
|
@@ -15617,7 +15699,8 @@ def run_dinoland_script():
|
|
|
15617
15699
|
mask_dir=mask_dir.get().strip(), outdir=outdir.get().strip() or "lm_out",
|
|
15618
15700
|
model=model_id.get(), layers=layers.get(), n_lm=n_lm.get(), radius=radius.get(),
|
|
15619
15701
|
dim=dim.get(), facet=facet.get(), align=align.get(), preview=preview.get(),
|
|
15620
|
-
fig_per_page=fig_per_page.get(), emit_refs=emit_refs.get(), extra=extra.get()
|
|
15702
|
+
fig_per_page=fig_per_page.get(), emit_refs=emit_refs.get(), extra=extra.get(),
|
|
15703
|
+
mirror_refs=mirror_refs.get(), rotate_refs=rotate_refs.get())
|
|
15621
15704
|
if not v["imgA"]:
|
|
15622
15705
|
messagebox.showerror("Input Error", "Please select the reference image A.")
|
|
15623
15706
|
return
|
|
@@ -15629,10 +15712,13 @@ def run_dinoland_script():
|
|
|
15629
15712
|
return
|
|
15630
15713
|
|
|
15631
15714
|
script_dir = Path(__file__).parent
|
|
15632
|
-
dinoland_script = script_dir / '
|
|
15715
|
+
dinoland_script = script_dir / 'dinov3_landmark_transfer_v52.py' # v52 = v51 + --rotate_refs
|
|
15716
|
+
if not dinoland_script.is_file():
|
|
15717
|
+
dinoland_script = script_dir / 'dinov3_landmark_transfer_v51.py'
|
|
15633
15718
|
if not dinoland_script.is_file():
|
|
15634
15719
|
messagebox.showerror("Script Error", f"DINOLand script not found at: {dinoland_script}")
|
|
15635
15720
|
return
|
|
15721
|
+
_descriptron_key_gui("HF_TOKEN", parent=input_window, model_id=v.get("model")) # v2.0.4
|
|
15636
15722
|
cmd = _dinoland_build_cmd(v, dinoland_script)
|
|
15637
15723
|
out_path = Path(v["outdir"]); out_path.mkdir(parents=True, exist_ok=True)
|
|
15638
15724
|
log_path = out_path / "dinoland_run.log"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|