Skip to content

Commit f8ec229

Browse files
Normalisation and core finding improved
1 parent 80d98ab commit f8ec229

6 files changed

Lines changed: 336 additions & 183 deletions

File tree

docs/source/pybundle_class.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ for a detailed description of each option's meaning.
2727
* coreMethod = None (``set_core_method``)
2828
* outputType = 'float64' (``set_output_type``)
2929

30-
**CROP/MASK Settings (for FILTER/EDGE_FILTER only):**
30+
**CROP/MASK Settings:**
3131

3232
* applyMask = False (``set_apply_mask``)
3333
* autoMask = True (``set_auto_mask``)
3434
* autoLoc = False (``set_auto_loc``)
3535
* crop = False(``set_crop``)
3636
* loc = None (``set_loc``)
3737
* mask = None (``set_mask``)
38-
38+
* radius = None (``set_radius``)
3939

4040
**CALIB/BACKGROUND/NORMALISATION Settings:**
4141

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
66

77
[project]
88
name = "PyFibreBundle"
9-
version = "1.3.1"
9+
version = "1.3.2"
1010
description = "Image processing of images acquired through fibre imaging bundle, including core removal, mosaicing and super-resolution.."
1111
readme = "README.md"
1212
authors = [{ name = "Michael Hughes", email = "m.r.hughes@kent.ac.uk" }]

src/pybundle/core.py

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,9 @@ def find_bundle(img, **kwargs):
260260

261261

262262
def crop_rect(img, loc):
263-
"""Extracts a square around the bundle using specified co-ordinates.
263+
"""Extracts a square around the bundle using specified co-ordinates. If the
264+
rectange is larger than the image then the returned image will be a rectangle,
265+
limited by the extent of the image.
264266
265267
Returns tuple of (cropped image as 2D numpy array, new location tuple)
266268
@@ -269,16 +271,27 @@ def crop_rect(img, loc):
269271
loc : location to crop, specified as bundle location tuple of
270272
(centreX, centreY, radius)
271273
"""
272-
273-
cx,cy, rad = loc
274-
imgCrop = img[cy-rad:cy+ rad, cx-rad:cx+rad]
275-
276-
# Correct the co-ordinates of the bundle so that they
277-
# are correct for new cropped image
278-
newLoc = [rad,rad,loc[2]]
279-
280-
return imgCrop, newLoc
281-
274+
if loc is not None:
275+
276+
h,w = np.shape(img)[:2]
277+
cx,cy, rad = loc
278+
279+
minX = np.clip(cx-rad, 0, None)
280+
maxX = np.clip(cx+rad, None, w)
281+
282+
283+
minY = np.clip(cy-rad, 0, None)
284+
maxY = np.clip(cy+rad, None, h)
285+
286+
imgCrop = img[minY:maxY, minX: maxX]
287+
288+
# Correct the co-ordinates of the bundle so that they
289+
# are correct for new cropped image
290+
newLoc = [rad,rad,loc[2]]
291+
292+
return imgCrop, newLoc
293+
else:
294+
return img, None
282295

283296

284297

@@ -314,14 +327,17 @@ def apply_mask(img, mask):
314327
with areas to be kept as 1 and areas to be masked as 0.
315328
"""
316329

317-
if img.ndim == 3:
318-
m = np.expand_dims(mask, 2)
330+
if mask is not None:
331+
if img.ndim == 3:
332+
m = np.expand_dims(mask, 2)
333+
else:
334+
m = mask
335+
imgMasked = np.multiply(img, m)
336+
337+
return imgMasked
319338
else:
320-
m = mask
321-
imgMasked = np.multiply(img, m)
339+
return img
322340

323-
return imgMasked
324-
325341

326342
def auto_mask(img, loc = None, **kwargs):
327343
""" Locates bundle and sets pixels outside to 0 .
@@ -332,13 +348,24 @@ def auto_mask(img, loc = None, **kwargs):
332348
Keyword Arguments:
333349
loc : optional location of bundle as tuple of (centreX, centreY, radius),
334350
defaults to determining this using find_bundle
351+
radius : optional, int, radius of mask to use rather than the automatically
352+
determined radius
335353
Others : if loc is not specified, other optional keyword arguments will
336354
be passed to find_bundle.
337355
338356
339357
"""
358+
radius = kwargs.get('radius', None)
359+
360+
# If location not specified, find it
340361
if loc is None:
341362
loc = pybundle.find_bundle(img, **kwargs)
363+
364+
# If radius was specified, replace auto determined radius
365+
if radius is not None:
366+
loc = (loc[0], loc[1], radius)
367+
368+
# Mask image
342369
mask = pybundle.get_mask(img, loc)
343370
imgMasked = pybundle.apply_mask(img, mask)
344371

src/pybundle/core_interpolation.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import math
1515
import time
1616

17+
18+
import matplotlib.pyplot as plt
19+
1720
import cv2 as cv
1821

1922
from scipy.spatial import Delaunay
@@ -53,15 +56,18 @@ def find_cores(img, coreSpacing):
5356
# If a colour image, convert to greyscale by taking the maximum value across the channels
5457
imgF = pybundle.max_channels(imgF)
5558

56-
imgF = (imgF / np.max(imgF) * 255).astype('uint8')
59+
imgF = (imgF / np.max(imgF) * 255).astype('uint8')
5760

5861
# Find regional maximum by taking difference between dilated and original
5962
# image. Because of the way dilation works, the local maxima are not changed
6063
# and so these will have a value of 0
61-
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (coreSpacing,coreSpacing))
64+
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (int(round(coreSpacing)),int(round(coreSpacing)) ))
65+
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (3,3 ))
66+
6267
imgD = cv.dilate(imgF, kernel)
68+
6369
imgMax = 255 - (imgF - imgD) # we need to invert the image
64-
70+
6571
# Just keep the maxima
6672
thres, imgBinary = cv.threshold(imgMax, 0,1,cv.THRESH_BINARY+cv.THRESH_OTSU)
6773

@@ -117,9 +123,10 @@ def core_values(img, coreX, coreY, filterSize, **kwargs):
117123

118124
if filterSize is not None:
119125
img = pybundle.g_filter(img, filterSize)
120-
121-
if numba and numbaAvailable:
122-
cInt = core_value_extract_numba(img, coreX, coreY)
126+
127+
cInt = np.zeros(np.shape(coreX))
128+
if numba and numbaAvailable:
129+
cInt = cInt + core_value_extract_numba(img, coreX, coreY)
123130
else:
124131
cInt = img[coreY, coreX]
125132

@@ -156,29 +163,31 @@ def calib_tri_interp(img, coreSize, gridSize, **kwargs):
156163
spurious core detections outside of bundle, defualts to True
157164
mask : optional, boolean, when reconstructing output image will be masked outside of
158165
bundle, defaults to True
166+
159167
"""
160168

161-
centreX = kwargs.get('centreX', -1)
162-
centreY = kwargs.get('centreY', -1)
163-
radius = kwargs.get('radius', -1)
169+
centreX = kwargs.get('centreX', None)
170+
centreY = kwargs.get('centreY', None)
171+
radius = kwargs.get('radius', None)
164172
filterSize = kwargs.get('filterSize', 0)
165173
normalise = kwargs.get('normalise', None)
166174
autoMask = kwargs.get('autoMask', True)
167175
mask = kwargs.get('mask', True)
168176
background = kwargs.get('background', None)
177+
169178
if autoMask:
170-
img = pybundle.auto_mask(img)
179+
img = pybundle.auto_mask(img, radius = radius)
171180
# Find the cores in the calibration image
172181
coreX, coreY = pybundle.find_cores(img, coreSize)
173182
coreX = np.round(coreX).astype('uint16')
174183
coreY = np.round(coreY).astype('uint16')
175184

176185
# Default values
177-
if centreX < 0:
186+
if centreX is None:
178187
centreX = np.mean(coreX)
179-
if centreY < 0:
188+
if centreY is None:
180189
centreY = np.mean(coreY)
181-
if radius < 0:
190+
if radius is None:
182191
dist = np.sqrt((coreX - centreX)**2 + (coreY - centreY)**2)
183192
radius = max(dist)
184193

@@ -385,9 +394,10 @@ def recon_tri_interp(img, calib, **kwargs):
385394
numba = kwargs.get('numba', True)
386395

387396
# Extract intensity from each core
397+
t1 = time.perf_counter()
388398
cVals = pybundle.core_values(
389399
img, calib.coreX, calib.coreY, calib.filterSize, **kwargs).astype('float64')
390-
400+
391401
if calib.background is not None:
392402
cVals = cVals - calib.backgroundVals
393403

0 commit comments

Comments
 (0)