Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Oct 25, 2017
2 parents dd29d47 + ec345ec commit 21a653a
Show file tree
Hide file tree
Showing 12 changed files with 615 additions and 207 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
LLSpy Release History
#####################

`0.3.3`_
========

**Added:**

* exposed "min bead number" parameter for automated bead detection in the gui, as well as manual intensity threshold.
* alert when automated bead detection gives suspicious results (dramatically different number of beads in each channel).
* ability to undo "Rename Scriped" (rename_iters function), under Process Menu

**Changed:**

* more robust settings.txt file parsing (thanks for sample Carlos!)
* refactored the rename_iters function to be more robust
* slightly stricter OTF file naming regex. updated docs accordingly

**Fixed:**

* fixed "invalid literal for int() with base 10" bug in refRegWave validation
* (hopefully) fixed bug that bugs you to update llspy_extra when you've already done it. If this still fails, consider reinstalling (deleting your 'llsenv' anaconda environment and starting again with a fresh one).

`0.3.2`_
========

Expand Down Expand Up @@ -143,6 +163,7 @@ LLSpy Release History

.. _Next release: https://github.com/tlambert03/LLSpy/

.. _0.3.3: https://github.com/tlambert03/LLSpy/releases/0.3.3
.. _0.3.2: https://github.com/tlambert03/LLSpy/releases/0.3.2
.. _0.3.1: https://github.com/tlambert03/LLSpy/releases/0.3.1
.. _0.3.0: https://github.com/tlambert03/LLSpy/releases/0.3.0
Expand Down
4 changes: 2 additions & 2 deletions docs/main.rst
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ For greater convenience and sophistication, you can also place raw PSF files in
psffile_pattern = re.compile(r"""
^(?P<date>\d{6}|\d{8}) # 6 or 8 digit date
_(?P<wave>\d+).* # wavelength ... only digits following _ are used
_(?P<slmpattern>[a-zA-Z_]*) # slm pattern
_(?P<wave>\d+) # wavelength ... only digits following _ are used
_(?P<slmpattern>[a-zA-Z]+) # slm pattern
_(?P<outerNA>[0-9p.]+) # outer NA, digits with . or p for decimal
[-_](?P<innerNA>[0-9p.]+) # inter NA, digits with . or p for decimal
(?P<isotf>_otf)?.tif$""", # optional _otf to specify that it is already an otf
Expand Down
55 changes: 37 additions & 18 deletions fiducialreg/fiducialreg.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
# to a stack from the 488 channel...
>>> out = affine(im560, 560_to_488_rigid)
"""
from __future__ import print_function
from __future__ import print_function, division

from scipy import ndimage, optimize, stats
from os import path as osp
Expand Down Expand Up @@ -73,7 +73,7 @@ def bead_centroids(img, labeled, nlabels):
return [ndimage.center_of_mass(img, labeled, l) for l in range(1, nlabels + 1)]


def get_thresh(im, mincount=20, steps=100):
def get_thresh(im, mincount=None, steps=100):
"""intelligently find coordinates of local maxima in an image
by searching a range of threshold parameters to find_local_maxima
Expand All @@ -86,10 +86,16 @@ def get_thresh(im, mincount=20, steps=100):
"""
if im.ndim == 3:
im = im.max(0)
if mincount is None:
mincount = 20
threshrange = np.linspace(im.min(), im.max(), steps)
object_count = [ndimage.label(im > t)[1] for t in threshrange]
object_count = np.array(object_count)
modecount = stats.mode(object_count[(object_count > mincount)], axis=None)[0][0]
if mincount > object_count.max():
raise RegistrationError(
'Could not detect minimum number of beads specified ({}), found: {}'.format(
mincount, object_count.max()))
modecount = stats.mode(object_count[(object_count >= mincount)], axis=None).mode[0]
logging.debug('Threshold detected: {}'.format(threshrange[np.argmax(object_count == modecount)]))
return threshrange[np.argmax(object_count == modecount)], modecount

Expand Down Expand Up @@ -457,7 +463,7 @@ class FiducialCloud(object):
"""
def __init__(self, data=None, dz=1, dx=1, blurxysig=1, blurzsig=2.5,
threshold='auto', mincount=20, imref=None, filtertype='blur'):
threshold=None, mincount=None, imref=None, filtertype='blur'):
# data is a numpy array or filename
self.data = None
if data is not None:
Expand All @@ -480,7 +486,7 @@ def __init__(self, data=None, dz=1, dx=1, blurxysig=1, blurzsig=2.5,
self.dz = dz
self.blurxysig = blurxysig
self.blurzsig = blurzsig
self.threshold = threshold
self.threshold = threshold if threshold is not None else 'auto'
self._mincount = mincount
self.imref = imref
self.coords = None
Expand Down Expand Up @@ -536,11 +542,16 @@ def update_coords(self, thresh=None):
return
if thresh is None:
thresh = self.threshold
if thresh == 'auto':
if thresh == 'auto' or not thresh:
thresh = self.autothresh()
try:
thresh = float(thresh)
assert thresh > 0
except Exception:
raise RegistrationError('Threshold must be number greater than 0. got: {}'.format(thresh))
logger.debug('Update_coords using threshold: {}'.format(thresh))
labeled = ndimage.label(self.filtered > thresh)[0]
objects = ndimage.find_objects(labeled)

# FIXME: pass sigmas to wx and wz parameters of GaussFitter
fitter = GaussFitter3D(self.data, dz=self.dz, dx=self.dx)
gaussfits = []
Expand All @@ -560,6 +571,9 @@ def update_coords(self, thresh=None):
if not len(self.coords):
logging.warning('PointCloud has no points! {}'.format(
self.filename if 'filename' in dir(self) else ''))
else:
logger.info("Registration found {} objects".format(self.count))


@property
def coords_inworld(self):
Expand Down Expand Up @@ -615,7 +629,7 @@ class CloudSet(object):
"""

def __init__(self, data=None, labels=None, dx=1, dz=1, **kwargs):
def __init__(self, data=None, labels=None, dx=1, dz=1, mincount=None, threshold=None, **kwargs):
self.dx = dx
self.dz = dz
if data is not None:
Expand All @@ -632,8 +646,9 @@ def __init__(self, data=None, labels=None, dx=1, dz=1, **kwargs):
self.N = len(data)
self.clouds = []
for i, d in enumerate(data):
logger.debug("Creating FiducalCloud for label: {}".format(self.labels[i]))
self.clouds.append(FiducialCloud(d, dx=self.dx, dz=self.dz, **kwargs))
logger.info("Creating FiducalCloud for label: {}".format(self.labels[i]))
self.clouds.append(FiducialCloud(d, dx=self.dx, dz=self.dz,
threshold=threshold, mincount=mincount, **kwargs))
else:
self.clouds = []
self.N = 0
Expand Down Expand Up @@ -769,13 +784,17 @@ def get_all_tforms(self, refs=None, inworld=True,
D = []
for moving, fixed in pairings:
for mode in modes:
D.append({
'mode': mode,
'reference': fixed,
'moving': moving,
'inworld': inworld,
'tform': self.tform(moving, fixed, mode, inworld=inworld)
})
try:
D.append({
'mode': mode,
'reference': fixed,
'moving': moving,
'inworld': inworld,
'tform': self.tform(moving, fixed, mode, inworld=inworld)
})
except Exception:
print("SKIPPING MODE: ", mode)
logger.error('Failed to calculate mode "{}" in get_all_tforms. Skipping.'.format(mode))
return D

def write_all_tforms(self, outfile, **kwargs):
Expand Down Expand Up @@ -868,7 +887,7 @@ def tform(self, movingLabel=None, fixedLabel=None, mode='2step',
moving = matching[movIdx]
fixed = matching[fixIdx]
tform = funcDict[mode](moving, fixed)
logger.debug('Measured {} Tform Matrix {}inWorld:\n'.format(mode, '' if inworld else 'not ' ) +
logger.info('Measured {} Tform Matrix {}inWorld:\n'.format(mode, '' if inworld else 'not ' ) +
str(tform))
return tform
else:
Expand Down
5 changes: 4 additions & 1 deletion llspy/gui/guiDefaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,7 @@ prevBackendSpimagineRadio=true
prevBackendMatplotlibRadio=false
confirmOnQuitCheckBox=true
errorOptOutCheckBox=false
reprocessCheckBox=true
reprocessCheckBox=true
RegMinBeadsSpin=20
RegBeadThreshSpin=1000
RegAutoThreshCheckbox=true
Loading

0 comments on commit 21a653a

Please sign in to comment.