Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cellpose/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
from cellpose.version import version, version_str
import logging

# set base `cellpose` logger
logging.getLogger(__name__).addHandler(logging.NullHandler())
7 changes: 4 additions & 3 deletions cellpose/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Copyright © 2025 Howard Hughes Medical Institute, Authored by Carsen Stringer, Michael Rariden and Marius Pachitariu.
"""

import logging
import sys, os, pathlib, warnings, datetime, time, copy

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

def run(image=None):
from ..io import logger_setup
logger, log_file = logger_setup()
logger_setup()
# Always start by initializing Qt (only once per application)
warnings.filterwarnings("ignore")
app = QApplication(sys.argv)
Expand Down Expand Up @@ -166,7 +167,7 @@ def run(image=None):
app.setWindowIcon(app_icon)
app.setStyle("Fusion")
app.setPalette(guiparts.DarkPalette())
MainW(image=image, logger=logger)
MainW(image=image, logger=logging.getLogger(__name__))
ret = app.exec_()
sys.exit(ret)

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

def remove_region_cells(self):
if self.removing_cells_list:
Expand Down
18 changes: 14 additions & 4 deletions cellpose/gui/guiparts.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import numpy as np
import pathlib, os

from cellpose.gui.io import _save_sets


def stylesheet():
return """
Expand Down Expand Up @@ -628,8 +630,11 @@ def __init__(self, image=None, viewbox=None, parent=None, **kargs):
self.parent.in_stroke = False

def mouseClickEvent(self, ev):
if (self.parent.masksOn or
self.parent.outlinesOn) and not self.parent.removing_region:
if not (self.parent.masksOn or
self.parent.outlinesOn) and self.parent.removing_region:
return

try:
is_right_click = ev.button() == QtCore.Qt.RightButton
if self.parent.loaded \
and (is_right_click or ev.modifiers() & QtCore.Qt.ShiftModifier and not ev.double())\
Expand Down Expand Up @@ -665,9 +670,12 @@ def mouseClickEvent(self, ev):
else:
self.parent.select_cell_multi(idx)
self.parent.removing_cells_list.append(idx)

elif self.parent.masksOn and not self.parent.deleting_multiple:
self.parent.unselect_cell()
except Exception as err:
print('Error encountered while drawing. Saving masks and exiting...')
_save_sets(self.parent)
raise(err)

def mouseDragEvent(self, ev):
ev.ignore()
Expand Down Expand Up @@ -713,7 +721,9 @@ def is_at_start(self, pos):
return False

def end_stroke(self):
self.parent.p0.removeItem(self.scatter)
if hasattr(self, 'scatter') and self.scatter is not None:
if self.scatter.scene() == self.parent.layer.scene():
self.parent.p0.removeItem(self.scatter)
if not self.parent.stroke_appended:
self.parent.strokes.append(self.parent.current_stroke)
self.parent.stroke_appended = True
Expand Down
38 changes: 20 additions & 18 deletions cellpose/gui/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _initialize_images(parent, image, load_3D=False):
load_3D = parent.load_3D if load_3D is False else load_3D

parent.stack = image
print(f"GUI_INFO: image shape: {image.shape}")
parent.logger.info(f" : image shape: {image.shape}")
if load_3D:
parent.NZ = len(parent.stack)
parent.scroll.setMaximum(parent.NZ - 1)
Expand All @@ -187,7 +187,7 @@ def _initialize_images(parent, image, load_3D=False):
parent.stack *= 255

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

del image
gc.collect()
Expand All @@ -205,13 +205,15 @@ def _initialize_images(parent, image, load_3D=False):
parent.Lyr, parent.Lxr = parent.Ly, parent.Lx
parent.clear_all()

if not hasattr(parent, "stack_filtered") and parent.restore:
parent.logger.info(": no 'img_restore' found, applying current settings")
parent.compute_restore()

if parent.autobtn.isChecked():
if parent.restore is None or parent.restore != "filter":
print(
"GUI_INFO: normalization checked: computing saturation levels (and optionally filtered image)"
)
parent.logger.info(": normalization checked: computing saturation levels (and optionally filtered image)")
parent.compute_saturation()

parent.compute_scale()
parent.track_changes = []

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

if "manual_changes" in dat:
parent.track_changes = dat["manual_changes"]
print("GUI_INFO: loaded in previous changes")
parent.logger.info("loaded in previous changes")
if "zdraw" in dat:
parent.zdraw = dat["zdraw"]
else:
Expand Down Expand Up @@ -398,7 +400,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
# get unique values
shape = masks.shape
if len(fastremap.unique(masks)) != masks.max() + 1:
print("GUI_INFO: renumbering masks")
parent.logger.info("renumbering masks")
fastremap.renumber(masks, in_place=True)
outlines = None
masks = masks.reshape(shape)
Expand All @@ -423,7 +425,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
if parent.cellpix_orig.ndim == 2:
parent.cellpix_orig = parent.cellpix_orig[np.newaxis, :, :]

print(f"GUI_INFO: {masks.max()} masks found")
parent.logger.info(f"{masks.max()} masks found")

# get outlines
if outlines is None: # parent.outlinesOn
Expand All @@ -437,7 +439,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
outlines = masks_to_outlines(parent.cellpix_orig[z])
parent.outpix_orig[z] = outlines * parent.cellpix_orig[z]
if z % 50 == 0 and parent.NZ > 1:
print("GUI_INFO: plane %d outlines processed" % z)
parent.logger.info("plane %d outlines processed" % z)
if parent.restore and "upsample" in parent.restore:
parent.outpix_resize = parent.outpix.copy()
else:
Expand All @@ -449,7 +451,7 @@ def _masks_to_gui(parent, masks, outlines=None, colors=None):
outlines = masks_to_outlines(parent.cellpix_orig[z])
parent.outpix_orig[z] = outlines * parent.cellpix_orig[z]
if z % 50 == 0 and parent.NZ > 1:
print("GUI_INFO: plane %d outlines processed" % z)
parent.logger.info("plane %d outlines processed" % z)

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

parent.ncells.set(parent.cellpix.max())
colors = parent.colormap[:parent.ncells.get(), :3] if colors is None else colors
print("GUI_INFO: creating cellcolors and drawing masks")
parent.logger.info("creating cellcolors and drawing masks")
parent.cellcolors = np.concatenate((np.array([[255, 255, 255]]), colors),
axis=0).astype(np.uint8)
if parent.ncells > 0:
Expand All @@ -483,28 +485,28 @@ def _save_png(parent):
base = os.path.splitext(filename)[0]
if parent.NZ == 1:
if parent.cellpix[0].max() > 65534:
print("GUI_INFO: saving 2D masks to tif (too many masks for PNG)")
parent.logger.info("saving 2D masks to tif (too many masks for PNG)")
imsave(base + "_cp_masks.tif", parent.cellpix[0])
else:
print("GUI_INFO: saving 2D masks to png")
parent.logger.info("saving 2D masks to png")
imsave(base + "_cp_masks.png", parent.cellpix[0].astype(np.uint16))
else:
print("GUI_INFO: saving 3D masks to tiff")
parent.logger.info("saving 3D masks to tiff")
imsave(base + "_cp_masks.tif", parent.cellpix)


def _save_flows(parent):
""" save flows and cellprob to tiff """
filename = parent.filename
base = os.path.splitext(filename)[0]
print("GUI_INFO: saving flows and cellprob to tiff")
parent.logger.info("saving flows and cellprob to tiff")
if len(parent.flows) > 0:
imsave(base + "_cp_cellprob.tif", parent.flows[1])
for i in range(3):
imsave(base + f"_cp_flows_{i}.tif", parent.flows[0][..., i])
if len(parent.flows) > 2:
imsave(base + "_cp_flows.tif", parent.flows[2])
print("GUI_INFO: saved flows and cellprob")
parent.logger.info("saved flows and cellprob")
else:
print("ERROR: no flows or cellprob found")

Expand Down Expand Up @@ -620,7 +622,7 @@ def _save_sets(parent):
dat["img_restore"] = parent.stack_filtered
try:
np.save(base + "_seg.npy", dat)
print("GUI_INFO: %d ROIs saved to %s" % (parent.ncells.get(), base + "_seg.npy"))
parent.logger.info("%d ROIs saved to %s" % (parent.ncells.get(), base + "_seg.npy"))
except Exception as e:
print(f"ERROR: {e}")
del dat
32 changes: 22 additions & 10 deletions cellpose/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,30 @@ def logger_setup(cp_path=".cellpose", logfile_name="run.log", stdout_file_replac
log_file.unlink()
except:
print('creating new log file')
handlers = [logging.FileHandler(log_file),]
logfile_fh = logging.FileHandler(log_file)
if stdout_file_replacement is not None:
handlers.append(logging.FileHandler(stdout_file_replacement))
stdout_fh = logging.FileHandler(stdout_file_replacement)
else:
handlers.append(logging.StreamHandler(sys.stdout))
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=handlers,
force=True
)
logger = logging.getLogger(__name__)
stdout_fh = logging.StreamHandler(sys.stdout)

formatter = logging.Formatter("%(asctime)s [%(module)s %(levelname)s] %(message)s")
debug_formatter = logging.Formatter("%(asctime)s %(levelname)s [%(filename)s:%(lineno)d - %(funcName)20s()] %(message)s")
logger = logging.getLogger('cellpose')
logger.setLevel(logging.INFO)
logger.handlers.clear()

logfile_fh.setFormatter(debug_formatter)
logfile_fh.setLevel(logging.DEBUG)
logger.addHandler(logfile_fh)

stdout_fh.setFormatter(formatter)
stdout_fh.setLevel(logging.INFO)
logger.addHandler(stdout_fh)

logger.propagate = False

print(f"[GUI INFO] : WRITING LOG OUTPUT TO {log_file}")
print(version_str)
logger.info(f"WRITING LOG OUTPUT TO {log_file}")
logger.info(version_str)

Expand Down
Loading