Skip to content

Commit c2a71b5

Browse files
committed
Doc updates; minor style updates; fix deprecation warning
1 parent d87193f commit c2a71b5

File tree

3 files changed

+51
-50
lines changed

3 files changed

+51
-50
lines changed

imageprocessing.py

+41-41
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
* numpy
2727
* scipy
2828
* Python Image Library (PIL) or Pillow
29-
* matplotlib
30-
* imageio
29+
* matplotlib (plotAverageAmpSpec only)
30+
* imageio (plotAverageAmpSpec only)
3131
3232
"""
3333

@@ -38,11 +38,10 @@
3838
from numpy import pi
3939
from numpy.fft import fft2, ifft2, fftshift, ifftshift
4040
import scipy.ndimage
41-
import matplotlib.pyplot as plt
4241
try:
43-
import Image # will work on most installations
42+
import Image # via PIL
4443
except ImportError:
45-
from PIL import Image # if installed via pillow
44+
from PIL import Image # via pillow
4645

4746

4847
##### UTILITY FUNCTION DEFINITIONS #####
@@ -86,14 +85,10 @@ def imread(image, output_dtype=np.float64, pad_depth_channel=True,
8685
# Handle alpha channel
8786
if im.ndim == 3 and (im.shape[2] in [2,4]) and alpha_action:
8887
if alpha_action == 'remove':
89-
with warnings.catch_warnings():
90-
warnings.simplefilter('always')
91-
warnings.warn('Removing alpha channel')
88+
warnings.warn('Removing alpha channel')
9289
im = im[..., :-1]
9390
elif alpha_action == 'mask':
94-
with warnings.catch_warnings():
95-
warnings.simplefilter('always')
96-
warnings.warn('Masking by alpha channel')
91+
warnings.warn('Masking by alpha channel')
9792
orig_dtype = im.dtype
9893
im = im.astype(np.float64)
9994
im, mask = np.split(im, [-1], axis=-1)
@@ -267,11 +262,13 @@ def applyPhaseScram(image, coherence=0.0, rndphi=None, mask=None, nSegs=1,
267262
apply, with 0 being fully scrambled (default) and 1 being not scrambled
268263
at all.
269264
rndphi : array, optional
270-
Array of random phases.
265+
2D array of random phases - allows using a custom phase spectrum.
266+
Should be same size as image segments (or whole image if nSegs == 1).
271267
mask : array, optional
272268
Mask of weights in range 0-1 that can be applied to random phase array
273269
(e.g. to scramble only certain parts of the spectrum). Mask should be
274-
for an unshifted spectrum.
270+
for an unshifted spectrum, and same size as image segments (or whole
271+
image if nSegs == 1),
275272
nSegs : int, optional
276273
Number of segments to split image into. If nSegs is 1 (default),
277274
scrambling is performed across entire image (i.e. global scrambling).
@@ -293,34 +290,34 @@ def applyPhaseScram(image, coherence=0.0, rndphi=None, mask=None, nSegs=1,
293290
--------
294291
Phase scramble image with 0% coherence
295292
296-
>>> scram1 = applyPhaseScram('/some/image.png')
293+
>>> im = imageio.imread('imageio:camera.png')
294+
>>> scram1 = applyPhaseScram(im)
297295
298296
Scramble with 40% phase coherence
299297
300-
>>> scram2 = applyPhaseScram('/some/image.png', coherence = .4)
298+
>>> scram2 = applyPhaseScram(im, coherence = .4)
301299
302300
Use own random phase array
303301
304302
>>> import numpy as np
305-
>>> myrndphi = np.angle(np.fft.fft2(np.random.rand(im_height, im_width)))
306-
>>> scram3 = applyPhaseScram('/some/image.png', rndphi = myrndphi)
303+
>>> myrndphi = np.angle(np.fft.fft2(np.random.rand(*im.shape)))
304+
>>> scram3 = applyPhaseScram(im, rndphi = myrndphi)
307305
308306
Weight rndphi by mask. Here we weight by an inverted horizontal-pass
309307
filter to scramble vertical orientations but preserve horizontals.
310308
311309
>>> from imageprocessing import FourierFilter
312-
>>> impath = '/some/image.png'
313-
>>> filterer = FourierFilter(impath)
310+
>>> filterer = FourierFilter(im)
314311
>>> filt = filterer.makeFilter(
315312
... mode='ori', filtertype='gaussian', invert=True,
316313
... filter_kwargs = {'mu':np.radians(0),
317314
... 'sigma':fwhm2sigma(np.radians(45))}
318315
... )
319-
>>> scram4 = applyPhaseScram(impath, mask = filt)
316+
>>> scram4 = applyPhaseScram(im, mask = filt)
320317
321318
Locally scrambled image within windows of an 8x8 grid
322319
323-
>>> local_scram = applyPhaseScram('/some/image.png', nSegs = 8)
320+
>>> local_scram = applyPhaseScram(im, nSegs = 8)
324321
325322
"""
326323
# Read in image
@@ -329,8 +326,9 @@ def applyPhaseScram(image, coherence=0.0, rndphi=None, mask=None, nSegs=1,
329326

330327
# Work out segments
331328
if L % nSegs or W % nSegs:
332-
raise ValueError('Image dimensions ({0}, {1}) must be divisible by '
333-
'nSegs ({2})'.format(L, W, nSegs))
329+
raise ValueError(
330+
f'Image dimensions ({L},{W}) must be divisible by nSegs ({nSegs})'
331+
)
334332
segL = L // nSegs
335333
segW = W // nSegs
336334

@@ -366,11 +364,11 @@ def applyPhaseScram(image, coherence=0.0, rndphi=None, mask=None, nSegs=1,
366364
ampF = np.abs(F)
367365
phiF = np.angle(F)
368366
# Calculate new phase spectrum
369-
newphi = phiF + rndphi
367+
phiF += rndphi
370368
# Combine original amplitude spectrum with new phase spectrum
371-
newF = ampF * np.exp(newphi * 1j)
369+
F[:] = ampF * np.exp(phiF * 1j)
372370
# Inverse transform, assign into scram
373-
scram[y1:y2, x1:x2, i] = ifft2(newF).real
371+
scram[y1:y2, x1:x2, i] = ifft2(F).real
374372

375373
# Postproc and return
376374
return postproc_im(scram, **kwargs)
@@ -642,16 +640,17 @@ def plotAverageAmpSpec(indir, ext='png', nSegs=1, dpi=96, cmap='jet'):
642640
dpi : int, optional
643641
Resolution to save plots at (default = 96).
644642
cmap : any valid matplotlib cmap instance
645-
Colourmap for filled contour plot
643+
Colourmap for filled contour plot.
646644
"""
647645
# Local imports just for this function
648646
import glob, imageio
647+
import matplotlib.pyplot as plt
649648

650649
# Ensure . character not included in extension
651650
ext = ext.strip('.')
652651

653652
# Glob for input files
654-
infiles = sorted(glob.glob(os.path.join(indir, '*.%s' %ext)))
653+
infiles = sorted(glob.glob(os.path.join(indir, f'*.{ext}')))
655654
if len(infiles) == 0:
656655
raise IOError('No images found! Check directory and extension')
657656

@@ -662,8 +661,9 @@ def plotAverageAmpSpec(indir, ext='png', nSegs=1, dpi=96, cmap='jet'):
662661

663662
# Work out if we can segment image evenly, and dims of windows if we can
664663
if L % nSegs or W % nSegs:
665-
raise IOError('Image dimensions ({0}, {1}) must be divisible by '
666-
'nSegs ({2})'.format(L, W, nSegs))
664+
raise ValueError(
665+
f'Image dimensions ({L},{W}) must be divisible by nSegs ({nSegs})'
666+
)
667667
segL = L // nSegs
668668
segW = W // nSegs
669669

@@ -688,7 +688,7 @@ def plotAverageAmpSpec(indir, ext='png', nSegs=1, dpi=96, cmap='jet'):
688688
ampF = np.abs(fftshift(fft2(win)))
689689
# Log scale, assign relevant window of spectrum (we use ampF+1
690690
# to avoid any -ve values from log scaling values < 1)
691-
spectra[i, y:y+segL, x:x+segW] = np.log(ampF + 1)
691+
spectra[i, y:y+segL, x:x+segW] = np.log1p(ampF)
692692
spectra[i] /= spectra[i].max() # scale full array to range 0:1
693693

694694
# Create average spectrum
@@ -700,7 +700,7 @@ def plotAverageAmpSpec(indir, ext='png', nSegs=1, dpi=96, cmap='jet'):
700700
os.makedirs(outdir, exist_ok=True)
701701

702702
# Main numpy array
703-
savename = os.path.join(outdir, 'win{}_array.npy'.format(nSegs))
703+
savename = os.path.join(outdir, f'win{nSegs}_array.npy')
704704
np.save(savename, av_spectrum)
705705

706706
# Filled contour figure
@@ -713,9 +713,9 @@ def plotAverageAmpSpec(indir, ext='png', nSegs=1, dpi=96, cmap='jet'):
713713
cf = ax.contourf(av_spectrum, origin = 'upper')
714714
cf.set_cmap(cmap)
715715
cf.set_clim([0,1])
716-
savename = os.path.join(outdir, 'win%s_filled_contour.png' %(nSegs))
716+
savename = os.path.join(outdir, f'win{nSegs}_filled_contour.png')
717717
fig.savefig(savename, dpi = dpi)
718-
print('Saved %s' %savename)
718+
print('Saved ' + savename)
719719
plt.close(fig)
720720

721721
# Line contour figure
@@ -726,9 +726,9 @@ def plotAverageAmpSpec(indir, ext='png', nSegs=1, dpi=96, cmap='jet'):
726726
# spectrum in range 0:1
727727
ax.contour(av_spectrum, [0.45, 0.55], colors = 'k', linewidths = 2,
728728
origin = 'upper')
729-
savename = os.path.join(outdir, 'win%s_line_contour.png' %(nSegs))
729+
savename = os.path.join(outdir, f'win{nSegs}_line_contour.png')
730730
fig.savefig(savename, dpi = dpi)
731-
print('Saved %s' %savename)
731+
print('Saved ' + savename)
732732
plt.close(fig)
733733

734734

@@ -758,19 +758,21 @@ class SoftWindowImage():
758758
--------
759759
Apply a rectangular soft window
760760
761+
>>> im = imageio.imread('imageio:camera.png')
761762
>>> windower = SoftWindowImage('rect')
762-
>>> winIm = windower.maskImage('./some/image.png')
763+
>>> winIm = windower.maskImage(im)
763764
764765
The mask is created when the first image is processed, and stored within
765766
the class. The mask can be re-used for subsequent images of the same size
766767
767-
>>> winIm2 = windower.maskImage('./some/other_image.png')
768+
>>> im2 = imageio.imread('imageio:wikkie.png')
769+
>>> winIm2 = windower.maskImage(im2)
768770
769771
Create an elliptical mask with a fwhm of 0.8, and apply to image setting
770772
background to be white
771773
772774
>>> windower = SoftWindowImage('ellipse', mask_fwhm=0.8)
773-
>>> winIm3 = windower.maskImage('./some/image.png', bglum=255)
775+
>>> winIm3 = windower.maskImage(im, bglum=255)
774776
"""
775777
def __init__(self, mask_shape, mask_fwhm=0.9):
776778
if mask_shape not in ['ellipse', 'rect']:
@@ -779,7 +781,6 @@ def __init__(self, mask_shape, mask_fwhm=0.9):
779781
self.mask_fwhm = mask_fwhm
780782
self.mask = None # placeholder for mask
781783

782-
783784
def _createMask(self, imsize):
784785
"""
785786
Create soft-window mask, assigns into class. Should get called
@@ -831,7 +832,6 @@ def _createMask(self, imsize):
831832
# Assign to class
832833
self.mask = mask
833834

834-
835835
def maskImage(self, image, bglum='mean', **kwargs):
836836
"""
837837
Create and apply mask to image.

pyGist.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -239,32 +239,33 @@ class with both that vector supplied to the gist argument and the
239239
import matplotlib.pyplot as plt
240240
from matplotlib.colors import Normalize
241241
from mpl_toolkits.axes_grid1 import ImageGrid
242+
from scipy.signal import decimate
242243

243244
# Some admin stuff
244245
if not mode in ['imshow','contour']:
245246
raise ValueError('mode should be \'imshow\' or \'contour\'')
246247
nWindows = self.nBlocks**2
247-
df = 4 # down-sampling factor
248+
q = 4 # down-sampling factor
248249

249250
# If we don't already have filters, try to make them (note - user must
250251
# specify an image or imageSize argument for this to work)
251252
if self.G is None:
252253
self._createGabor()
253254

254255
# Work out filter dims and number of filters
255-
x, y, nFilters = self.G.shape
256-
down_x, down_y = int(np.ceil(x/df)), int(np.ceil(y/df)) # size after downsampling
256+
H, W, nFilters = self.G.shape
257+
down_H, down_W = int(np.ceil(H/q)), int(np.ceil(W/q)) # size after downsampling
257258

258259
# Indices describing which window and filter each point in gist relates to
259260
gistIdcs = np.arange(len(self.gist)).reshape(nFilters, nWindows)
260261

261262
# Pre-allocate 4D array for storing plot data
262-
plotData = np.zeros([down_x, down_y, nWindows], dtype=np.float32)
263+
plotData = np.zeros([down_H, down_W, nWindows], dtype=np.float32)
263264

264265
# Loop over filters
265266
for i in range(nFilters):
266267
# Get filter (down-sample to reduce memory load)
267-
filt = self.G[::df, ::df, i]
268+
filt = decimate(decimate(self.G[..., i], q, axis=0), q, axis=1)
268269
# Mirror about origin to give other 'tail' of filter, apply fftshift
269270
filt = fftshift(filt + np.rot90(filt,2))
270271

@@ -317,7 +318,7 @@ def _imread(self, image):
317318
elif isinstance(image, Image.Image):
318319
im = np.asarray(image)
319320
elif isinstance(image, np.ndarray):
320-
im = image
321+
im = image.copy()
321322
else:
322323
raise IOError('Image must be a valid filepath, Image instance, '
323324
'or numpy array')
@@ -520,7 +521,7 @@ def _downN(self, x, N):
520521

521522
# Plot showGist
522523
fig = gist.showGist()
523-
fig.canvas.set_window_title('Fig 4: GIST visualised with showGIST')
524+
fig.canvas.manager.set_window_title('Fig 4: GIST visualised with showGIST')
524525

525526
# Display
526527
plt.show()

pySHINE.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,13 @@ def readImage(image, grayscale=True, dtype=float, alpha_action='mask'):
147147
"""
148148
# Load image
149149
if isinstance(image, np.ndarray):
150-
im = image
150+
im = image.copy()
151151
elif isinstance(image, Image.Image):
152152
im = np.asarray(image)
153153
elif isinstance(image, str) and os.path.exists(image):
154154
im = np.asarray(imageio.imread(image))
155155
else:
156-
raise IOError('Cannot read image {}'.format(image))
156+
raise IOError(f'Cannot read image {image}')
157157

158158
# Handle alpha channel
159159
if im.ndim == 3 and (im.shape[2] in [2,4]):

0 commit comments

Comments
 (0)