fastremap 1.15.2__tar.gz → 1.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastremap-1.15.2 → fastremap-1.16.0}/ChangeLog +15 -0
- {fastremap-1.15.2/fastremap.egg-info → fastremap-1.16.0}/PKG-INFO +10 -1
- {fastremap-1.15.2 → fastremap-1.16.0}/README.md +9 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/automated_test.py +73 -4
- {fastremap-1.15.2 → fastremap-1.16.0/fastremap.egg-info}/PKG-INFO +10 -1
- fastremap-1.16.0/fastremap.egg-info/pbr.json +1 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/src/fastremap.pyx +134 -19
- fastremap-1.15.2/fastremap.egg-info/pbr.json +0 -1
- {fastremap-1.15.2 → fastremap-1.16.0}/.dockerignore +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/.github/workflows/build_wheel.yml +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/.github/workflows/test.yml +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/AUTHORS +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/LICENSE +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/MANIFEST.in +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/build_linux.sh +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/SOURCES.txt +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/dependency_links.txt +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/not-zip-safe +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/requires.txt +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/top_level.txt +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/manylinux1.Dockerfile +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/manylinux2010.Dockerfile +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/manylinux2014.Dockerfile +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/pyproject.toml +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/requirements.txt +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/requirements_dev.txt +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/setup.cfg +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/setup.py +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/src/fastremap.pxd +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/src/ipt.hpp +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/src/ska_flat_hash_map.hpp +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/test.py +0 -0
- {fastremap-1.15.2 → fastremap-1.16.0}/tox.ini +0 -0
@@ -1,6 +1,21 @@
|
|
1
1
|
CHANGES
|
2
2
|
=======
|
3
3
|
|
4
|
+
1.16.0
|
5
|
+
------
|
6
|
+
|
7
|
+
* test: add a more stringent random test
|
8
|
+
* fix(unique): unique\_via\_sort returns proper data width
|
9
|
+
* fix(unique): axis=0, ndim=2 works for higher data widths
|
10
|
+
* fix(unique): edge case for uint64 range
|
11
|
+
* fix(unique): handle floating point
|
12
|
+
* test: make sure fastremap.unique matches np.unique
|
13
|
+
* test: sanity check that axis=0 works
|
14
|
+
* perf: accelerate special case of np.unique(x, axis=0) where x.ndim=2
|
15
|
+
* feat: add indices
|
16
|
+
* feat+test: add widen\_dtype and narrow\_dtype
|
17
|
+
* docs: show how to use "indices"
|
18
|
+
|
4
19
|
1.15.2
|
5
20
|
------
|
6
21
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fastremap
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.16.0
|
4
4
|
Summary: Remap, mask, renumber, unique, and in-place transposition of 3D labeled images. Point cloud too.
|
5
5
|
Home-page: https://github.com/seung-lab/fastremap/
|
6
6
|
Author: William Silversmith
|
@@ -42,12 +42,18 @@ Renumber and relabel Numpy arrays at C++ speed and physically convert rectangula
|
|
42
42
|
import fastremap
|
43
43
|
|
44
44
|
uniq, cts = fastremap.unique(labels, return_counts=True) # may be much faster than np.unique
|
45
|
+
|
46
|
+
idxs = fastremap.indices(labels, 1231) # important for huge arrays
|
47
|
+
|
45
48
|
labels, remapping = fastremap.renumber(labels, in_place=True) # relabel values from 1 and refit data type
|
46
49
|
ptc = fastremap.point_cloud(labels) # dict of coordinates by label
|
47
50
|
|
48
51
|
labels = fastremap.refit(labels) # resize the data type of the array to fit extrema
|
49
52
|
labels = fastremap.refit(labels, value=-35) # resize the data type to fit the value provided
|
50
53
|
|
54
|
+
wider_dtype = fastremap.widen_dtype(np.uint32) # np.uint64
|
55
|
+
narrower_dtype = fastremap.narrow_dtype(np.uint32) # np.uint16
|
56
|
+
|
51
57
|
# remap all occurances of 1 -> 2
|
52
58
|
labels = fastremap.remap(labels, { 1: 2 }, preserve_missing_labels=True, in_place=True)
|
53
59
|
|
@@ -78,8 +84,11 @@ binaries = fastremap.tobytes(labels, (64,64,64), order="F")
|
|
78
84
|
## All Available Functions
|
79
85
|
- **unique:** Faster implementation of `np.unique`.
|
80
86
|
- **renumber:** Relabel array from 1 to N which can often use smaller datatypes.
|
87
|
+
- **indices:** Optimized search for matching values.
|
81
88
|
- **remap:** Custom relabeling of values in an array from a dictionary.
|
82
89
|
- **refit:** Resize the data type of an array to the smallest that can contain the most extreme values in it.
|
90
|
+
- **narrow_dtype:** Find the next sized up dtype. e.g. uint16 -> uint32
|
91
|
+
- **widen_dtype:** Find the next sized down dtype. e.g. uint16 -> uint8
|
83
92
|
- **mask:** Zero out labels in an array specified by a given list.
|
84
93
|
- **mask_except**: Zero out all labels except those specified in a given list.
|
85
94
|
- **component_map**: Extract an int-to-int dictionary mapping of labels from one image containing component labels to another parent labels.
|
@@ -8,12 +8,18 @@ Renumber and relabel Numpy arrays at C++ speed and physically convert rectangula
|
|
8
8
|
import fastremap
|
9
9
|
|
10
10
|
uniq, cts = fastremap.unique(labels, return_counts=True) # may be much faster than np.unique
|
11
|
+
|
12
|
+
idxs = fastremap.indices(labels, 1231) # important for huge arrays
|
13
|
+
|
11
14
|
labels, remapping = fastremap.renumber(labels, in_place=True) # relabel values from 1 and refit data type
|
12
15
|
ptc = fastremap.point_cloud(labels) # dict of coordinates by label
|
13
16
|
|
14
17
|
labels = fastremap.refit(labels) # resize the data type of the array to fit extrema
|
15
18
|
labels = fastremap.refit(labels, value=-35) # resize the data type to fit the value provided
|
16
19
|
|
20
|
+
wider_dtype = fastremap.widen_dtype(np.uint32) # np.uint64
|
21
|
+
narrower_dtype = fastremap.narrow_dtype(np.uint32) # np.uint16
|
22
|
+
|
17
23
|
# remap all occurances of 1 -> 2
|
18
24
|
labels = fastremap.remap(labels, { 1: 2 }, preserve_missing_labels=True, in_place=True)
|
19
25
|
|
@@ -44,8 +50,11 @@ binaries = fastremap.tobytes(labels, (64,64,64), order="F")
|
|
44
50
|
## All Available Functions
|
45
51
|
- **unique:** Faster implementation of `np.unique`.
|
46
52
|
- **renumber:** Relabel array from 1 to N which can often use smaller datatypes.
|
53
|
+
- **indices:** Optimized search for matching values.
|
47
54
|
- **remap:** Custom relabeling of values in an array from a dictionary.
|
48
55
|
- **refit:** Resize the data type of an array to the smallest that can contain the most extreme values in it.
|
56
|
+
- **narrow_dtype:** Find the next sized up dtype. e.g. uint16 -> uint32
|
57
|
+
- **widen_dtype:** Find the next sized down dtype. e.g. uint16 -> uint8
|
49
58
|
- **mask:** Zero out labels in an array specified by a given list.
|
50
59
|
- **mask_except**: Zero out all labels except those specified in a given list.
|
51
60
|
- **component_map**: Extract an int-to-int dictionary mapping of labels from one image containing component labels to another parent labels.
|
@@ -397,6 +397,29 @@ def test_minmax():
|
|
397
397
|
assert minval == np.min(volume)
|
398
398
|
assert maxval == np.max(volume)
|
399
399
|
|
400
|
+
@pytest.mark.parametrize("dtype", DTYPES)
|
401
|
+
def test_unique_axis_0(dtype):
|
402
|
+
arr = np.array([
|
403
|
+
[0,1],
|
404
|
+
[0,2],
|
405
|
+
[0,3],
|
406
|
+
[0,2],
|
407
|
+
[1,2],
|
408
|
+
[2,3],
|
409
|
+
], dtype=dtype)
|
410
|
+
|
411
|
+
res = fastremap.unique(arr, axis=0)
|
412
|
+
ans = np.unique(arr, axis=0)
|
413
|
+
|
414
|
+
assert np.all(res == ans)
|
415
|
+
|
416
|
+
def test_unique_axis_0_random():
|
417
|
+
arr = np.random.randint(0,100000, size=[1000000,2], dtype=np.uint32)
|
418
|
+
a1 = fastremap.unique(arr, axis=0)
|
419
|
+
a2 = np.unique(arr, axis=0)
|
420
|
+
assert np.all(a1 == a2)
|
421
|
+
|
422
|
+
|
400
423
|
@pytest.mark.parametrize("order", [ "C", "F" ])
|
401
424
|
def test_unique(order):
|
402
425
|
def reorder(arr):
|
@@ -610,9 +633,55 @@ def test_tobytes_misaligned(order):
|
|
610
633
|
except ValueError:
|
611
634
|
pass
|
612
635
|
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
636
|
+
def test_narrow_dtype():
|
637
|
+
assert fastremap.narrow_dtype(np.uint64) == np.uint32
|
638
|
+
assert fastremap.narrow_dtype(np.uint32) == np.uint16
|
639
|
+
assert fastremap.narrow_dtype(np.uint16) == np.uint8
|
640
|
+
assert fastremap.narrow_dtype(np.uint8) == np.uint8
|
641
|
+
|
642
|
+
assert fastremap.narrow_dtype(np.int64) == np.int32
|
643
|
+
assert fastremap.narrow_dtype(np.int32) == np.int16
|
644
|
+
assert fastremap.narrow_dtype(np.int16) == np.int8
|
645
|
+
assert fastremap.narrow_dtype(np.int8) == np.int8
|
646
|
+
|
647
|
+
assert fastremap.narrow_dtype(np.uint64, exotics=True) == np.uint32
|
648
|
+
assert fastremap.narrow_dtype(np.uint32, exotics=True) == np.uint16
|
649
|
+
assert fastremap.narrow_dtype(np.uint16, exotics=True) == np.uint8
|
650
|
+
assert fastremap.narrow_dtype(np.uint8, exotics=True) == np.uint8
|
651
|
+
|
652
|
+
assert fastremap.narrow_dtype(np.int64, exotics=True) == np.int32
|
653
|
+
assert fastremap.narrow_dtype(np.int32, exotics=True) == np.int16
|
654
|
+
assert fastremap.narrow_dtype(np.int16, exotics=True) == np.int8
|
655
|
+
assert fastremap.narrow_dtype(np.int8, exotics=True) == np.int8
|
656
|
+
|
657
|
+
assert fastremap.narrow_dtype(np.float64) == np.float32
|
658
|
+
assert fastremap.narrow_dtype(np.float32) == np.float32
|
659
|
+
|
660
|
+
assert fastremap.narrow_dtype(np.float64, exotics=True) == np.float32
|
661
|
+
assert fastremap.narrow_dtype(np.float32, exotics=True) == np.float16
|
662
|
+
|
663
|
+
assert fastremap.narrow_dtype(np.complex128) == np.complex64
|
664
|
+
assert fastremap.narrow_dtype(np.complex64) == np.complex64
|
665
|
+
|
666
|
+
def test_widen_dtype():
|
667
|
+
assert fastremap.widen_dtype(np.uint64) == np.uint64
|
668
|
+
assert fastremap.widen_dtype(np.uint32) == np.uint64
|
669
|
+
assert fastremap.widen_dtype(np.uint16) == np.uint32
|
670
|
+
assert fastremap.widen_dtype(np.uint8) == np.uint16
|
671
|
+
|
672
|
+
assert fastremap.widen_dtype(np.int64) == np.int64
|
673
|
+
assert fastremap.widen_dtype(np.int32) == np.int64
|
674
|
+
assert fastremap.widen_dtype(np.int16) == np.int32
|
675
|
+
assert fastremap.widen_dtype(np.int8) == np.int16
|
676
|
+
|
677
|
+
assert fastremap.widen_dtype(np.float64, exotics=True) == np.longdouble
|
678
|
+
assert fastremap.widen_dtype(np.float64) == np.float64
|
679
|
+
assert fastremap.widen_dtype(np.float32) == np.float64
|
680
|
+
assert fastremap.widen_dtype(np.float16) == np.float32
|
681
|
+
|
682
|
+
assert fastremap.widen_dtype(np.complex64) == np.complex64
|
683
|
+
assert fastremap.widen_dtype(np.complex64, exotics=True) == np.complex128
|
684
|
+
assert fastremap.widen_dtype(np.complex128, exotics=True) == np.clongdouble
|
685
|
+
assert fastremap.widen_dtype(np.clongdouble, exotics=True) == np.clongdouble
|
617
686
|
|
618
687
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fastremap
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.16.0
|
4
4
|
Summary: Remap, mask, renumber, unique, and in-place transposition of 3D labeled images. Point cloud too.
|
5
5
|
Home-page: https://github.com/seung-lab/fastremap/
|
6
6
|
Author: William Silversmith
|
@@ -42,12 +42,18 @@ Renumber and relabel Numpy arrays at C++ speed and physically convert rectangula
|
|
42
42
|
import fastremap
|
43
43
|
|
44
44
|
uniq, cts = fastremap.unique(labels, return_counts=True) # may be much faster than np.unique
|
45
|
+
|
46
|
+
idxs = fastremap.indices(labels, 1231) # important for huge arrays
|
47
|
+
|
45
48
|
labels, remapping = fastremap.renumber(labels, in_place=True) # relabel values from 1 and refit data type
|
46
49
|
ptc = fastremap.point_cloud(labels) # dict of coordinates by label
|
47
50
|
|
48
51
|
labels = fastremap.refit(labels) # resize the data type of the array to fit extrema
|
49
52
|
labels = fastremap.refit(labels, value=-35) # resize the data type to fit the value provided
|
50
53
|
|
54
|
+
wider_dtype = fastremap.widen_dtype(np.uint32) # np.uint64
|
55
|
+
narrower_dtype = fastremap.narrow_dtype(np.uint32) # np.uint16
|
56
|
+
|
51
57
|
# remap all occurances of 1 -> 2
|
52
58
|
labels = fastremap.remap(labels, { 1: 2 }, preserve_missing_labels=True, in_place=True)
|
53
59
|
|
@@ -78,8 +84,11 @@ binaries = fastremap.tobytes(labels, (64,64,64), order="F")
|
|
78
84
|
## All Available Functions
|
79
85
|
- **unique:** Faster implementation of `np.unique`.
|
80
86
|
- **renumber:** Relabel array from 1 to N which can often use smaller datatypes.
|
87
|
+
- **indices:** Optimized search for matching values.
|
81
88
|
- **remap:** Custom relabeling of values in an array from a dictionary.
|
82
89
|
- **refit:** Resize the data type of an array to the smallest that can contain the most extreme values in it.
|
90
|
+
- **narrow_dtype:** Find the next sized up dtype. e.g. uint16 -> uint32
|
91
|
+
- **widen_dtype:** Find the next sized down dtype. e.g. uint16 -> uint8
|
83
92
|
- **mask:** Zero out labels in an array specified by a given list.
|
84
93
|
- **mask_except**: Zero out all labels except those specified in a given list.
|
85
94
|
- **component_map**: Extract an int-to-int dictionary mapping of labels from one image containing component labels to another parent labels.
|
@@ -0,0 +1 @@
|
|
1
|
+
{"git_version": "a7c2749", "is_release": true}
|
@@ -12,7 +12,7 @@ constrained environments when format shifting.
|
|
12
12
|
|
13
13
|
Author: William Silversmith
|
14
14
|
Affiliation: Seung Lab, Princeton Neuroscience Institute
|
15
|
-
Date: August 2018 - May
|
15
|
+
Date: August 2018 - May 2025
|
16
16
|
"""
|
17
17
|
from typing import Sequence, List
|
18
18
|
cimport cython
|
@@ -101,6 +101,23 @@ def match_array_orders(*arrs, order="K"):
|
|
101
101
|
else:
|
102
102
|
return [ np.asfortranarray(arr) for arr in arrs ]
|
103
103
|
|
104
|
+
@cython.boundscheck(False)
|
105
|
+
@cython.wraparound(False) # turn off negative index wrapping for entire function
|
106
|
+
@cython.nonecheck(False)
|
107
|
+
def indices(cnp.ndarray[NUMBER, cast=True, ndim=1] arr, NUMBER value):
|
108
|
+
"""
|
109
|
+
Search through an array and identify the indices where value matches the array.
|
110
|
+
"""
|
111
|
+
cdef vector[uint64_t] all_indices
|
112
|
+
cdef uint64_t i = 0
|
113
|
+
cdef uint64_t size = arr.size
|
114
|
+
|
115
|
+
for i in range(size):
|
116
|
+
if arr[i] == value:
|
117
|
+
all_indices.push_back(i)
|
118
|
+
|
119
|
+
return np.asarray(all_indices, dtype=np.uint64)
|
120
|
+
|
104
121
|
def renumber(arr, start=1, preserve_zero=True, in_place=False):
|
105
122
|
"""
|
106
123
|
renumber(arr, start=1, preserve_zero=True, in_place=False)
|
@@ -339,6 +356,83 @@ def fit_dtype(dtype, value, exotics=False):
|
|
339
356
|
dtype, value
|
340
357
|
))
|
341
358
|
|
359
|
+
def widen_dtype(dtype, exotics:bool = False):
|
360
|
+
"""
|
361
|
+
Widen the given dtype to the next size
|
362
|
+
of the same type. For example,
|
363
|
+
int8 -> int16 or uint32 -> uint64
|
364
|
+
|
365
|
+
64-bit types will map to themselves.
|
366
|
+
|
367
|
+
Return: upgraded dtype
|
368
|
+
"""
|
369
|
+
dtype = np.dtype(dtype)
|
370
|
+
|
371
|
+
if np.issubdtype(dtype, np.floating):
|
372
|
+
sequence = [ np.float16, np.float32, np.float64 ]
|
373
|
+
if exotics:
|
374
|
+
sequence += [ np.longdouble ]
|
375
|
+
elif np.issubdtype(dtype, np.unsignedinteger):
|
376
|
+
sequence = [ np.uint8, np.uint16, np.uint32, np.uint64 ]
|
377
|
+
elif np.issubdtype(dtype, np.complexfloating):
|
378
|
+
sequence = [ np.complex64 ]
|
379
|
+
if exotics:
|
380
|
+
sequence += [ np.complex128, np.clongdouble ]
|
381
|
+
elif np.issubdtype(dtype, np.integer):
|
382
|
+
sequence = [ np.int8, np.int16, np.int32, np.int64 ]
|
383
|
+
elif np.issubdtype(dtype, (np.intp, np.uintp)):
|
384
|
+
return dtype
|
385
|
+
elif exotics:
|
386
|
+
raise ValueError(
|
387
|
+
f"Unsupported dtype: {dtype}\n"
|
388
|
+
)
|
389
|
+
else:
|
390
|
+
raise ValueError(
|
391
|
+
f"Unsupported dtype: {dtype}\n"
|
392
|
+
f"Only standard floats, integers, and complex types are supported."
|
393
|
+
f"For additional types (e.g. long double, complex128, clongdouble), enable exotics."
|
394
|
+
)
|
395
|
+
|
396
|
+
idx = sequence.index(dtype)
|
397
|
+
return sequence[min(idx+1, len(sequence) - 1)]
|
398
|
+
|
399
|
+
def narrow_dtype(dtype, exotics:bool = False):
|
400
|
+
"""
|
401
|
+
Widen the given dtype to the next size
|
402
|
+
of the same type. For example,
|
403
|
+
int16 -> int8 or uint64 -> uint32
|
404
|
+
|
405
|
+
8-bit types will map to themselves.
|
406
|
+
|
407
|
+
exotics: include float16
|
408
|
+
|
409
|
+
Return: upgraded dtype
|
410
|
+
"""
|
411
|
+
dtype = np.dtype(dtype)
|
412
|
+
if dtype.itemsize == 1:
|
413
|
+
return dtype
|
414
|
+
|
415
|
+
if np.issubdtype(dtype, np.floating):
|
416
|
+
sequence = [ np.float32, np.float64, np.longdouble ]
|
417
|
+
if exotics:
|
418
|
+
sequence = [ np.float16 ] + sequence
|
419
|
+
elif np.issubdtype(dtype, np.unsignedinteger):
|
420
|
+
sequence = [ np.uint8, np.uint16, np.uint32, np.uint64 ]
|
421
|
+
elif np.issubdtype(dtype, np.complexfloating):
|
422
|
+
sequence = [ np.complex64, np.complex128, np.clongdouble ]
|
423
|
+
elif np.issubdtype(dtype, np.integer):
|
424
|
+
sequence = [ np.int8, np.int16, np.int32, np.int64 ]
|
425
|
+
elif np.issubdtype(dtype, (np.intp, np.uintp)):
|
426
|
+
return dtype
|
427
|
+
else:
|
428
|
+
raise ValueError(
|
429
|
+
f"Unsupported dtype: {dtype}\n"
|
430
|
+
f"Only standard floats, integers, and complex types are supported."
|
431
|
+
)
|
432
|
+
|
433
|
+
idx = sequence.index(dtype)
|
434
|
+
return sequence[max(idx-1, 0)]
|
435
|
+
|
342
436
|
def mask(arr, labels, in_place=False, value=0):
|
343
437
|
"""
|
344
438
|
mask(arr, labels, in_place=False, value=0)
|
@@ -777,19 +871,24 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
|
|
777
871
|
if not isinstance(labels, np.ndarray):
|
778
872
|
labels = np.array(labels)
|
779
873
|
|
780
|
-
if not np.issubdtype(labels.dtype, np.integer):
|
781
|
-
raise TypeError("fastremap.unique only supports integer types.")
|
782
|
-
|
783
874
|
# These flags are currently unsupported so call uncle and
|
784
875
|
# use the standard implementation instead.
|
785
|
-
if axis is not None:
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
return_inverse
|
790
|
-
|
791
|
-
|
792
|
-
|
876
|
+
if (axis is not None) or (not np.issubdtype(labels.dtype, np.integer)):
|
877
|
+
if (
|
878
|
+
axis == 0
|
879
|
+
and (labels.ndim == 2 and np.dtype(labels.dtype).itemsize < 8)
|
880
|
+
and not (return_index or return_inverse or return_counts)
|
881
|
+
and labels.flags.c_contiguous
|
882
|
+
):
|
883
|
+
return two_axis_unique(labels)
|
884
|
+
else:
|
885
|
+
return np.unique(
|
886
|
+
labels,
|
887
|
+
return_index=return_index,
|
888
|
+
return_inverse=return_inverse,
|
889
|
+
return_counts=return_counts,
|
890
|
+
axis=axis
|
891
|
+
)
|
793
892
|
|
794
893
|
cdef size_t voxels = labels.size
|
795
894
|
|
@@ -799,12 +898,10 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
|
|
799
898
|
labels_orig = labels
|
800
899
|
labels = reshape(labels, (voxels,))
|
801
900
|
|
802
|
-
|
803
|
-
|
901
|
+
max_label = 0
|
902
|
+
min_label = 0
|
804
903
|
if voxels > 0:
|
805
904
|
min_label, max_label = minmax(labels)
|
806
|
-
else:
|
807
|
-
min_label, max_label = (0, 0)
|
808
905
|
|
809
906
|
def c_order_index(arr):
|
810
907
|
if len(shape) > 1 and fortran_order:
|
@@ -819,9 +916,9 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
|
|
819
916
|
counts = np.array([], dtype=np.uint32)
|
820
917
|
index = np.array([], dtype=np.uint64)
|
821
918
|
inverse = np.array([], dtype=np.uintp)
|
822
|
-
elif min_label >= 0 and max_label <
|
919
|
+
elif min_label >= 0 and max_label < int(voxels):
|
823
920
|
uniq, index, counts, inverse = unique_via_array(labels, max_label, return_index=return_index, return_inverse=return_inverse)
|
824
|
-
elif (max_label - min_label) <=
|
921
|
+
elif (max_label - min_label) <= int(voxels):
|
825
922
|
uniq, index, counts, inverse = unique_via_shifted_array(labels, min_label, max_label, return_index=return_index, return_inverse=return_inverse)
|
826
923
|
elif float(pixel_pairs(labels)) / float(voxels) > 0.66:
|
827
924
|
uniq, index, counts, inverse = unique_via_renumber(labels, return_index=return_index, return_inverse=return_inverse)
|
@@ -845,6 +942,23 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
|
|
845
942
|
return tuple(results)
|
846
943
|
return uniq
|
847
944
|
|
945
|
+
def two_axis_unique(labels):
|
946
|
+
"""
|
947
|
+
Faster replacement for np.unique(labels, axis=0)
|
948
|
+
when ndim = 2 and the dtype can be widened.
|
949
|
+
|
950
|
+
This special case is useful for sorting edge lists.
|
951
|
+
"""
|
952
|
+
dtype = labels.dtype
|
953
|
+
wide_dtype = widen_dtype(dtype)
|
954
|
+
|
955
|
+
labels = labels[:, [1,0]].reshape(-1, order="C")
|
956
|
+
labels = labels.view(wide_dtype)
|
957
|
+
labels = unique(labels)
|
958
|
+
N = len(labels)
|
959
|
+
labels = labels.view(dtype).reshape((N, 2), order="C")
|
960
|
+
return labels[:,[1,0]]
|
961
|
+
|
848
962
|
def unique_via_shifted_array(labels, min_label=None, max_label=None, return_index=False, return_inverse=False):
|
849
963
|
if min_label is None or max_label is None:
|
850
964
|
min_label, max_label = minmax(labels)
|
@@ -895,9 +1009,10 @@ def unique_via_sort(cnp.ndarray[ALLINT, ndim=1] labels):
|
|
895
1009
|
uniq.push_back(cur)
|
896
1010
|
counts.push_back(accum)
|
897
1011
|
|
1012
|
+
dtype = labels.dtype
|
898
1013
|
del labels
|
899
1014
|
|
900
|
-
return np.array(uniq), np.array(counts)
|
1015
|
+
return np.array(uniq, dtype=dtype), np.array(counts, dtype=np.uint64)
|
901
1016
|
|
902
1017
|
@cython.boundscheck(False)
|
903
1018
|
@cython.wraparound(False) # turn off negative index wrapping for entire function
|
@@ -1 +0,0 @@
|
|
1
|
-
{"git_version": "b766561", "is_release": true}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|