|
5 | 5 | from argparse import ArgumentParser |
6 | 6 | from math import floor, log2 |
7 | 7 | from os import path, listdir |
8 | | -from scipy.stats import mode |
9 | 8 | from scipy.ndimage.interpolation import zoom |
10 | 9 | from itertools import product |
11 | 10 | from functools import lru_cache |
@@ -73,8 +72,8 @@ def create_parser(): |
73 | 72 | "--from", |
74 | 73 | "-f", |
75 | 74 | help="Resolution to base downsampling on", |
76 | | - type=int, |
77 | | - default=1, |
| 75 | + type=str, |
| 76 | + default='1', |
78 | 77 | ) |
79 | 78 |
|
80 | 79 | # Either provide the maximum resolution to be downsampled OR a specific, anisotropic magnification. |
@@ -331,7 +330,42 @@ def _median(x): |
331 | 330 |
|
332 | 331 |
|
333 | 332 | def _mode(x): |
334 | | - return mode(x, axis=0, nan_policy="omit")[0][0] |
| 333 | + """ |
| 334 | + Fast mode implementation from: https://stackoverflow.com/a/35674754 |
| 335 | + """ |
| 336 | + # Check inputs |
| 337 | + ndim = x.ndim |
| 338 | + axis = 0 |
| 339 | + # Sort array |
| 340 | + sort = np.sort(x, axis=axis) |
| 341 | + # Create array to transpose along the axis and get padding shape |
| 342 | + transpose = np.roll(np.arange(ndim)[::-1], axis) |
| 343 | + shape = list(sort.shape) |
| 344 | + shape[axis] = 1 |
| 345 | + # Create a boolean array along strides of unique values |
| 346 | + strides = np.concatenate([np.zeros(shape=shape, dtype='bool'), |
| 347 | + np.diff(sort, axis=axis) == 0, |
| 348 | + np.zeros(shape=shape, dtype='bool')], |
| 349 | + axis=axis).transpose(transpose).ravel() |
| 350 | + # Count the stride lengths |
| 351 | + counts = np.cumsum(strides) |
| 352 | + counts[~strides] = np.concatenate([[0], np.diff(counts[~strides])]) |
| 353 | + counts[strides] = 0 |
| 354 | + # Get shape of padded counts and slice to return to the original shape |
| 355 | + shape = np.array(sort.shape) |
| 356 | + shape[axis] += 1 |
| 357 | + shape = shape[transpose] |
| 358 | + slices = [slice(None)] * ndim |
| 359 | + slices[axis] = slice(1, None) |
| 360 | + # Reshape and compute final counts |
| 361 | + counts = counts.reshape(shape).transpose(transpose)[slices] + 1 |
| 362 | + |
| 363 | + # Find maximum counts and return modals/counts |
| 364 | + slices = [slice(None, i) for i in sort.shape] |
| 365 | + del slices[axis] |
| 366 | + index = np.ogrid[slices] |
| 367 | + index.insert(axis, np.argmax(counts, axis=axis)) |
| 368 | + return sort[index] |
335 | 369 |
|
336 | 370 |
|
337 | 371 | def downsample_cube(cube_buffer, factors, interpolation_mode): |
|
0 commit comments