From d31d43e9b0cb3c90202cf39ccdfa3220f6300917 Mon Sep 17 00:00:00 2001 From: Antoine Weisrock Date: Thu, 7 Mar 2024 15:55:56 +0100 Subject: [PATCH 1/6] refactor: subclasses can customize _update_img without redefining it --- src/crappy/tool/camera_config/camera_config.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/crappy/tool/camera_config/camera_config.py b/src/crappy/tool/camera_config/camera_config.py index 9662bbee..55be0b60 100644 --- a/src/crappy/tool/camera_config/camera_config.py +++ b/src/crappy/tool/camera_config/camera_config.py @@ -1050,6 +1050,7 @@ def _update_img(self) -> None: self.shape = img.shape self._cast_img(img) + self._draw_overlay() self._resize_img() self._calc_hist() @@ -1061,3 +1062,9 @@ def _update_img(self) -> None: self._update_pixel_value() self.update() + + def _draw_overlay(self) -> None: + """Method meant to be used by subclasses for drawing an overlay on top of + the image to display.""" + + ... From 4589a4b9e315e4dc1af885992df356e7b3af59a5 Mon Sep 17 00:00:00 2001 From: Antoine Weisrock Date: Thu, 7 Mar 2024 16:03:34 +0100 Subject: [PATCH 2/6] refactor: replace _on_img_resize with _draw_overlay Avoids repeating code, and therefore prevents partial fixes in the future. --- .../tool/camera_config/dic_ve_config.py | 48 +---------------- .../tool/camera_config/dis_correl_config.py | 52 ++----------------- .../camera_config/video_extenso_config.py | 50 ++---------------- 3 files changed, 11 insertions(+), 139 deletions(-) diff --git a/src/crappy/tool/camera_config/dic_ve_config.py b/src/crappy/tool/camera_config/dic_ve_config.py index 6b1230b6..f67f2fb5 100644 --- a/src/crappy/tool/camera_config/dic_ve_config.py +++ b/src/crappy/tool/camera_config/dic_ve_config.py @@ -3,10 +3,6 @@ from typing import Optional from tkinter.messagebox import showerror import tkinter as tk -import numpy as np -from io import BytesIO -from pkg_resources import resource_string -from time import sleep import logging from multiprocessing.queues import Queue @@ -165,50 +161,10 @@ def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: self._display_img() self.update() - def _update_img(self) -> None: - """Same as in the parent class except it also draws the patches on top of - the displayed image.""" + def _draw_overlay(self) -> None: + """Draws the detected spots to track on top of the last acquired image.""" - self.log(logging.DEBUG, "Updating the image") - - ret = self._camera.get_image() - - # If no frame could be grabbed from the camera - if ret is None: - # If it's the first call, generate error image to initialize the window - if not self._n_loops: - self.log(logging.WARNING, "Could not get an image from the camera, " - "displaying an error image instead") - ret = None, np.array(Image.open(BytesIO(resource_string( - 'crappy', 'tool/data/no_image.png')))) - # Otherwise, just pass - else: - self.log(logging.DEBUG, "No image returned by the camera") - self.update() - sleep(0.001) - return - - self._n_loops += 1 - _, img = ret - - if img.dtype != self.dtype: - self.dtype = img.dtype - if self.shape != img.shape: - self.shape = img.shape - - self._cast_img(img) self._draw_spots() - self._resize_img() - - self._calc_hist() - self._resize_hist() - - self._display_img() - self._display_hist() - - self._update_pixel_value() - - self.update() def _handle_box_outside_img(self, box: Box) -> None: """If a patch is outside the image, warning the user and resetting the diff --git a/src/crappy/tool/camera_config/dis_correl_config.py b/src/crappy/tool/camera_config/dis_correl_config.py index da17bf95..d8330288 100644 --- a/src/crappy/tool/camera_config/dis_correl_config.py +++ b/src/crappy/tool/camera_config/dis_correl_config.py @@ -3,10 +3,6 @@ import tkinter as tk from tkinter.messagebox import showerror from typing import Optional -import numpy as np -from io import BytesIO -from pkg_resources import resource_string -from time import sleep import logging from multiprocessing.queues import Queue @@ -164,54 +160,16 @@ def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: self._resize_img() self._display_img() self.update() + def _draw_overlay(self) -> None: + """Draws the box to use for performing correlation on top of the last + acquired image. - def _update_img(self) -> None: - """Same as in the parent class except it also draws the select box on top - of the displayed image.""" + Does not draw the correl box is the user is using the selection box. + """ - self.log(logging.DEBUG, "Updating the image") - - ret = self._camera.get_image() - - # If no frame could be grabbed from the camera - if ret is None: - # If it's the first call, generate error image to initialize the window - if not self._n_loops: - self.log(logging.WARNING, "Could not get an image from the camera, " - "displaying an error image instead") - ret = None, np.array(Image.open(BytesIO(resource_string( - 'crappy', 'tool/data/no_image.png')))) - # Otherwise, just pass - else: - self.log(logging.DEBUG, "No image returned by the camera") - self.update() - sleep(0.001) - return - - self._n_loops += 1 - _, img = ret - - if img.dtype != self.dtype: - self.dtype = img.dtype - if self.shape != img.shape: - self.shape = img.shape - - self._cast_img(img) - # Do not draw the correl box if the user is creating the select box if self._draw_correl_box: self._draw_box(self._correl_box) self._draw_box(self._select_box) - self._resize_img() - - self._calc_hist() - self._resize_hist() - - self._display_img() - self._display_hist() - - self._update_pixel_value() - - self.update() def _handle_box_outside_img(self, _: Box) -> None: """If the correl box is outside the image, it means that the image size has diff --git a/src/crappy/tool/camera_config/video_extenso_config.py b/src/crappy/tool/camera_config/video_extenso_config.py index cacbbe8a..2ac4fd21 100644 --- a/src/crappy/tool/camera_config/video_extenso_config.py +++ b/src/crappy/tool/camera_config/video_extenso_config.py @@ -3,10 +3,6 @@ import tkinter as tk from tkinter.messagebox import showerror from typing import Optional -import numpy as np -from io import BytesIO -from pkg_resources import resource_string -from time import sleep import logging from multiprocessing.queues import Queue @@ -177,52 +173,14 @@ def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: self._resize_img() self._display_img() self.update() + def _draw_overlay(self) -> None: + """Draws the detected spots to track on top of the last acquired image. - def _update_img(self) -> None: - """Same as in the parent class except it also draws the patches and the - select box on top of the displayed image.""" + Also draws the selection box if the user is currently drawing one. + """ - self.log(logging.DEBUG, "Updating the image") - - ret = self._camera.get_image() - - # If no frame could be grabbed from the camera - if ret is None: - # If it's the first call, generate error image to initialize the window - if not self._n_loops: - self.log(logging.WARNING, "Could not get an image from the camera, " - "displaying an error image instead") - ret = None, np.array(Image.open(BytesIO(resource_string( - 'crappy', 'tool/data/no_image.png')))) - # Otherwise, just pass - else: - self.log(logging.DEBUG, "No image returned by the camera") - self.update() - sleep(0.001) - return - - self._n_loops += 1 - _, img = ret - - if img.dtype != self.dtype: - self.dtype = img.dtype - if self.shape != img.shape: - self.shape = img.shape - - self._cast_img(img) self._draw_box(self._select_box) self._draw_spots() - self._resize_img() - - self._calc_hist() - self._resize_hist() - - self._display_img() - self._display_hist() - - self._update_pixel_value() - - self.update() def _handle_box_outside_img(self, _: Box) -> None: """If a patch is outside the image, it means that the image size has been From 51b9644c1410fccc3cb09bf57770fd2b905d134b Mon Sep 17 00:00:00 2001 From: Antoine Weisrock Date: Thu, 7 Mar 2024 16:06:10 +0100 Subject: [PATCH 3/6] refactor: remove useless repetition of _on_img_resize removal permitted by the changes in d31d43e9 and 4589a4b9 --- src/crappy/tool/camera_config/camera_config.py | 2 ++ src/crappy/tool/camera_config/dic_ve_config.py | 11 ----------- src/crappy/tool/camera_config/dis_correl_config.py | 14 -------------- .../tool/camera_config/video_extenso_config.py | 11 ----------- 4 files changed, 2 insertions(+), 36 deletions(-) diff --git a/src/crappy/tool/camera_config/camera_config.py b/src/crappy/tool/camera_config/camera_config.py index 55be0b60..8fe53601 100644 --- a/src/crappy/tool/camera_config/camera_config.py +++ b/src/crappy/tool/camera_config/camera_config.py @@ -940,6 +940,8 @@ def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: self.log(logging.DEBUG, "The image canvas was resized") + self._draw_overlay() + self._resize_img() self._display_img() self.update() diff --git a/src/crappy/tool/camera_config/dic_ve_config.py b/src/crappy/tool/camera_config/dic_ve_config.py index f67f2fb5..5946a345 100644 --- a/src/crappy/tool/camera_config/dic_ve_config.py +++ b/src/crappy/tool/camera_config/dic_ve_config.py @@ -150,17 +150,6 @@ def _stop_box(self, _: tk.Event) -> None: # This box is not needed anymore self._select_box.reset() - def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: - """Same as in the parent class except it also draws the patches on top of - the displayed image.""" - - self.log(logging.DEBUG, "The image canvas was resized") - - self._draw_spots() - self._resize_img() - self._display_img() - self.update() - def _draw_overlay(self) -> None: """Draws the detected spots to track on top of the last acquired image.""" diff --git a/src/crappy/tool/camera_config/dis_correl_config.py b/src/crappy/tool/camera_config/dis_correl_config.py index d8330288..5a081de9 100644 --- a/src/crappy/tool/camera_config/dis_correl_config.py +++ b/src/crappy/tool/camera_config/dis_correl_config.py @@ -146,20 +146,6 @@ def _stop_box(self, _: tk.Event) -> None: self._draw_correl_box = True - def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: - """Same as in the parent class except it also draws the select box on top - of the displayed image.""" - - self.log(logging.DEBUG, "The image canvas was resized") - - # Do not draw the correl box if the user is creating the select box - if self._draw_correl_box: - self._draw_box(self._correl_box) - self._draw_box(self._select_box) - - self._resize_img() - self._display_img() - self.update() def _draw_overlay(self) -> None: """Draws the box to use for performing correlation on top of the last acquired image. diff --git a/src/crappy/tool/camera_config/video_extenso_config.py b/src/crappy/tool/camera_config/video_extenso_config.py index 2ac4fd21..7a757358 100644 --- a/src/crappy/tool/camera_config/video_extenso_config.py +++ b/src/crappy/tool/camera_config/video_extenso_config.py @@ -162,17 +162,6 @@ def _save_l0(self) -> None: f"Successfully saved L0 ! L0 x : {self._detector.spots.x_l0}, " f"L0 y : {self._detector.spots.y_l0}") - def _on_img_resize(self, _: Optional[tk.Event] = None) -> None: - """Same as in the parent class except it also draws the patches and the - select box on top of the displayed image.""" - - self.log(logging.DEBUG, "The image canvas was resized") - - self._draw_box(self._select_box) - self._draw_spots() - self._resize_img() - self._display_img() - self.update() def _draw_overlay(self) -> None: """Draws the detected spots to track on top of the last acquired image. From 75a87239639a354be111f8e9b927f42aa61b8f5b Mon Sep 17 00:00:00 2001 From: Antoine Weisrock Date: Thu, 7 Mar 2024 16:06:26 +0100 Subject: [PATCH 4/6] style: minor syntax improvement --- src/crappy/tool/camera_config/camera_config_boxes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crappy/tool/camera_config/camera_config_boxes.py b/src/crappy/tool/camera_config/camera_config_boxes.py index 069d47bf..4ec426b1 100644 --- a/src/crappy/tool/camera_config/camera_config_boxes.py +++ b/src/crappy/tool/camera_config/camera_config_boxes.py @@ -88,7 +88,7 @@ def _handle_box_outside_img(self, _: Box) -> None: """This method is meant to simplify the customization of the action to perform when a patch is outside the image in subclasses.""" - pass + ... def _draw_spots(self) -> None: """Simply draws every spot on top of the image.""" From cf5b58e35a9176e5930d2c5061c7b3ca2e3562b4 Mon Sep 17 00:00:00 2001 From: Antoine Weisrock Date: Thu, 7 Mar 2024 16:07:14 +0100 Subject: [PATCH 5/6] refactor: remove additional code repetitions in subclasses --- src/crappy/tool/camera_config/dis_correl_config.py | 9 +-------- src/crappy/tool/camera_config/video_extenso_config.py | 5 +---- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/crappy/tool/camera_config/dis_correl_config.py b/src/crappy/tool/camera_config/dis_correl_config.py index 5a081de9..2d5871d2 100644 --- a/src/crappy/tool/camera_config/dis_correl_config.py +++ b/src/crappy/tool/camera_config/dis_correl_config.py @@ -108,14 +108,7 @@ def _start_box(self, event: tk.Event) -> None: """Simply saves the position of the user click, and disables the display of the current correl box.""" - self.log(logging.DEBUG, "Starting the selection box") - - # If the mouse is on the canvas but not on the image, do nothing - if not self._check_event_pos(event): - return - - self._select_box.x_start, \ - self._select_box.y_start = self._coord_to_pix(event.x, event.y) + super()._start_box(event) self._draw_correl_box = False diff --git a/src/crappy/tool/camera_config/video_extenso_config.py b/src/crappy/tool/camera_config/video_extenso_config.py index 7a757358..b18d4198 100644 --- a/src/crappy/tool/camera_config/video_extenso_config.py +++ b/src/crappy/tool/camera_config/video_extenso_config.py @@ -111,10 +111,7 @@ def _create_buttons(self) -> None: """Compared with the parent class, creates an extra button for saving the original position of the spots.""" - self._update_button = tk.Button(self._sets_frame, text="Apply Settings", - command=self._update_settings) - self._update_button.pack(expand=False, fill='none', ipadx=5, ipady=5, - padx=5, pady=5, anchor='n', side='top') + super()._create_buttons() self._update_button = tk.Button(self._sets_frame, text="Save L0", command=self._save_l0) From e099409b00aab02eb0eb11968590e9b4012f0706 Mon Sep 17 00:00:00 2001 From: Antoine Weisrock Date: Thu, 7 Mar 2024 16:27:57 +0100 Subject: [PATCH 6/6] fix: bug in config window when using Camera object returning None The error image indicating that no image could be grabbed was being displayed recurrently, whereas it should only be before the very first image is captured. Fixes #113 --- src/crappy/tool/camera_config/camera_config.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/crappy/tool/camera_config/camera_config.py b/src/crappy/tool/camera_config/camera_config.py index 8fe53601..25792f5b 100644 --- a/src/crappy/tool/camera_config/camera_config.py +++ b/src/crappy/tool/camera_config/camera_config.py @@ -112,6 +112,7 @@ def __init__(self, self._run = True self._n_loops = 0 self._max_freq = max_freq + self._got_first_img: bool = False # Settings for adjusting the behavior of the zoom self._zoom_ratio = 0.9 @@ -1025,13 +1026,12 @@ def _update_img(self) -> None: ret = self._camera.get_image() # Flag raised if no image could be grabbed - no_img = False + no_img = ret is None # If no frame could be grabbed from the camera - if ret is None: - no_img = True + if no_img: # If it's the first call, generate error image to initialize the window - if not self._n_loops: + if not self._got_first_img: self.log(logging.WARNING, "Could not get an image from the camera, " "displaying an error image instead") ret = None, np.array(Image.open(BytesIO(resource_string( @@ -1043,6 +1043,8 @@ def _update_img(self) -> None: sleep(0.001) return + # Always set, so that the error image is only ever loaded once + self._got_first_img = True self._n_loops += 1 _, img = ret