coralnet-toolbox 0.0.75__py2.py3-none-any.whl → 0.0.77__py2.py3-none-any.whl
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.
- coralnet_toolbox/Annotations/QtPolygonAnnotation.py +57 -12
- coralnet_toolbox/Annotations/QtRectangleAnnotation.py +44 -14
- coralnet_toolbox/Common/QtGraphicsUtility.py +18 -8
- coralnet_toolbox/Explorer/transformer_models.py +13 -2
- coralnet_toolbox/IO/QtExportMaskAnnotations.py +576 -402
- coralnet_toolbox/IO/QtImportImages.py +7 -15
- coralnet_toolbox/IO/QtOpenProject.py +15 -19
- coralnet_toolbox/Icons/system_monitor.png +0 -0
- coralnet_toolbox/MachineLearning/ImportDataset/QtBase.py +33 -8
- coralnet_toolbox/QtAnnotationWindow.py +4 -0
- coralnet_toolbox/QtEventFilter.py +5 -5
- coralnet_toolbox/QtImageWindow.py +4 -0
- coralnet_toolbox/QtMainWindow.py +104 -64
- coralnet_toolbox/QtProgressBar.py +1 -0
- coralnet_toolbox/QtSystemMonitor.py +370 -0
- coralnet_toolbox/Rasters/RasterManager.py +5 -2
- coralnet_toolbox/Results/ConvertResults.py +14 -8
- coralnet_toolbox/Results/ResultsProcessor.py +3 -2
- coralnet_toolbox/SAM/QtDeployGenerator.py +1 -1
- coralnet_toolbox/SAM/QtDeployPredictor.py +10 -0
- coralnet_toolbox/SeeAnything/QtDeployGenerator.py +324 -177
- coralnet_toolbox/SeeAnything/QtDeployPredictor.py +10 -6
- coralnet_toolbox/Tile/QtTileBatchInference.py +4 -4
- coralnet_toolbox/Tools/QtPatchTool.py +6 -2
- coralnet_toolbox/Tools/QtPolygonTool.py +5 -3
- coralnet_toolbox/Tools/QtRectangleTool.py +17 -9
- coralnet_toolbox/Tools/QtSAMTool.py +144 -91
- coralnet_toolbox/Tools/QtSeeAnythingTool.py +4 -0
- coralnet_toolbox/Tools/QtTool.py +79 -3
- coralnet_toolbox/Tools/QtWorkAreaTool.py +4 -0
- coralnet_toolbox/Transformers/Models/GroundingDINO.py +72 -0
- coralnet_toolbox/Transformers/Models/OWLViT.py +72 -0
- coralnet_toolbox/Transformers/Models/OmDetTurbo.py +68 -0
- coralnet_toolbox/Transformers/Models/QtBase.py +121 -0
- coralnet_toolbox/{AutoDistill → Transformers}/Models/__init__.py +1 -1
- coralnet_toolbox/{AutoDistill → Transformers}/QtBatchInference.py +15 -15
- coralnet_toolbox/{AutoDistill → Transformers}/QtDeployModel.py +18 -16
- coralnet_toolbox/{AutoDistill → Transformers}/__init__.py +1 -1
- coralnet_toolbox/__init__.py +1 -1
- coralnet_toolbox/utilities.py +0 -15
- {coralnet_toolbox-0.0.75.dist-info → coralnet_toolbox-0.0.77.dist-info}/METADATA +9 -9
- {coralnet_toolbox-0.0.75.dist-info → coralnet_toolbox-0.0.77.dist-info}/RECORD +46 -44
- coralnet_toolbox/AutoDistill/Models/GroundingDINO.py +0 -81
- coralnet_toolbox/AutoDistill/Models/OWLViT.py +0 -76
- coralnet_toolbox/AutoDistill/Models/OmDetTurbo.py +0 -75
- coralnet_toolbox/AutoDistill/Models/QtBase.py +0 -112
- {coralnet_toolbox-0.0.75.dist-info → coralnet_toolbox-0.0.77.dist-info}/WHEEL +0 -0
- {coralnet_toolbox-0.0.75.dist-info → coralnet_toolbox-0.0.77.dist-info}/entry_points.txt +0 -0
- {coralnet_toolbox-0.0.75.dist-info → coralnet_toolbox-0.0.77.dist-info}/licenses/LICENSE.txt +0 -0
- {coralnet_toolbox-0.0.75.dist-info → coralnet_toolbox-0.0.77.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
import torch
|
4
|
+
|
5
|
+
from ultralytics.engine.results import Results
|
6
|
+
|
7
|
+
from transformers import AutoProcessor, AutoModelForZeroShotObjectDetection
|
8
|
+
|
9
|
+
from autodistill.detection import CaptionOntology
|
10
|
+
|
11
|
+
from coralnet_toolbox.Transformers.Models.QtBase import QtBaseModel
|
12
|
+
|
13
|
+
|
14
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
15
|
+
# Classes
|
16
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass
|
20
|
+
class GroundingDINOModel(QtBaseModel):
|
21
|
+
def __init__(self, ontology: CaptionOntology, model="SwinB", device: str = "cpu"):
|
22
|
+
super().__init__(ontology, device)
|
23
|
+
|
24
|
+
if model == "SwinB":
|
25
|
+
model_name = "IDEA-Research/grounding-dino-base"
|
26
|
+
else:
|
27
|
+
model_name = "IDEA-Research/grounding-dino-tiny"
|
28
|
+
|
29
|
+
self.processor = AutoProcessor.from_pretrained(model_name, use_fast=True)
|
30
|
+
self.model = AutoModelForZeroShotObjectDetection.from_pretrained(model_name).to(self.device)
|
31
|
+
|
32
|
+
def _process_predictions(self, image, texts, confidence):
|
33
|
+
"""Process model predictions for a single image."""
|
34
|
+
inputs = self.processor(text=texts, images=image, return_tensors="pt").to(self.device)
|
35
|
+
outputs = self.model(**inputs)
|
36
|
+
|
37
|
+
results_processed = self.processor.post_process_grounded_object_detection(
|
38
|
+
outputs,
|
39
|
+
inputs.input_ids,
|
40
|
+
threshold=confidence,
|
41
|
+
target_sizes=[image.shape[:2]],
|
42
|
+
)[0]
|
43
|
+
|
44
|
+
boxes = results_processed["boxes"]
|
45
|
+
scores = results_processed["scores"]
|
46
|
+
|
47
|
+
# If no objects are detected, return an empty list to match the original behavior.
|
48
|
+
if scores.nelement() == 0:
|
49
|
+
return []
|
50
|
+
|
51
|
+
# Per original logic, assign all detections to class_id 0.
|
52
|
+
# TODO: We are only supporting a single class right now
|
53
|
+
class_ids = torch.zeros(scores.shape[0], 1, device=self.device)
|
54
|
+
|
55
|
+
# Combine boxes, scores, and class_ids into the (N, 6) tensor format
|
56
|
+
# required by the Results object: [x1, y1, x2, y2, confidence, class_id]
|
57
|
+
combined_data = torch.cat([
|
58
|
+
boxes,
|
59
|
+
scores.unsqueeze(1),
|
60
|
+
class_ids
|
61
|
+
], dim=1)
|
62
|
+
|
63
|
+
# Create the dictionary mapping class indices to class names.
|
64
|
+
names = {idx: text for idx, text in enumerate(self.ontology.classes())}
|
65
|
+
|
66
|
+
# Create the Results object with a DETACHED tensor
|
67
|
+
result = Results(orig_img=image,
|
68
|
+
path=None,
|
69
|
+
names=names,
|
70
|
+
boxes=combined_data.detach().cpu())
|
71
|
+
|
72
|
+
return result
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
import torch
|
4
|
+
|
5
|
+
from ultralytics.engine.results import Results
|
6
|
+
|
7
|
+
from transformers import OwlViTForObjectDetection, OwlViTProcessor
|
8
|
+
|
9
|
+
from autodistill.detection import CaptionOntology
|
10
|
+
|
11
|
+
from coralnet_toolbox.Transformers.Models.QtBase import QtBaseModel
|
12
|
+
|
13
|
+
|
14
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
15
|
+
# Classes
|
16
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass
|
20
|
+
class OWLViTModel(QtBaseModel):
|
21
|
+
def __init__(self, ontology: CaptionOntology, device: str = "cpu"):
|
22
|
+
super().__init__(ontology, device)
|
23
|
+
|
24
|
+
model_name = "google/owlvit-base-patch32"
|
25
|
+
self.processor = OwlViTProcessor.from_pretrained(model_name, use_fast=True)
|
26
|
+
self.model = OwlViTForObjectDetection.from_pretrained(model_name).to(self.device)
|
27
|
+
|
28
|
+
def _process_predictions(self, image, texts, confidence):
|
29
|
+
"""
|
30
|
+
Process model predictions for a single image, converting directly
|
31
|
+
to an Ultralytics Results object without an intermediate Supervision object.
|
32
|
+
"""
|
33
|
+
inputs = self.processor(text=texts, images=image, return_tensors="pt").to(self.device)
|
34
|
+
outputs = self.model(**inputs)
|
35
|
+
|
36
|
+
# Post-process the outputs to get detections.
|
37
|
+
# The confidence threshold is applied during this step.
|
38
|
+
results_processed = self.processor.post_process_object_detection(
|
39
|
+
outputs,
|
40
|
+
threshold=confidence,
|
41
|
+
target_sizes=[image.shape[:2]]
|
42
|
+
)[0]
|
43
|
+
|
44
|
+
boxes = results_processed["boxes"]
|
45
|
+
scores = results_processed["scores"]
|
46
|
+
|
47
|
+
# If no objects are detected, return an empty list to match the original behavior.
|
48
|
+
if scores.nelement() == 0:
|
49
|
+
return []
|
50
|
+
|
51
|
+
# Per original logic, assign all detections to class_id 0.
|
52
|
+
# TODO: We are only supporting a single class right now
|
53
|
+
class_ids = torch.zeros(scores.shape[0], 1, device=self.device)
|
54
|
+
|
55
|
+
# Combine boxes, scores, and class_ids into the (N, 6) tensor format
|
56
|
+
# required by the Results object: [x1, y1, x2, y2, confidence, class_id]
|
57
|
+
combined_data = torch.cat([
|
58
|
+
boxes,
|
59
|
+
scores.unsqueeze(1),
|
60
|
+
class_ids
|
61
|
+
], dim=1)
|
62
|
+
|
63
|
+
# Create the dictionary mapping class indices to class names.
|
64
|
+
names = {idx: text for idx, text in enumerate(self.ontology.classes())}
|
65
|
+
|
66
|
+
# Create the Results object with a DETACHED tensor
|
67
|
+
result = Results(orig_img=image,
|
68
|
+
path=None,
|
69
|
+
names=names,
|
70
|
+
boxes=combined_data.detach().cpu())
|
71
|
+
|
72
|
+
return result
|
@@ -0,0 +1,68 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
import torch
|
4
|
+
|
5
|
+
from ultralytics.engine.results import Results
|
6
|
+
|
7
|
+
from transformers import AutoProcessor, OmDetTurboForObjectDetection
|
8
|
+
|
9
|
+
from autodistill.detection import CaptionOntology
|
10
|
+
|
11
|
+
from coralnet_toolbox.Transformers.Models.QtBase import QtBaseModel
|
12
|
+
|
13
|
+
|
14
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
15
|
+
# Classes
|
16
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
|
19
|
+
@dataclass
|
20
|
+
class OmDetTurboModel(QtBaseModel):
|
21
|
+
def __init__(self, ontology: CaptionOntology, device: str = "cpu"):
|
22
|
+
super().__init__(ontology, device)
|
23
|
+
|
24
|
+
model_name = "omlab/omdet-turbo-swin-tiny-hf"
|
25
|
+
self.processor = AutoProcessor.from_pretrained(model_name, use_fast=True)
|
26
|
+
self.model = OmDetTurboForObjectDetection.from_pretrained(model_name).to(self.device)
|
27
|
+
|
28
|
+
def _process_predictions(self, image, texts, confidence):
|
29
|
+
"""Process model predictions for a single image."""
|
30
|
+
inputs = self.processor(text=texts, images=image, return_tensors="pt").to(self.device)
|
31
|
+
outputs = self.model(**inputs)
|
32
|
+
|
33
|
+
results_processed = self.processor.post_process_grounded_object_detection(
|
34
|
+
outputs,
|
35
|
+
threshold=confidence,
|
36
|
+
target_sizes=[image.shape[:2]],
|
37
|
+
text_labels=texts,
|
38
|
+
)[0]
|
39
|
+
|
40
|
+
boxes = results_processed["boxes"]
|
41
|
+
scores = results_processed["scores"]
|
42
|
+
|
43
|
+
# If no objects are detected, return an empty list to match the original behavior.
|
44
|
+
if scores.nelement() == 0:
|
45
|
+
return []
|
46
|
+
|
47
|
+
# Per original logic, assign all detections to class_id 0.
|
48
|
+
# TODO: We are only supporting a single class right now
|
49
|
+
class_ids = torch.zeros(scores.shape[0], 1, device=self.device)
|
50
|
+
|
51
|
+
# Combine boxes, scores, and class_ids into the (N, 6) tensor format
|
52
|
+
# required by the Results object: [x1, y1, x2, y2, confidence, class_id]
|
53
|
+
combined_data = torch.cat([
|
54
|
+
boxes,
|
55
|
+
scores.unsqueeze(1),
|
56
|
+
class_ids
|
57
|
+
], dim=1)
|
58
|
+
|
59
|
+
# Create the dictionary mapping class indices to class names.
|
60
|
+
names = {idx: text for idx, text in enumerate(self.ontology.classes())}
|
61
|
+
|
62
|
+
# Create the Results object with a DETACHED tensor
|
63
|
+
result = Results(orig_img=image,
|
64
|
+
path=None,
|
65
|
+
names=names,
|
66
|
+
boxes=combined_data.detach().cpu())
|
67
|
+
|
68
|
+
return result
|
@@ -0,0 +1,121 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
|
4
|
+
import cv2
|
5
|
+
import numpy as np
|
6
|
+
|
7
|
+
from ultralytics.engine.results import Results
|
8
|
+
|
9
|
+
from autodistill.detection import CaptionOntology, DetectionBaseModel
|
10
|
+
from autodistill.helpers import load_image
|
11
|
+
|
12
|
+
from coralnet_toolbox.Results import CombineResults
|
13
|
+
|
14
|
+
|
15
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
16
|
+
# Classes
|
17
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
18
|
+
|
19
|
+
|
20
|
+
@dataclass
|
21
|
+
class QtBaseModel(DetectionBaseModel, ABC):
|
22
|
+
"""
|
23
|
+
Base class for Transformer foundation models that provides common functionality for
|
24
|
+
handling inputs, processing image data, and formatting detection results.
|
25
|
+
"""
|
26
|
+
ontology: CaptionOntology
|
27
|
+
|
28
|
+
def __init__(self, ontology: CaptionOntology, device: str = "cpu"):
|
29
|
+
"""
|
30
|
+
Initialize the base model with ontology and device.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
ontology: The CaptionOntology containing class labels
|
34
|
+
device: The compute device (cpu, cuda, etc.)
|
35
|
+
"""
|
36
|
+
self.ontology = ontology
|
37
|
+
self.device = device
|
38
|
+
self.processor = None
|
39
|
+
self.model = None
|
40
|
+
|
41
|
+
def _normalize_input(self, input) -> list[np.ndarray]:
|
42
|
+
"""
|
43
|
+
Normalizes various input types into a list of images in CV2 (BGR) format.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
input: Can be an image path, a list of paths, a numpy array, or a list of numpy arrays.
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
A list of images, each as a numpy array in CV2 (BGR) format.
|
50
|
+
"""
|
51
|
+
images = []
|
52
|
+
if isinstance(input, str):
|
53
|
+
# Single image path
|
54
|
+
images = [load_image(input, return_format="cv2")]
|
55
|
+
elif isinstance(input, np.ndarray):
|
56
|
+
# Single image numpy array (RGB) or a batch of images (NHWC, RGB)
|
57
|
+
if input.ndim == 3:
|
58
|
+
images = [cv2.cvtColor(input, cv2.COLOR_RGB2BGR)]
|
59
|
+
elif input.ndim == 4:
|
60
|
+
images = [cv2.cvtColor(img, cv2.COLOR_RGB2BGR) for img in input]
|
61
|
+
else:
|
62
|
+
raise ValueError(f"Unsupported numpy array dimensions: {input.ndim}")
|
63
|
+
elif isinstance(input, list):
|
64
|
+
if all(isinstance(i, str) for i in input):
|
65
|
+
# List of image paths
|
66
|
+
images = [load_image(path, return_format="cv2") for path in input]
|
67
|
+
elif all(isinstance(i, np.ndarray) for i in input):
|
68
|
+
# List of image arrays (RGB)
|
69
|
+
images = [cv2.cvtColor(img, cv2.COLOR_RGB2BGR) for img in input]
|
70
|
+
else:
|
71
|
+
raise ValueError("A list input must contain either all image paths or all numpy arrays.")
|
72
|
+
else:
|
73
|
+
raise TypeError(f"Unsupported input type: {type(input)}")
|
74
|
+
|
75
|
+
return images
|
76
|
+
|
77
|
+
@abstractmethod
|
78
|
+
def _process_predictions(self, image: np.ndarray, texts: list[str], confidence: float) -> Results:
|
79
|
+
"""
|
80
|
+
Process model predictions for a single image.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
image: The input image in CV2 (BGR) format.
|
84
|
+
texts: The text prompts from the ontology.
|
85
|
+
confidence: Confidence threshold.
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
A single Ultralytics Results object, which may be empty if no detections are found.
|
89
|
+
"""
|
90
|
+
pass
|
91
|
+
|
92
|
+
def predict(self, inputs, confidence=0.01) -> list[Results]:
|
93
|
+
"""
|
94
|
+
Run inference on input images.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
inputs: Can be an image path, a list of image paths, a numpy array, or a list of numpy arrays.
|
98
|
+
confidence: Detection confidence threshold.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
A list containing a single combined Ultralytics Results object with detections from all input images.
|
102
|
+
Returns an empty list if no detections are found in any image.
|
103
|
+
"""
|
104
|
+
# Step 1: Normalize the input into a consistent list of images
|
105
|
+
normalized_inputs = self._normalize_input(inputs)
|
106
|
+
|
107
|
+
# Step 2: Prepare for inference
|
108
|
+
results = []
|
109
|
+
texts = self.ontology.prompts()
|
110
|
+
|
111
|
+
# Step 3: Loop through images and process predictions
|
112
|
+
for normalized_input in normalized_inputs:
|
113
|
+
result = self._process_predictions(normalized_input, texts, confidence)
|
114
|
+
if result:
|
115
|
+
results.append(result)
|
116
|
+
|
117
|
+
if len(results):
|
118
|
+
# Combine the results into one, then wrap in a list
|
119
|
+
results = CombineResults().combine_results(results)
|
120
|
+
|
121
|
+
return [results] if results else []
|
@@ -13,14 +13,14 @@ from PyQt5.QtWidgets import (QApplication, QMessageBox, QCheckBox, QVBoxLayout,
|
|
13
13
|
|
14
14
|
|
15
15
|
class BatchInferenceDialog(QDialog):
|
16
|
-
"""Dialog for performing batch inference on images using
|
16
|
+
"""Dialog for performing batch inference on images using Transformers."""
|
17
17
|
|
18
18
|
def __init__(self, main_window, parent=None):
|
19
19
|
super().__init__(parent)
|
20
20
|
self.main_window = main_window
|
21
21
|
self.image_window = main_window.image_window
|
22
22
|
self.annotation_window = main_window.annotation_window
|
23
|
-
self.deploy_model_dialog = main_window.
|
23
|
+
self.deploy_model_dialog = main_window.transformers_deploy_model_dialog
|
24
24
|
self.loaded_models = self.deploy_model_dialog.loaded_model
|
25
25
|
|
26
26
|
self.setWindowTitle("Batch Inference")
|
@@ -64,25 +64,25 @@ class BatchInferenceDialog(QDialog):
|
|
64
64
|
self.image_options_group = QButtonGroup(self)
|
65
65
|
|
66
66
|
# Create image selection options
|
67
|
-
self.
|
68
|
-
self.
|
69
|
-
self.
|
70
|
-
self.
|
67
|
+
self.apply_filtered_checkbox = QCheckBox("▼ Apply to filtered images")
|
68
|
+
self.apply_prev_checkbox = QCheckBox("↑ Apply to previous images")
|
69
|
+
self.apply_next_checkbox = QCheckBox("↓ Apply to next images")
|
70
|
+
self.apply_all_checkbox = QCheckBox("↕ Apply to all images")
|
71
71
|
# Add options to button group
|
72
|
-
self.image_options_group.addButton(self.
|
73
|
-
self.image_options_group.addButton(self.
|
74
|
-
self.image_options_group.addButton(self.
|
75
|
-
self.image_options_group.addButton(self.
|
72
|
+
self.image_options_group.addButton(self.apply_filtered_checkbox)
|
73
|
+
self.image_options_group.addButton(self.apply_prev_checkbox)
|
74
|
+
self.image_options_group.addButton(self.apply_next_checkbox)
|
75
|
+
self.image_options_group.addButton(self.apply_all_checkbox)
|
76
76
|
# Make selections exclusive
|
77
77
|
self.image_options_group.setExclusive(True)
|
78
78
|
# Default selection
|
79
|
-
self.
|
79
|
+
self.apply_all_checkbox.setChecked(True)
|
80
80
|
|
81
81
|
# Add widgets to layout
|
82
|
-
layout.addWidget(self.
|
83
|
-
layout.addWidget(self.
|
84
|
-
layout.addWidget(self.
|
85
|
-
layout.addWidget(self.
|
82
|
+
layout.addWidget(self.apply_filtered_checkbox)
|
83
|
+
layout.addWidget(self.apply_prev_checkbox)
|
84
|
+
layout.addWidget(self.apply_next_checkbox)
|
85
|
+
layout.addWidget(self.apply_all_checkbox)
|
86
86
|
|
87
87
|
group_box.setLayout(layout)
|
88
88
|
self.layout.addWidget(group_box)
|
@@ -18,6 +18,7 @@ from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
|
|
18
18
|
from coralnet_toolbox.QtProgressBar import ProgressBar
|
19
19
|
|
20
20
|
from coralnet_toolbox.Results import ResultsProcessor
|
21
|
+
from coralnet_toolbox.Results import ConvertResults
|
21
22
|
from coralnet_toolbox.Results import MapResults
|
22
23
|
|
23
24
|
from coralnet_toolbox.utilities import rasterio_open
|
@@ -33,13 +34,13 @@ from coralnet_toolbox.Icons import get_icon
|
|
33
34
|
|
34
35
|
class DeployModelDialog(QDialog):
|
35
36
|
"""
|
36
|
-
Dialog for deploying and managing
|
37
|
+
Dialog for deploying and managing Transformers models.
|
37
38
|
Allows users to load, configure, and deactivate models, as well as make predictions on images.
|
38
39
|
"""
|
39
40
|
|
40
41
|
def __init__(self, main_window, parent=None):
|
41
42
|
"""
|
42
|
-
Initialize the
|
43
|
+
Initialize the TransformersDeployModelDialog.
|
43
44
|
|
44
45
|
Args:
|
45
46
|
main_window: The main application window.
|
@@ -52,7 +53,7 @@ class DeployModelDialog(QDialog):
|
|
52
53
|
self.annotation_window = main_window.annotation_window
|
53
54
|
|
54
55
|
self.setWindowIcon(get_icon("coral.png"))
|
55
|
-
self.setWindowTitle("
|
56
|
+
self.setWindowTitle("Transformers Deploy Model (Ctrl + 6)")
|
56
57
|
self.resize(400, 325)
|
57
58
|
|
58
59
|
# Initialize variables
|
@@ -66,6 +67,8 @@ class DeployModelDialog(QDialog):
|
|
66
67
|
self.ontology = None
|
67
68
|
self.class_mapping = {}
|
68
69
|
self.ontology_pairs = []
|
70
|
+
|
71
|
+
self.task = 'detect'
|
69
72
|
|
70
73
|
# Create the layout
|
71
74
|
self.layout = QVBoxLayout(self)
|
@@ -422,8 +425,6 @@ class DeployModelDialog(QDialog):
|
|
422
425
|
progress_bar.close()
|
423
426
|
# Restore cursor
|
424
427
|
QApplication.restoreOverrideCursor()
|
425
|
-
# Exit the dialog box
|
426
|
-
self.accept()
|
427
428
|
|
428
429
|
def load_new_model(self, model_name):
|
429
430
|
"""
|
@@ -433,8 +434,17 @@ class DeployModelDialog(QDialog):
|
|
433
434
|
model_name: Name of the model to load.
|
434
435
|
uncertainty_thresh: Threshold for uncertainty.
|
435
436
|
"""
|
437
|
+
|
438
|
+
# Clear the model
|
439
|
+
self.loaded_model = None
|
440
|
+
self.model_name = None
|
441
|
+
|
442
|
+
# Clear cache
|
443
|
+
gc.collect()
|
444
|
+
torch.cuda.empty_cache()
|
445
|
+
|
436
446
|
if "GroundingDINO" in model_name:
|
437
|
-
from coralnet_toolbox.
|
447
|
+
from coralnet_toolbox.Transformers.Models.GroundingDINO import GroundingDINOModel
|
438
448
|
|
439
449
|
model = model_name.split("-")[1].strip()
|
440
450
|
self.model_name = model_name
|
@@ -443,14 +453,14 @@ class DeployModelDialog(QDialog):
|
|
443
453
|
device=self.main_window.device)
|
444
454
|
|
445
455
|
elif "OmDetTurbo" in model_name:
|
446
|
-
from coralnet_toolbox.
|
456
|
+
from coralnet_toolbox.Transformers.Models.OmDetTurbo import OmDetTurboModel
|
447
457
|
|
448
458
|
self.model_name = model_name
|
449
459
|
self.loaded_model = OmDetTurboModel(ontology=self.ontology,
|
450
460
|
device=self.main_window.device)
|
451
461
|
|
452
462
|
elif "OWLViT" in model_name:
|
453
|
-
from coralnet_toolbox.
|
463
|
+
from coralnet_toolbox.Transformers.Models.OWLViT import OWLViTModel
|
454
464
|
|
455
465
|
self.model_name = model_name
|
456
466
|
self.loaded_model = OWLViTModel(ontology=self.ontology,
|
@@ -495,7 +505,6 @@ class DeployModelDialog(QDialog):
|
|
495
505
|
continue
|
496
506
|
|
497
507
|
results = self._apply_model(inputs)
|
498
|
-
results = self._update_results(results_processor, results, inputs, image_path)
|
499
508
|
results = self._apply_sam(results, image_path)
|
500
509
|
self._process_results(results_processor, results, image_path)
|
501
510
|
|
@@ -553,13 +562,6 @@ class DeployModelDialog(QDialog):
|
|
553
562
|
|
554
563
|
return results_list
|
555
564
|
|
556
|
-
def _update_results(self, results_processor, results, inputs, image_path):
|
557
|
-
"""Update the results to match Ultralytics format."""
|
558
|
-
return [results_processor.from_supervision(results,
|
559
|
-
inputs,
|
560
|
-
image_path,
|
561
|
-
self.class_mapping)]
|
562
|
-
|
563
565
|
def _apply_sam(self, results_list, image_path):
|
564
566
|
"""Apply SAM to the results if needed."""
|
565
567
|
# Check if SAM model is deployed and loaded
|
coralnet_toolbox/__init__.py
CHANGED
coralnet_toolbox/utilities.py
CHANGED
@@ -30,21 +30,6 @@ from coralnet_toolbox.QtProgressBar import ProgressBar
|
|
30
30
|
# ----------------------------------------------------------------------------------------------------------------------
|
31
31
|
|
32
32
|
|
33
|
-
def get_available_device():
|
34
|
-
"""
|
35
|
-
Get available devices
|
36
|
-
|
37
|
-
:return:
|
38
|
-
"""
|
39
|
-
devices = ['cpu',]
|
40
|
-
if torch.cuda.is_available():
|
41
|
-
for i in range(torch.cuda.device_count()):
|
42
|
-
devices.append(f'cuda:{i}')
|
43
|
-
if torch.backends.mps.is_available():
|
44
|
-
devices.append('mps')
|
45
|
-
return devices
|
46
|
-
|
47
|
-
|
48
33
|
@lru_cache(maxsize=32)
|
49
34
|
def rasterio_open(image_path):
|
50
35
|
"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: coralnet-toolbox
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.77
|
4
4
|
Summary: Tools for annotating and developing ML models for benthic imagery
|
5
5
|
Author-email: Jordan Pierce <jordan.pierce@noaa.gov>
|
6
6
|
License: MIT License
|
@@ -16,7 +16,7 @@ License-File: LICENSE.txt
|
|
16
16
|
Requires-Dist: PyQt5>=5.15.11
|
17
17
|
Requires-Dist: pyqtdarktheme
|
18
18
|
Requires-Dist: pyqtgraph
|
19
|
-
Requires-Dist: ultralytics>=8.3.
|
19
|
+
Requires-Dist: ultralytics>=8.3.191
|
20
20
|
Requires-Dist: lap>=0.5.12
|
21
21
|
Requires-Dist: open-clip-torch>=2.20.0
|
22
22
|
Requires-Dist: supervision>=0.24.0
|
@@ -27,7 +27,7 @@ Requires-Dist: pycocotools
|
|
27
27
|
Requires-Dist: ujson
|
28
28
|
Requires-Dist: timm==0.9.2
|
29
29
|
Requires-Dist: autodistill
|
30
|
-
Requires-Dist: transformers>=4.
|
30
|
+
Requires-Dist: transformers>=4.56.0
|
31
31
|
Requires-Dist: hf_xet
|
32
32
|
Requires-Dist: x-segment-anything>=0.0.8
|
33
33
|
Requires-Dist: yolo-tiling>=0.0.19
|
@@ -39,6 +39,8 @@ Requires-Dist: beautifulsoup4>=4.12.2
|
|
39
39
|
Requires-Dist: webdriver_manager
|
40
40
|
Requires-Dist: dill
|
41
41
|
Requires-Dist: seaborn
|
42
|
+
Requires-Dist: GPUtil
|
43
|
+
Requires-Dist: psutil
|
42
44
|
Provides-Extra: all
|
43
45
|
Requires-Dist: coralnet-toolbox[extra]; extra == "all"
|
44
46
|
Dynamic: license-file
|
@@ -114,6 +116,7 @@ For a complete installation guide (including CUDA setup), see the [Installation
|
|
114
116
|
| **Overview** | Get the big picture | [📋 Read More](https://jordan-pierce.github.io/CoralNet-Toolbox/overview) |
|
115
117
|
| **Installation** | Detailed setup instructions | [⚙️ Setup Guide](https://jordan-pierce.github.io/CoralNet-Toolbox/installation) |
|
116
118
|
| **Usage** | Learn the tools | [🛠️ User Manual](https://jordan-pierce.github.io/CoralNet-Toolbox/usage) |
|
119
|
+
| **Hot Keys** | Keyboard shortcuts | [⌨️ Shortcuts](https://jordan-pierce.github.io/CoralNet-Toolbox/hot-keys) |
|
117
120
|
| **Classification** | Community tutorial | [🧠 AI Tutorial](https://jordan-pierce.github.io/CoralNet-Toolbox/classify) |
|
118
121
|
|
119
122
|
</div>
|
@@ -179,7 +182,7 @@ The toolbox integrates state-of-the-art models for efficient annotation workflow
|
|
179
182
|
| **Framework** | **Models** | **Capability** |
|
180
183
|
|:---:|:---:|:---:|
|
181
184
|
| **YOLOE** | See Anything | Visual prompt detection |
|
182
|
-
| **
|
185
|
+
| **Transformers** | Grounding DINO • OWLViT • OmDetTurbo | Zero-shot detection |
|
183
186
|
|
184
187
|
</div>
|
185
188
|
|
@@ -277,12 +280,9 @@ uv pip install coralnet-toolbox
|
|
277
280
|
### 🚀 **Step 3: GPU Acceleration (Optional)**
|
278
281
|
For CUDA-enabled systems:
|
279
282
|
```bash
|
280
|
-
# Example for CUDA
|
281
|
-
conda install nvidia/label/cuda-11.8.0::cuda-nvcc -y
|
282
|
-
conda install nvidia/label/cuda-11.8.0::cuda-toolkit -y
|
283
|
-
|
283
|
+
# Example for CUDA 12.9
|
284
284
|
# Install PyTorch with CUDA support
|
285
|
-
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/
|
285
|
+
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu129 --upgrade
|
286
286
|
```
|
287
287
|
|
288
288
|
### 🏃♂️ **Step 4: Launch**
|