Skip to content

Commit

Permalink
Merge pull request #94 from Jordan-Pierce/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Jordan-Pierce authored Dec 30, 2024
2 parents 93b055c + de154de commit d1792e2
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 81 deletions.
2 changes: 1 addition & 1 deletion coralnet_toolbox/Annotations/QtAnnotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,4 @@ def __repr__(self):
f"image_path={self.image_path}, "
f"label={self.label.short_label_code}, "
f"data={self.data}, "
f"machine_confidence={self.machine_confidence})")
f"machine_confidence={self.machine_confidence})")
42 changes: 22 additions & 20 deletions coralnet_toolbox/QtAnnotationWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from coralnet_toolbox.Tools import (
PanTool,
PatchTool,
PatchTool,
PolygonTool,
RectangleTool,
SAMTool,
Expand All @@ -42,6 +42,7 @@ class AnnotationWindow(QGraphicsView):
annotationSizeChanged = pyqtSignal(int) # Signal to emit when annotation size changes
annotationSelected = pyqtSignal(int) # Signal to emit when annotation is selected
annotationDeleted = pyqtSignal(str) # Signal to emit when annotation is deleted
annotationCreated = pyqtSignal(str) # Signal to emit when annotation is created
hover_point = pyqtSignal(QPointF) # Signal to emit when mouse hovers over a point

def __init__(self, main_window, parent=None):
Expand All @@ -54,7 +55,7 @@ def __init__(self, main_window, parent=None):
self.annotation_size = 224
self.annotation_color = None
self.transparency = 128

self.zoom_factor = 1.0
self.pan_active = False
self.pan_start = None
Expand Down Expand Up @@ -136,7 +137,7 @@ def keyPressEvent(self, event):
if self.active_image and self.selected_tool:
self.tools[self.selected_tool].keyPressEvent(event)
super().keyPressEvent(event)

# Handle the hot key for deleting (backspace or delete) selected annotations
if event.modifiers() & Qt.ControlModifier:
if event.key() == Qt.Key_Delete or event.key() == Qt.Key_Backspace:
Expand All @@ -157,7 +158,7 @@ def cursorInWindow(self, pos, mapped=False):
pos = self.mapToScene(pos)

return image_rect.contains(pos)

def cursorInViewport(self, pos):
if not pos:
return False
Expand Down Expand Up @@ -227,14 +228,14 @@ def set_annotation_size(self, size=None, delta=0):
if len(self.selected_annotations) <= 1:
# Emit that the annotation size has changed
self.annotationSizeChanged.emit(self.annotation_size)

def is_annotation_moveable(self, annotation):
if annotation.show_message:
self.unselect_annotations()
annotation.show_warning_message()
return False
return True

def toggle_cursor_annotation(self, scene_pos: QPointF = None):

if self.cursor_annotation:
Expand Down Expand Up @@ -284,7 +285,7 @@ def set_image(self, image_path):
self.scene.addItem(QGraphicsPixmapItem(self.image_pixmap))
self.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
self.tools["zoom"].calculate_min_zoom()

self.toggle_cursor_annotation()

# Set the image dimensions, and current view in status bar
Expand Down Expand Up @@ -402,7 +403,7 @@ def load_annotations(self):
# Initialize the progress bar
progress_bar = ProgressBar(self, title="Loading Annotations")
progress_bar.show()

# Crop all the annotations for current image (if not already cropped)
annotations = self.crop_image_annotations(return_annotations=True)
progress_bar.start_progress(len(annotations))
Expand All @@ -419,12 +420,12 @@ def load_annotations(self):

QApplication.processEvents()
self.viewport().update()

def load_these_annotations(self, image_path, annotations):
# Initialize the progress bar
progress_bar = ProgressBar(self, title="Loading Annotations")
progress_bar.show()

# Crop all the annotations for current image (if not already cropped)
annotations = self.crop_these_image_annotations(image_path, annotations)
progress_bar.start_progress(len(annotations))
Expand Down Expand Up @@ -487,15 +488,15 @@ def _crop_annotations_batch_linear(self, image_path, annotations):
progress_bar = ProgressBar(self, title="Cropping Annotations")
progress_bar.show()
progress_bar.start_progress(len(annotations))

# Get the rasterio representation
rasterio_image = self.main_window.image_window.rasterio_open(image_path)
# Loop through the annotations, crop the image if not already cropped
for annotation in annotations:
if not annotation.cropped_image:
annotation.create_cropped_image(rasterio_image)
progress_bar.update_progress()

progress_bar.stop_progress()
progress_bar.close()

Expand All @@ -504,13 +505,13 @@ def _crop_annotations_batch(self, image_path, annotations):
progress_bar = ProgressBar(self, title="Cropping Annotations")
progress_bar.show()
progress_bar.start_progress(len(annotations))

# Create a lock for thread-safe access to the rasterio dataset
lock = threading.Lock()

# Get the rasterio representation
rasterio_image = self.main_window.image_window.rasterio_open(image_path)

def crop_annotation(annotation):
with lock:
if not annotation.cropped_image:
Expand All @@ -523,7 +524,7 @@ def crop_annotation(annotation):
for future in as_completed(futures):
future.result() # Ensure any exceptions are raised
progress_bar.update_progress()

progress_bar.stop_progress()
progress_bar.close()

Expand Down Expand Up @@ -557,16 +558,17 @@ def add_annotation(self, scene_pos: QPointF = None):
annotation.annotationUpdated.connect(self.main_window.confidence_window.display_cropped_image)

self.annotations_dict[annotation.id] = annotation

self.main_window.confidence_window.display_cropped_image(annotation)
self.annotationCreated.emit(annotation.id)

def delete_annotation(self, annotation_id):
if annotation_id in self.annotations_dict:
# Get the annotation from dict, delete it
# Get the annotation from dict
annotation = self.annotations_dict[annotation_id]
# Delete the annotation
annotation.delete()
self.annotationDeleted.emit(annotation.id)
del self.annotations_dict[annotation_id]
self.annotationDeleted.emit(annotation_id)
# Clear the confidence window
self.main_window.confidence_window.clear_display()

Expand Down Expand Up @@ -612,4 +614,4 @@ def clear_scene(self):
del item
self.scene.deleteLater()
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.setScene(self.scene)
18 changes: 13 additions & 5 deletions coralnet_toolbox/QtConfidenceWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from PyQt5.QtCore import Qt, pyqtSignal, QRectF
from PyQt5.QtGui import QPixmap, QColor, QPainter, QCursor
from PyQt5.QtWidgets import (QGraphicsView, QGraphicsScene, QWidget, QVBoxLayout,
QLabel, QHBoxLayout, QFrame)
QLabel, QHBoxLayout, QFrame, QGroupBox)

warnings.filterwarnings("ignore", category=DeprecationWarning)

Expand Down Expand Up @@ -72,6 +72,11 @@ def __init__(self, main_window, parent=None):
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setSpacing(0)

# Create a groupbox and set its title
self.groupBox = QGroupBox("Confidence Window")
self.groupBoxLayout = QVBoxLayout()
self.groupBox.setLayout(self.groupBoxLayout)

self.graphics_view = None
self.scene = None
self.downscale_factor = 1.0
Expand All @@ -91,7 +96,10 @@ def __init__(self, main_window, parent=None):
# Add QLabel for dimensions
self.dimensions_label = QLabel(self)
self.dimensions_label.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.dimensions_label)
self.groupBoxLayout.addWidget(self.dimensions_label)

# Add the groupbox to the main layout
self.layout.addWidget(self.groupBox)

def resizeEvent(self, event):
super().resizeEvent(event)
Expand All @@ -102,15 +110,15 @@ def init_graphics_view(self):
self.graphics_view = QGraphicsView(self)
self.scene = QGraphicsScene(self)
self.graphics_view.setScene(self.scene)
self.layout.addWidget(self.graphics_view, 2) # 2 for stretch factor
self.groupBoxLayout.addWidget(self.graphics_view, 2) # 2 for stretch factor
self.update_blank_pixmap()

def init_bar_chart_widget(self):
self.bar_chart_widget = QWidget()
self.bar_chart_layout = QVBoxLayout(self.bar_chart_widget)
self.bar_chart_layout.setContentsMargins(0, 0, 0, 0)
self.bar_chart_layout.setSpacing(2) # Set spacing to make bars closer
self.layout.addWidget(self.bar_chart_widget, 1) # 1 for stretch factor
self.groupBoxLayout.addWidget(self.bar_chart_widget, 1) # 1 for stretch factor

def update_blank_pixmap(self):
view_size = self.graphics_view.size()
Expand Down Expand Up @@ -212,4 +220,4 @@ def handle_bar_click(self, label):
self.annotation.update_label(label)
# Update everything (essentially)
self.main_window.annotation_window.unselect_annotation(self.annotation)
self.main_window.annotation_window.select_annotation(self.annotation)
self.main_window.annotation_window.select_annotation(self.annotation)
Loading

0 comments on commit d1792e2

Please sign in to comment.