Skip to content

Commit

Permalink
reformatting gui to better support mac
Browse files Browse the repository at this point in the history
  • Loading branch information
carsen-stringer committed Aug 9, 2020
1 parent 2b5dca9 commit 0e61564
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 98 deletions.
49 changes: 4 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,51 +154,10 @@ The GUI serves two main functions:
1. Running the segmentation algorithm.
2. Manually labelling data.

Main GUI mouse controls (works in all views):

- Pan = left-click + drag
- Zoom = scroll wheel
- Full view = double left-click
- Select mask = left-click on mask
- Delete mask = Ctrl + left-click
- Start draw mask = right-click
- End draw mask = right-click, or return to circle at beginning

Overlaps in masks are NOT allowed. If you draw a mask on top of another mask, it is cropped so that it doesn't overlap with the old mask. Masks in 2D should be single strokes (if *single_stroke* is checked).

If you want to draw masks in 3D, then you can turn *single_stroke* option off and draw a stroke on each plane with the cell and then press ENTER. 3D labelling will fill in unlabelled z-planes so that you do not have to as densely label.

!NOTE!: The GUI automatically saves after you draw a mask but NOT after segmentation and NOT after 3D mask drawing (too slow). Save in the file menu or with Ctrl+S. The output file is in the same folder as the loaded image with `_seg.npy` appended.

| Keyboard shortcuts | Description |
| ------------------- | ------------------------------------------------------------------------------ |
| CTRL+H | help |
| CTRL+Z | undo previously drawn mask/stroke |
| CTRL+0 | clear all masks |
| CTRL+L | load image (can alternatively drag and drop image) |
| CTRL+S | SAVE MASKS IN IMAGE to `_seg.npy` file |
| CTRL+P | load `_seg.npy` file (note: it will load automatically with image if it exists) |
| CTRL+M | load masks file (must be same size as image with 0 for NO mask, and 1,2,3... for masks)|
| CTRL+N | load numpy stack (NOT WORKING ATM) |
| A/D or LEFT/RIGHT | cycle through images in current directory |
| W/S or UP/DOWN | change color (RGB/gray/red/green/blue) |
| PAGE-UP / PAGE-DOWN | change to flows and cell prob views (if segmentation computed) |
| , / . | increase / decrease brush size for drawing masks |
| X | turn masks ON or OFF |
| Z | toggle outlines ON or OFF |
| C | cycle through labels for image type (saved to `_seg.npy`) |

**Segmentation options**

SIZE: you can manually enter the approximate diameter for your cells, or press "calibrate" to let the model estimate it. The size is represented by a disk at the bottom of the view window (can turn this disk off by unchecking "scale disk on").

use GPU: if you have installed the cuda version of mxnet, then you can activate this, but it won't give huge speedups when running single images in the GUI.

MODEL: there is a *cytoplasm* model and a *nuclei* model, choose what you want to segment

CHAN TO SEG: this is the channel in which the cytoplasm or nuclei exist

CHAN2 (OPT): if *cytoplasm* model is chosen, then choose the nuclear channel for this option
There is a help window in the GUI that provides more instructions and
a page in the documentation [here](https://cellpose.readthedocs.io/en/latest/gui.html).
Also, if you hover over certain words in the GUI, their definitions
are revealed as tooltips.

### In a notebook

Expand Down
87 changes: 63 additions & 24 deletions cellpose/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def __init__(self, image=None):
self.l0 = QtGui.QGridLayout()
self.cwidget.setLayout(self.l0)
self.setCentralWidget(self.cwidget)
self.l0.setVerticalSpacing(4)
self.l0.setVerticalSpacing(6)

self.imask = 0

Expand Down Expand Up @@ -206,7 +206,16 @@ def help_window(self):
HW.show()

def make_buttons(self):
self.boldfont = QtGui.QFont("Arial", 10, QtGui.QFont.Bold)
label_style = """QLabel{
color: white
}
QToolTip {
background-color: black;
color: white;
border: black solid 1px
}"""
self.boldfont = QtGui.QFont("Arial", 12, QtGui.QFont.Bold)
self.medfont = QtGui.QFont("Arial", 10)
self.smallfont = QtGui.QFont("Arial", 8)
self.headings = ('color: rgb(150,255,150);')
self.dropdowns = ("color: white;"
Expand All @@ -220,13 +229,13 @@ def make_buttons(self):
label.setFont(self.boldfont)
self.l0.addWidget(label, 0,0,1,1)

label = QtGui.QLabel('[W/S]')
label.setStyleSheet('color: white')
#label.setFont(self.smallfont)
label = QtGui.QLabel('[up/down or W/S]')
label.setStyleSheet(label_style)
label.setFont(self.smallfont)
self.l0.addWidget(label, 1,0,1,1)

label = QtGui.QLabel('[pageup/down]')
label.setStyleSheet('color: white')
label.setStyleSheet(label_style)
label.setFont(self.smallfont)
self.l0.addWidget(label, 1,1,1,1)

Expand All @@ -236,6 +245,7 @@ def make_buttons(self):
self.RGBChoose = guiparts.RGBRadioButtons(self, b,1)
self.RGBDropDown = QtGui.QComboBox()
self.RGBDropDown.addItems(["RGB","gray","red","green","blue"])
self.RGBDropDown.setFont(self.medfont)
self.RGBDropDown.currentIndexChanged.connect(self.color_choose)
self.RGBDropDown.setFixedWidth(60)
self.RGBDropDown.setStyleSheet(self.dropdowns)
Expand Down Expand Up @@ -263,9 +273,11 @@ def make_buttons(self):
self.BrushChoose.currentIndexChanged.connect(self.brush_choose)
self.BrushChoose.setFixedWidth(60)
self.BrushChoose.setStyleSheet(self.dropdowns)
self.BrushChoose.setFont(self.medfont)
self.l0.addWidget(self.BrushChoose, b, 1,1,1)
label = QtGui.QLabel('brush size: [, .]')
label.setStyleSheet('color: white;')
label.setStyleSheet(label_style)
label.setFont(self.medfont)
self.l0.addWidget(label, b,0,1,1)

# cross-hair
Expand All @@ -276,13 +288,15 @@ def make_buttons(self):
# turn on draw mode
self.SCheckBox = QtGui.QCheckBox('single stroke')
self.SCheckBox.setStyleSheet(self.checkstyle)
self.SCheckBox.setFont(self.medfont)
self.SCheckBox.toggled.connect(self.autosave_on)
self.l0.addWidget(self.SCheckBox, b,0,1,2)

b+=1
# turn on crosshairs
self.CHCheckBox = QtGui.QCheckBox('cross-hairs')
self.CHCheckBox.setStyleSheet(self.checkstyle)
self.CHCheckBox.setFont(self.medfont)
self.CHCheckBox.toggled.connect(self.cross_hairs)
self.l0.addWidget(self.CHCheckBox, b,0,1,1)

Expand All @@ -292,6 +306,7 @@ def make_buttons(self):
self.masksOn = True
self.MCheckBox = QtGui.QCheckBox('MASKS ON [X]')
self.MCheckBox.setStyleSheet(self.checkstyle)
self.MCheckBox.setFont(self.medfont)
self.MCheckBox.setChecked(True)
self.MCheckBox.toggled.connect(self.toggle_masks)
self.l0.addWidget(self.MCheckBox, b,0,1,2)
Expand All @@ -301,6 +316,7 @@ def make_buttons(self):
self.outlinesOn = True
self.OCheckBox = QtGui.QCheckBox('outlines on [Z]')
self.OCheckBox.setStyleSheet(self.checkstyle)
self.OCheckBox.setFont(self.medfont)
self.OCheckBox.setChecked(True)
self.OCheckBox.toggled.connect(self.toggle_masks)
self.l0.addWidget(self.OCheckBox, b,0,1,2)
Expand All @@ -326,11 +342,14 @@ def make_buttons(self):

b+=1
self.diameter = 30
label = QtGui.QLabel('cell diameter (pix):')
label.setStyleSheet('color: white;')
label = QtGui.QLabel('cell diameter (pixels):')
label.setStyleSheet(label_style)
label.setFont(self.medfont)
label.setToolTip('you can manually enter the approximate diameter for your cells, or press “calibrate” to let the model estimate it. The size is represented by a disk at the bottom of the view window (can turn this disk of by unchecking “scale disk on”)')
self.l0.addWidget(label, b, 0,1,2)
self.Diameter = QtGui.QLineEdit()
self.Diameter.setText(str(self.diameter))
self.Diameter.setFont(self.medfont)
self.Diameter.returnPressed.connect(self.compute_scale)
self.Diameter.setFixedWidth(50)
b+=1
Expand All @@ -348,15 +367,19 @@ def make_buttons(self):
b+=1
self.scale_on = True
self.ScaleOn = QtGui.QCheckBox('scale disk on')
self.ScaleOn.setFont(self.medfont)
self.ScaleOn.setStyleSheet('color: red;')
self.ScaleOn.setChecked(True)
self.ScaleOn.setToolTip('see current diameter as red disk at bottom')
self.ScaleOn.toggled.connect(self.toggle_scale)
self.l0.addWidget(self.ScaleOn, b,0,1,2)

# use GPU
b+=1
self.useGPU = QtGui.QCheckBox('use GPU')
self.useGPU.setStyleSheet(self.checkstyle)
self.useGPU.setFont(self.medfont)
self.useGPU.setToolTip('if you have specially installed the cuda version of mxnet, then you can activate this, but it won’t give huge speedups when running single 2D images in the GUI.')
self.check_gpu()
self.l0.addWidget(self.useGPU, b,0,1,2)

Expand All @@ -368,22 +391,31 @@ def make_buttons(self):
self.ModelChoose.addItems(models)
self.ModelChoose.setFixedWidth(70)
self.ModelChoose.setStyleSheet(self.dropdowns)
self.ModelChoose.setFont(self.medfont)
self.l0.addWidget(self.ModelChoose, b, 1,1,1)
label = QtGui.QLabel('model: ')
label.setStyleSheet('color: white;')
label.setStyleSheet(label_style)
label.setFont(self.medfont)
label.setToolTip('there is a <em>cytoplasm</em> model and a <em>nuclei</em> model, choose what you want to segment')
self.l0.addWidget(label, b, 0,1,1)

b+=1
# choose channel
self.ChannelChoose = [QtGui.QComboBox(), QtGui.QComboBox()]
self.ChannelChoose[0].addItems(['gray','red','green','blue'])
self.ChannelChoose[1].addItems(['none','red','green','blue'])
cstr = ['chan to seg', 'chan2 (opt)']
cstr = ['chan to segment:', 'chan2 (optional): ']
for i in range(2):
self.ChannelChoose[i].setFixedWidth(70)
self.ChannelChoose[i].setStyleSheet(self.dropdowns)
self.ChannelChoose[i].setFont(self.medfont)
label = QtGui.QLabel(cstr[i])
label.setStyleSheet('color: white;')
label.setStyleSheet(label_style)
label.setFont(self.medfont)
if i==0:
label.setToolTip('this is the channel in which the cytoplasm or nuclei exist that you want to segment')
else:
label.setToolTip('if <em>cytoplasm</em> model is chosen, and you also have a nuclear channel, then choose the nuclear channel for this option')
self.l0.addWidget(label, b, 0,1,1)
self.l0.addWidget(self.ChannelChoose[i], b, 1,1,1)
b+=1
Expand All @@ -392,6 +424,7 @@ def make_buttons(self):
b+=1
self.invert = QtGui.QCheckBox('invert grayscale')
self.invert.setStyleSheet(self.checkstyle)
self.invert.setFont(self.medfont)
self.l0.addWidget(self.invert, b,0,1,2)

b+=1
Expand All @@ -412,7 +445,8 @@ def make_buttons(self):
b+=1
label = QtGui.QLabel('flow error threshold:')
label.setToolTip('threshold on flow error to accept for masks (set higher to get more cells)')
label.setStyleSheet('color: white;')
label.setStyleSheet(label_style)
label.setFont(self.medfont)
self.l0.addWidget(label, b, 0,1,2)

b+=1
Expand All @@ -424,11 +458,13 @@ def make_buttons(self):
self.threshslider.setValue(4)
self.l0.addWidget(self.threshslider, b, 0,1,2)
self.threshslider.valueChanged.connect(self.compute_cprob)
#self.threshslider.setEnabled(False)
self.threshslider.setStyleSheet(guiparts.horizontal_slider_style())
self.threshslider.setEnabled(False)

b+=1
label = QtGui.QLabel('cell prob threshold:')
label.setStyleSheet('color: white;')
label.setStyleSheet(label_style)
label.setFont(self.medfont)
self.l0.addWidget(label, b, 0,1,2)
label.setToolTip('cell probability threshold (set lower to get more cells)')

Expand All @@ -441,8 +477,8 @@ def make_buttons(self):
self.cellprob = 0.0
self.l0.addWidget(self.probslider, b, 0,1,2)
self.probslider.valueChanged.connect(self.compute_cprob)
#self.probslider.setEnabled(False)

self.probslider.setStyleSheet(guiparts.horizontal_slider_style())
self.probslider.setEnabled(False)

b+=1
line = QHLine()
Expand All @@ -451,6 +487,7 @@ def make_buttons(self):

self.autobtn = QtGui.QCheckBox('auto-adjust')
self.autobtn.setStyleSheet(self.checkstyle)
self.autobtn.setFont(self.medfont)
self.autobtn.setChecked(True)
self.l0.addWidget(self.autobtn, b+2,0,1,1)

Expand All @@ -469,13 +506,13 @@ def make_buttons(self):
self.slider.setTickPosition(QtGui.QSlider.TicksRight)
self.l0.addWidget(self.slider, b,1,1,1)
self.l0.setRowStretch(b, 1)

b+=2
# add z position underneath
self.currentZ = 0
label = QtGui.QLabel('Z:')
label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
label.setStyleSheet('color: white;')
label.setStyleSheet(label_style)
self.l0.addWidget(label, b, 0,1,1)
self.zpos = QtGui.QLineEdit()
self.zpos.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
Expand Down Expand Up @@ -749,7 +786,7 @@ def reset(self):
if self.autobtn.isChecked():
self.saturation = [[0,255] for n in range(self.NZ)]
self.currentZ = 0
self.flows = [[],[],[]]
self.flows = [[],[],[],[],[[]]]
self.stack = np.zeros((1,self.Ly,self.Lx,3))
# masks matrix
self.layers = 0*np.ones((1,self.Ly,self.Lx,4), np.uint8)
Expand Down Expand Up @@ -929,8 +966,8 @@ def update_plot(self):
#self.img.set_ColorMap(self.bwr)
if self.masksOn or self.outlinesOn:
self.layer.setImage(self.layers[self.currentZ], autoLevels=False)
self.slider.setLow(self.saturation[self.currentZ][0])
self.slider.setHigh(self.saturation[self.currentZ][1])
#self.slider.setLow(self.saturation[self.currentZ][0])
#self.slider.setHigh(self.saturation[self.currentZ][1])
self.win.show()
self.show()

Expand Down Expand Up @@ -1143,7 +1180,7 @@ def compute_cprob(self):

def compute_model(self):
self.progress.setValue(0)
if 1:
try:
self.clear_all()
self.flows = [[],[],[]]
self.initialize_model()
Expand Down Expand Up @@ -1198,7 +1235,9 @@ def compute_model(self):
self.progress.setValue(100)

self.toggle_server(off=True)
else:#except Exception as e:
self.threshslider.setEnabled(True)
self.probslider.setEnabled(True)
except Exception as e:
print('ERROR: %s'%e)


Expand Down

0 comments on commit 0e61564

Please sign in to comment.