Skip to content

Commit 3124e49

Browse files
Fix tests...
1 parent e346b95 commit 3124e49

File tree

2 files changed

+172
-44
lines changed

2 files changed

+172
-44
lines changed

src/navigate/controller/sub_controllers/camera_view.py

Lines changed: 146 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ def initialize(self, name, data):
273273

274274
def update_snr(self):
275275
"""Updates the signal-to-noise ratio."""
276+
276277
pass
277278

278279
def set_mode(self, mode=""):
@@ -374,6 +375,13 @@ def toggle_min_max_buttons(self, display=False):
374375
def try_to_display_image(self, image):
375376
"""Try to display an image.
376377
378+
Note
379+
----
380+
This function is called when an image is acquired. The image is passed to the
381+
display function. If the display function is already displaying an image, the
382+
function will return. Thus, if imaging is faster than the display, the display
383+
will skip frames.
384+
377385
Parameters
378386
----------
379387
image : numpy.ndarray
@@ -558,18 +566,59 @@ def digital_zoom(self):
558566
return zoom_image
559567

560568
def detect_saturation(self, image):
561-
"""Look for any pixels at the maximum intensity allowable for the camera."""
569+
"""Look for any pixels at the maximum intensity allowable for the camera.
570+
571+
Note
572+
----
573+
The camera is set to 16-bit depth, so the maximum intensity is 2^16 - 1. If
574+
another camera is used, this function should be updated to reflect the maximum
575+
intensity value.
576+
577+
Parameters
578+
----------
579+
image : numpy.ndarray
580+
Image data.
581+
582+
Returns
583+
-------
584+
saturated_pixels : numpy.ndarray
585+
Saturated pixels in the image.
586+
"""
562587
saturation_value = 2**16 - 1
563588
self.saturated_pixels = image[image > saturation_value]
564589

565590
def down_sample_image(self, image):
566-
"""Down-sample the data for image display according to widget size."""
591+
"""Down-sample the data for image display according to widget size.
592+
593+
Interpolation type is cv2.INTER_LINEAR by default.
594+
595+
Parameters
596+
----------
597+
image : numpy.ndarray
598+
Image data.
599+
600+
Returns
601+
-------
602+
down_sampled_image : numpy.ndarray
603+
Down-sampled image data.
604+
"""
567605
sx, sy = self.canvas_width, self.canvas_height
568606
down_sampled_image = cv2.resize(image, (sx, sy))
569607
return down_sampled_image
570608

571609
def scale_image_intensity(self, image):
572-
"""Scale the data to the min/max counts, and adjust bit-depth."""
610+
"""Scale the data to the min/max counts, and adjust bit-depth.
611+
612+
Parameters
613+
----------
614+
image : numpy.ndarray
615+
Image data.
616+
617+
Returns
618+
-------
619+
image : numpy.ndarray
620+
Scaled image data.
621+
"""
573622
if self.autoscale is True:
574623
self.max_counts = np.max(image)
575624
self.min_counts = np.min(image)
@@ -609,6 +658,11 @@ def add_crosshair(self, image):
609658
def array_to_image(self, image):
610659
"""Convert a numpy array to a PIL Image
611660
661+
Parameters
662+
----------
663+
image : numpy.ndarray
664+
Image data.
665+
612666
Returns
613667
-------
614668
image : Image
@@ -617,17 +671,26 @@ def array_to_image(self, image):
617671
return Image.fromarray(image.astype(np.uint8))
618672

619673
def populate_image(self, image):
620-
"""Converts image to an ImageTk.PhotoImage and populates the Tk Canvas"""
674+
"""Converts image to an ImageTk.PhotoImage and populates the Tk Canvas
675+
676+
Note
677+
----
678+
When calling ImageTk.PhotoImage() to generate a new image, it will destroy
679+
what the canvas is showing, causing it to blink. This problem is solved by
680+
creating two images and alternating between them.
681+
682+
Parameters
683+
----------
684+
image : numpy.ndarray
685+
Image data.
686+
"""
621687
temp_img = self.array_to_image(image)
622-
# when calling ImageTk.PhotoImage() to generate a new image, it will destroy
623-
# what the canvas is showing, causing it to blink.
624688
if self.image_cache_flag:
625689
self.tk_image = ImageTk.PhotoImage(temp_img)
626690
self.canvas.create_image(0, 0, image=self.tk_image, anchor="nw")
627691
else:
628692
self.tk_image2 = ImageTk.PhotoImage(temp_img)
629693
self.canvas.create_image(0, 0, image=self.tk_image2, anchor="nw")
630-
631694
self.image_cache_flag = not self.image_cache_flag
632695

633696
def process_image(self):
@@ -647,7 +710,13 @@ def process_image(self):
647710
self.populate_image(image)
648711

649712
def left_click(self, *args):
650-
"""Toggles cross-hair on image upon left click event."""
713+
"""Toggles cross-hair on image upon left click event.
714+
715+
Parameters
716+
----------
717+
args : tuple
718+
Arguments.
719+
"""
651720
if self.image is not None:
652721
self.apply_cross_hair = not self.apply_cross_hair
653722
self.process_image()
@@ -701,6 +770,11 @@ def update_min_max_counts(self, display=False):
701770
702771
When the min and max counts are toggled in the GUI, this function is called.
703772
Updates the min and max values.
773+
774+
Parameters
775+
----------
776+
display : bool
777+
Flag to display the image.
704778
"""
705779
if self.image_palette["Min"].get() != "":
706780
self.min_counts = float(self.image_palette["Min"].get())
@@ -886,7 +960,13 @@ def update_snr(self):
886960
self.image_palette["SNR"].grid(row=3, column=0, sticky=tk.NSEW, pady=3)
887961

888962
def slider_update(self, *args):
889-
"""Updates the image when the slider is moved."""
963+
"""Updates the image when the slider is moved.
964+
965+
Parameters
966+
----------
967+
args : tuple
968+
Arguments.
969+
"""
890970

891971
slider_index = self.view.slider.get()
892972
channel_index = self.view.live_frame.channel.get()
@@ -909,9 +989,13 @@ def slider_update(self, *args):
909989
def update_display_state(self, *args):
910990
"""Image Display Combobox Called.
911991
912-
Sets self.display_state to desired display format.
913-
Toggles state of slider widget.
914-
Sets number of positions.
992+
Sets self.display_state to desired display format. Toggles state of slider
993+
widget. Sets number of positions.
994+
995+
Parameters
996+
----------
997+
args : tuple
998+
Arguments.
915999
"""
9161000
if self.number_of_slices == 0:
9171001
return
@@ -1140,6 +1224,11 @@ def array_to_image(self, image):
11401224
11411225
If a color mask is present, it will apply the mask to the image.
11421226
1227+
Parameters
1228+
----------
1229+
image : numpy.ndarray
1230+
Image data.
1231+
11431232
Returns
11441233
-------
11451234
image : Image
@@ -1189,11 +1278,6 @@ def set_mask_color_table(self, colors):
11891278
----------
11901279
colors : list
11911280
List of colors to use for the segmentation mask
1192-
1193-
Returns
1194-
-------
1195-
self.mask_color_table : np.array
1196-
Array of colors to use for the segmentation mask
11971281
"""
11981282
self.mask_color_table = np.zeros((256, 1, 3), dtype=np.uint8)
11991283
self.mask_color_table[0] = [0, 0, 0]
@@ -1238,14 +1322,29 @@ def __init__(self, view, parent_controller=None):
12381322
The parent controller of the camera view controller.
12391323
"""
12401324
super().__init__(view, parent_controller)
1325+
1326+
#: tkinter.Canvas: The tkinter canvas that displays the image.
12411327
self.view = view
1328+
1329+
#: np.ndarray: The image data.
12421330
self.image = None
1331+
1332+
#: np.ndarray: The maximum intensity projection in the ZY plane.
12431333
self.zx_mip = None
1334+
1335+
#: np.ndarray: The maximum intensity projection in the ZY plane.
12441336
self.zy_mip = None
1337+
1338+
#: np.ndarray: The maximum intensity projection in the XY plane.
12451339
self.xy_mip = None
1340+
1341+
#: bool: The autoscale flag.
12461342
self.autoscale = True
1343+
1344+
#: str: The perspective of the image.
12471345
self.perspective = "XY"
12481346

1347+
#: dict: The render widgets.
12491348
self.render_widgets = self.view.render.get_widgets()
12501349

12511350
if platform.system() == "Windows":
@@ -1254,13 +1353,10 @@ def __init__(self, view, parent_controller=None):
12541353
def initialize(self, name, data):
12551354
"""Initialize the MIP view.
12561355
1257-
Sets the min and max intensity values for the image.
1258-
Disables the min and max widgets.
1259-
Invokes the gray and autoscale widgets.
1260-
Hides the SNR widget.
1261-
Sets the perspective widget values.
1262-
Sets the perspective widget to XY.
1263-
Sets the channel widget to CH0.
1356+
Sets the min and max intensity values for the image.Disables the min and max
1357+
widgets. Invokes the gray and autoscale widgets.Hides the SNR widget.
1358+
Sets the perspective widget values. Sets the perspective widget to XY. Sets
1359+
the channel widget to CH0.
12641360
12651361
Parameters
12661362
----------
@@ -1422,7 +1518,13 @@ def display_image(self, image):
14221518
is_displaying_image.value = False
14231519

14241520
def display_mip_image(self, *args):
1425-
"""Display MIP image in non-live view"""
1521+
"""Display MIP image in non-live view.
1522+
1523+
Parameters
1524+
----------
1525+
args : tuple
1526+
Arguments.
1527+
"""
14261528
if self.perspective != self.render_widgets["perspective"].get():
14271529
self.update_perspective()
14281530
if self.mode != "stop":
@@ -1432,6 +1534,15 @@ def display_mip_image(self, *args):
14321534
self.process_image()
14331535

14341536
def update_perspective(self, *args, display=False):
1537+
"""Update the perspective of the image.
1538+
1539+
Parameters
1540+
----------
1541+
args : tuple
1542+
Arguments.
1543+
display : bool
1544+
Flag to display the image.
1545+
"""
14351546
display_mode = self.render_widgets["perspective"].get()
14361547
self.perspective = display_mode
14371548
if display_mode == "XY":
@@ -1448,7 +1559,15 @@ def update_perspective(self, *args, display=False):
14481559
self.reset_display(False)
14491560

14501561
def down_sample_image(self, image, reset_original=False):
1451-
"""Down-sample the data for image display according to widget size."""
1562+
"""Down-sample the data for image display according to widget size.
1563+
1564+
Parameters
1565+
----------
1566+
image : numpy.ndarray
1567+
Image data.
1568+
reset_original : bool
1569+
Flag to reset the original image size.
1570+
"""
14521571
sx, sy = self.canvas_width, self.canvas_height
14531572
down_sampled_image = cv2.resize(image, (sx, sy))
14541573
if reset_original:
@@ -1458,6 +1577,7 @@ def down_sample_image(self, image, reset_original=False):
14581577
self.canvas_height_scale = 1
14591578
return down_sampled_image
14601579

1580+
14611581
class SpooledImageLoader:
14621582
"""A class to lazily load images from disk using a spooled temporary file."""
14631583

0 commit comments

Comments
 (0)