Skip to content

Commit 94ae120

Browse files
Merge pull request #1431 from MouseLand/imagedraw_fixes
Imagedraw fixes & update logging
2 parents 0577880 + 99fe4c1 commit 94ae120

5 files changed

Lines changed: 64 additions & 35 deletions

File tree

cellpose/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
from cellpose.version import version, version_str
2+
import logging
3+
4+
# set base `cellpose` logger
5+
logging.getLogger(__name__).addHandler(logging.NullHandler())

cellpose/gui/gui.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Copyright © 2025 Howard Hughes Medical Institute, Authored by Carsen Stringer, Michael Rariden and Marius Pachitariu.
33
"""
44

5+
import logging
56
import sys, os, pathlib, warnings, datetime, time, copy
67

78
from qtpy import QtGui, QtCore
@@ -138,7 +139,7 @@ def make_cmap(cm=0):
138139

139140
def run(image=None):
140141
from ..io import logger_setup
141-
logger, log_file = logger_setup()
142+
logger_setup()
142143
# Always start by initializing Qt (only once per application)
143144
warnings.filterwarnings("ignore")
144145
app = QApplication(sys.argv)
@@ -166,7 +167,7 @@ def run(image=None):
166167
app.setWindowIcon(app_icon)
167168
app.setStyle("Fusion")
168169
app.setPalette(guiparts.DarkPalette())
169-
MainW(image=image, logger=logger)
170+
MainW(image=image, logger=logging.getLogger(__name__))
170171
ret = app.exec_()
171172
sys.exit(ret)
172173

@@ -1242,7 +1243,7 @@ def remove_single_cell(self, idx):
12421243
self.ismanual = np.delete(self.ismanual, idx - 1)
12431244
self.cellcolors = np.delete(self.cellcolors, [idx], axis=0)
12441245
del self.zdraw[idx - 1]
1245-
print("GUI_INFO: removed cell %d" % (idx - 1))
1246+
self.logger.info(f'removed cell {idx-1}')
12461247

12471248
def remove_region_cells(self):
12481249
if self.removing_cells_list:

cellpose/gui/guiparts.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import numpy as np
99
import pathlib, os
1010

11+
from cellpose.gui.io import _save_sets
12+
1113

1214
def stylesheet():
1315
return """
@@ -628,8 +630,11 @@ def __init__(self, image=None, viewbox=None, parent=None, **kargs):
628630
self.parent.in_stroke = False
629631

630632
def mouseClickEvent(self, ev):
631-
if (self.parent.masksOn or
632-
self.parent.outlinesOn) and not self.parent.removing_region:
633+
if not (self.parent.masksOn or
634+
self.parent.outlinesOn) and self.parent.removing_region:
635+
return
636+
637+
try:
633638
is_right_click = ev.button() == QtCore.Qt.RightButton
634639
if self.parent.loaded \
635640
and (is_right_click or ev.modifiers() & QtCore.Qt.ShiftModifier and not ev.double())\
@@ -665,9 +670,12 @@ def mouseClickEvent(self, ev):
665670
else:
666671
self.parent.select_cell_multi(idx)
667672
self.parent.removing_cells_list.append(idx)
668-
669673
elif self.parent.masksOn and not self.parent.deleting_multiple:
670674
self.parent.unselect_cell()
675+
except Exception as err:
676+
print('Error encountered while drawing. Saving masks and exiting...')
677+
_save_sets(self.parent)
678+
raise(err)
671679

672680
def mouseDragEvent(self, ev):
673681
ev.ignore()
@@ -713,7 +721,9 @@ def is_at_start(self, pos):
713721
return False
714722

715723
def end_stroke(self):
716-
self.parent.p0.removeItem(self.scatter)
724+
if hasattr(self, 'scatter') and self.scatter is not None:
725+
if self.scatter.scene() == self.parent.layer.scene():
726+
self.parent.p0.removeItem(self.scatter)
717727
if not self.parent.stroke_appended:
718728
self.parent.strokes.append(self.parent.current_stroke)
719729
self.parent.stroke_appended = True

cellpose/gui/io.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def _initialize_images(parent, image, load_3D=False):
170170
load_3D = parent.load_3D if load_3D is False else load_3D
171171

172172
parent.stack = image
173-
print(f"GUI_INFO: image shape: {image.shape}")
173+
parent.logger.info(f" : image shape: {image.shape}")
174174
if load_3D:
175175
parent.NZ = len(parent.stack)
176176
parent.scroll.setMaximum(parent.NZ - 1)
@@ -187,7 +187,7 @@ def _initialize_images(parent, image, load_3D=False):
187187
parent.stack *= 255
188188

189189
if load_3D:
190-
print("GUI_INFO: converted to float and normalized values to 0.0->255.0")
190+
parent.logger.info(": converted to float and normalized values to 0.0->255.0")
191191

192192
del image
193193
gc.collect()
@@ -205,13 +205,15 @@ def _initialize_images(parent, image, load_3D=False):
205205
parent.Lyr, parent.Lxr = parent.Ly, parent.Lx
206206
parent.clear_all()
207207

208+
if not hasattr(parent, "stack_filtered") and parent.restore:
209+
parent.logger.info(": no 'img_restore' found, applying current settings")
210+
parent.compute_restore()
211+
208212
if parent.autobtn.isChecked():
209213
if parent.restore is None or parent.restore != "filter":
210-
print(
211-
"GUI_INFO: normalization checked: computing saturation levels (and optionally filtered image)"
212-
)
214+
parent.logger.info(": normalization checked: computing saturation levels (and optionally filtered image)")
213215
parent.compute_saturation()
214-
216+
215217
parent.compute_scale()
216218
parent.track_changes = []
217219

@@ -312,7 +314,7 @@ def _load_seg(parent, filename=None, image=None, image_file=None, load_3D=False)
312314

313315
if "manual_changes" in dat:
314316
parent.track_changes = dat["manual_changes"]
315-
print("GUI_INFO: loaded in previous changes")
317+
parent.logger.info("loaded in previous changes")
316318
if "zdraw" in dat:
317319
parent.zdraw = dat["zdraw"]
318320
else:
@@ -398,7 +400,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
398400
# get unique values
399401
shape = masks.shape
400402
if len(fastremap.unique(masks)) != masks.max() + 1:
401-
print("GUI_INFO: renumbering masks")
403+
parent.logger.info("renumbering masks")
402404
fastremap.renumber(masks, in_place=True)
403405
outlines = None
404406
masks = masks.reshape(shape)
@@ -423,7 +425,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
423425
if parent.cellpix_orig.ndim == 2:
424426
parent.cellpix_orig = parent.cellpix_orig[np.newaxis, :, :]
425427

426-
print(f"GUI_INFO: {masks.max()} masks found")
428+
parent.logger.info(f"{masks.max()} masks found")
427429

428430
# get outlines
429431
if outlines is None: # parent.outlinesOn
@@ -437,7 +439,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
437439
outlines = masks_to_outlines(parent.cellpix_orig[z])
438440
parent.outpix_orig[z] = outlines * parent.cellpix_orig[z]
439441
if z % 50 == 0 and parent.NZ > 1:
440-
print("GUI_INFO: plane %d outlines processed" % z)
442+
parent.logger.info("plane %d outlines processed" % z)
441443
if parent.restore and "upsample" in parent.restore:
442444
parent.outpix_resize = parent.outpix.copy()
443445
else:
@@ -449,7 +451,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
449451
outlines = masks_to_outlines(parent.cellpix_orig[z])
450452
parent.outpix_orig[z] = outlines * parent.cellpix_orig[z]
451453
if z % 50 == 0 and parent.NZ > 1:
452-
print("GUI_INFO: plane %d outlines processed" % z)
454+
parent.logger.info("plane %d outlines processed" % z)
453455

454456
if parent.outpix.ndim == 2:
455457
parent.outpix = parent.outpix[np.newaxis, :, :]
@@ -461,7 +463,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
461463

462464
parent.ncells.set(parent.cellpix.max())
463465
colors = parent.colormap[:parent.ncells.get(), :3] if colors is None else colors
464-
print("GUI_INFO: creating cellcolors and drawing masks")
466+
parent.logger.info("creating cellcolors and drawing masks")
465467
parent.cellcolors = np.concatenate((np.array([[255, 255, 255]]), colors),
466468
axis=0).astype(np.uint8)
467469
if parent.ncells > 0:
@@ -483,28 +485,28 @@ def _save_png(parent):
483485
base = os.path.splitext(filename)[0]
484486
if parent.NZ == 1:
485487
if parent.cellpix[0].max() > 65534:
486-
print("GUI_INFO: saving 2D masks to tif (too many masks for PNG)")
488+
parent.logger.info("saving 2D masks to tif (too many masks for PNG)")
487489
imsave(base + "_cp_masks.tif", parent.cellpix[0])
488490
else:
489-
print("GUI_INFO: saving 2D masks to png")
491+
parent.logger.info("saving 2D masks to png")
490492
imsave(base + "_cp_masks.png", parent.cellpix[0].astype(np.uint16))
491493
else:
492-
print("GUI_INFO: saving 3D masks to tiff")
494+
parent.logger.info("saving 3D masks to tiff")
493495
imsave(base + "_cp_masks.tif", parent.cellpix)
494496

495497

496498
def _save_flows(parent):
497499
""" save flows and cellprob to tiff """
498500
filename = parent.filename
499501
base = os.path.splitext(filename)[0]
500-
print("GUI_INFO: saving flows and cellprob to tiff")
502+
parent.logger.info("saving flows and cellprob to tiff")
501503
if len(parent.flows) > 0:
502504
imsave(base + "_cp_cellprob.tif", parent.flows[1])
503505
for i in range(3):
504506
imsave(base + f"_cp_flows_{i}.tif", parent.flows[0][..., i])
505507
if len(parent.flows) > 2:
506508
imsave(base + "_cp_flows.tif", parent.flows[2])
507-
print("GUI_INFO: saved flows and cellprob")
509+
parent.logger.info("saved flows and cellprob")
508510
else:
509511
print("ERROR: no flows or cellprob found")
510512

@@ -620,7 +622,7 @@ def _save_sets(parent):
620622
dat["img_restore"] = parent.stack_filtered
621623
try:
622624
np.save(base + "_seg.npy", dat)
623-
print("GUI_INFO: %d ROIs saved to %s" % (parent.ncells.get(), base + "_seg.npy"))
625+
parent.logger.info("%d ROIs saved to %s" % (parent.ncells.get(), base + "_seg.npy"))
624626
except Exception as e:
625627
print(f"ERROR: {e}")
626628
del dat

cellpose/io.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,30 @@ def logger_setup(cp_path=".cellpose", logfile_name="run.log", stdout_file_replac
8181
log_file.unlink()
8282
except:
8383
print('creating new log file')
84-
handlers = [logging.FileHandler(log_file),]
84+
logfile_fh = logging.FileHandler(log_file)
8585
if stdout_file_replacement is not None:
86-
handlers.append(logging.FileHandler(stdout_file_replacement))
86+
stdout_fh = logging.FileHandler(stdout_file_replacement)
8787
else:
88-
handlers.append(logging.StreamHandler(sys.stdout))
89-
logging.basicConfig(
90-
level=logging.INFO,
91-
format="%(asctime)s [%(levelname)s] %(message)s",
92-
handlers=handlers,
93-
force=True
94-
)
95-
logger = logging.getLogger(__name__)
88+
stdout_fh = logging.StreamHandler(sys.stdout)
89+
90+
formatter = logging.Formatter("%(asctime)s [%(module)s %(levelname)s] %(message)s")
91+
debug_formatter = logging.Formatter("%(asctime)s %(levelname)s [%(filename)s:%(lineno)d - %(funcName)20s()] %(message)s")
92+
logger = logging.getLogger('cellpose')
93+
logger.setLevel(logging.INFO)
94+
logger.handlers.clear()
95+
96+
logfile_fh.setFormatter(debug_formatter)
97+
logfile_fh.setLevel(logging.DEBUG)
98+
logger.addHandler(logfile_fh)
99+
100+
stdout_fh.setFormatter(formatter)
101+
stdout_fh.setLevel(logging.INFO)
102+
logger.addHandler(stdout_fh)
103+
104+
logger.propagate = False
105+
106+
print(f"[GUI INFO] : WRITING LOG OUTPUT TO {log_file}")
107+
print(version_str)
96108
logger.info(f"WRITING LOG OUTPUT TO {log_file}")
97109
logger.info(version_str)
98110

0 commit comments

Comments
 (0)