Skip to content

Commit 812c2a2

Browse files
committed
v2.6.0
1 parent 5c47e18 commit 812c2a2

File tree

198 files changed

+9730
-3376
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

198 files changed

+9730
-3376
lines changed

.dockerignore

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
11
env
2-
.env
2+
.env
3+
src/modules
4+
src/submodules
5+
src/ltrace/build
6+
src/ltrace/ltrace/assets
7+
.git
8+
tools/deploy/GeoSlicerManual
9+
tools/deploy/Resources
10+
gs*/*

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.zip filter=lfs diff=lfs merge=lfs -text
22
*.h5 filter=lfs diff=lfs merge=lfs -text
3+
*.hdf5 filter=lfs diff=lfs merge=lfs -text
34
*.nrrd filter=lfs diff=lfs merge=lfs -text
45
*.nc filter=lfs diff=lfs merge=lfs -text
56
*.pth filter=lfs diff=lfs merge=lfs -text

docker-compose.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ services:
55
build:
66
context: .
77
dockerfile: tools/docker/windows.Dockerfile
8+
environment:
9+
- PYTHONUNBUFFERED=1
10+
- HOME=C:/Users/ContainerAdministrator
811
volumes:
9-
- .git:c:/slicerltrace/.git
10-
- ~/.oci/:C:/Users/ContainerAdministrator/.oci/
11-
- ~/.ssh/:C:/Users/ContainerAdministrator/.ssh/
12+
- ~/.ssh:C:/Users/ContainerAdministrator/.ssh
13+
- ~/.oci:C:/Users/ContainerAdministrator/.oci
14+
- .:c:/slicerltrace/
1215
storage_opt:
1316
size: '70G'
1417
slicerltrace-base-windows:
@@ -30,10 +33,12 @@ services:
3033
- DISPLAY=${DISPLAY}
3134
- QT_X11_NO_MITSHM=1
3235
- PYTHONUNBUFFERED=1
36+
- DOCKER_BUILDKIT=1
3337
volumes:
3438
- /tmp/.X11-unix:/tmp/.X11-unix
3539
- "$HOME/.oci:/root/.oci"
3640
- ~/.ssh/:/root/.ssh/
41+
- .:/slicerltrace/
3742
user: "${UID}:${GID}"
3843
cap_add:
3944
- SYS_ADMIN

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ authorized_licenses = [
6969
"OSI Approved",
7070
"Python Software Foundation",
7171
"Historical Permission Notice and Disclaimer (HPND)",
72+
"CMU License (MIT-CMU)",
7273
]
7374
unauthorized_licenses = [
7475
"GNU General Public License v3 (GPLv3)"

src/ltrace/ltrace/algorithms/CorrelationDistance/common.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ def get_subvolume_slices(data_shape, base, subvolume_size, dim_it_counters, divi
6565
new_range += (
6666
slice(
6767
base[dim_index],
68-
base[dim_index] + subvolume_size[dim_index]
69-
if dim_it_counters[dim_index] < divisor[dim_index] - 1
70-
else data_shape[dim_index],
68+
(
69+
base[dim_index] + subvolume_size[dim_index]
70+
if dim_it_counters[dim_index] < divisor[dim_index] - 1
71+
else data_shape[dim_index]
72+
),
7173
),
7274
)
7375
return new_range

src/ltrace/ltrace/algorithms/Variogram_FFT/variogram.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ def get_nugget(self, axis_index):
7676

7777
@staticmethod
7878
def compute_autocovariance_function(data, spacing):
79-
8079
"""
8180
AUTO-COVARIANCE FUNCTION
8281
Computes the auto-covariance function in the FFT domain of a given data in a array up to three dimensions
@@ -114,7 +113,6 @@ def compute_autocovariance_function(data, spacing):
114113

115114
@staticmethod
116115
def compute_NDvariogram_FFT(data, spacing):
117-
118116
"""
119117
VARIOGRAM COMPUTED IN FFT DOMAIN
120118
Computes the variogram based on the auto-covariance function in the FFT domain of a given data in a array up to three dimensions

src/ltrace/ltrace/algorithms/measurements.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ def findPeaks(values: np.ndarray, default=None):
198198
return default
199199

200200
if np.issubdtype(values.dtype, np.integer):
201-
bins = np.bincount(values)
202-
largerBin = np.argmax(bins)
201+
min_ = np.min(values)
202+
bins = np.bincount(values - min_)
203+
largerBin = np.argmax(bins + min_)
203204
else:
204205
hist, edges = np.histogram(values, bins="auto")
205206
largerBin = edges[np.argmax(hist)]
@@ -300,7 +301,7 @@ def microporosity(
300301
a = microporosityLowerLimit or macroPorosityPeak or extendPeak(textureVoxelArray, np.min(micropores), "lower")
301302

302303
# truncate negative values on zero
303-
outputVoxelArray[mask] = np.clip((b - micropores.astype(np.float)) / (b - a), backgroundPorosity, 1)
304+
outputVoxelArray[mask] = np.clip((b - micropores.astype(np.float64)) / (b - a), backgroundPorosity, 1)
304305

305306
layers["Microporosity Voxels"] = mask.sum()
306307
m = layers.get("Microporosity Weighted", 0) # check if solid has being set first
File renamed without changes.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import configparser
2+
import typing
3+
4+
from dataclasses import dataclass
5+
from numba import uint16, uint32, uint64, float32
6+
from numba import njit, prange
7+
from numba.types import ListType, Array
8+
9+
import numpy as np
10+
11+
import slicer
12+
13+
14+
"""
15+
Normalization (just for reference)
16+
def norm(x, minimum, maximum):
17+
return minimum + (maximum - minimum) * x / 65535.0
18+
19+
20+
def denorm(x, current_min, current_max, into_min=0, into_max=65535):
21+
return into_min + (into_max - into_min) * (x - current_min) / (current_max - current_min)
22+
"""
23+
24+
25+
@njit(parallel=True)
26+
def fastMapping(
27+
porosityImageArray: Array(float32, 3, "C"),
28+
labelsArray: Array(uint16, 3, "C"),
29+
maskArray: Array(uint16, 3, "C"),
30+
targets: ListType(uint16),
31+
):
32+
"""
33+
Same as:
34+
# porosityImageFinalArray = np.clip(porosityImageFloat, 0, 1, dtype=np.float32)
35+
# porosityImageFinalArray[self.__lastLabelsArray >= targets[1]] = np.float32(0)
36+
# porosityImageFinalArray[self.__lastLabelsArray == 0] = np.float32(0)
37+
# porosityImageFinalArray[self.__lastLabelsArray == targets[0]] = np.float32(1)
38+
# porosityImageFinalArray *= self.__lastMaskArray
39+
"""
40+
41+
z, y, x = porosityImageArray.shape
42+
for i in prange(z):
43+
for j in range(y):
44+
for k in range(x):
45+
46+
if maskArray[i, j, k] == 0:
47+
porosityImageArray[i, j, k] = np.float32(0)
48+
continue
49+
50+
if labelsArray[i, j, k] == targets[0]:
51+
porosityImageArray[i, j, k] = np.float32(1)
52+
elif labelsArray[i, j, k] >= targets[1]:
53+
porosityImageArray[i, j, k] = np.float32(0)
54+
elif labelsArray[i, j, k] == 0:
55+
porosityImageArray[i, j, k] = np.float32(0)
56+
else:
57+
porosityImageArray[i, j, k] = max(0, min(1, porosityImageArray[i, j, k]))
58+
59+
return porosityImageArray
60+
61+
62+
@njit
63+
def fast1DBinCountUInt64(array: Array(uint32, 1, "C")) -> Array(uint64, 1, "C"):
64+
max_ = np.max(array)
65+
out = np.zeros(max_ + 1, dtype=np.uint64)
66+
67+
for i in range(len(array)):
68+
out[array[i]] += 1
69+
70+
return out
71+
72+
73+
def mapValue(values, x: typing.Union[float, typing.List[float]]):
74+
# Compute the attenuation factor for the modelled region
75+
accsum = np.cumsum(values)
76+
return np.interp(x, accsum / accsum[-1], np.arange(1, len(values) + 1))
77+
78+
79+
@dataclass
80+
class DataVar:
81+
values: np.ndarray
82+
start: uint32
83+
label: uint32
84+
name: str
85+
threshold: np.ndarray = None
86+
color: tuple = (0, 0, 0)
87+
88+
89+
class SampleModel:
90+
def __init__(self, pcrRange=(0.0, 1.0)):
91+
self.variables: typing.Dict[str, DataVar] = {}
92+
self.pcrMin = np.float32(pcrRange[0])
93+
self.pcrMax = np.float32(pcrRange[1])
94+
self.image = None
95+
self.limits = None
96+
97+
def addData(self, image: np.ndarray, mask: np.ndarray, label: int = 0, color: tuple = (0, 0, 0)):
98+
self.image = image
99+
self.addSubGroup("Data", mask, label, color, markers=[0.0001, 0.99])
100+
self.limits = [int(np.round(v)) for v in self.variables["Data"].threshold]
101+
102+
def addSubGroup(self, name: str, mask: np.ndarray, label: int, color: tuple, markers: typing.List[float] = None):
103+
if self.image is None:
104+
raise ValueError("Image is missing")
105+
106+
if np.any(mask.shape != self.image.shape):
107+
raise ValueError("Mask and image must have the same shape")
108+
109+
counts = fast1DBinCountUInt64(self.image[mask])
110+
counts[0] = 0 # exclude background 0
111+
threshold = mapValue(counts, x=markers)
112+
113+
if self.limits is not None:
114+
min_, max_ = self.limits
115+
posmax = min(len(counts), max_)
116+
posmin = max(min_, 0)
117+
else:
118+
posmax = len(counts)
119+
posmin = 0
120+
121+
for i in range(posmin, posmax, 1):
122+
if counts[i] > 0:
123+
posmin = i
124+
break
125+
126+
counts = counts if posmin == 0 else counts[posmin:]
127+
self.variables[name] = DataVar(counts, posmin, label, name, threshold, color)
128+
129+
def threshold(self, key, normalized=False):
130+
value = self.variables[key].threshold
131+
if normalized:
132+
return self.pcrMin + (self.pcrMax - self.pcrMin) * value / 65535
133+
return value
134+
135+
def setThreshold(self, key, value: np.ndarray, normalized=False):
136+
if normalized:
137+
value = 65535 * (value - self.pcrMin) / (self.pcrMax - self.pcrMin)
138+
self.variables[key].threshold = value
139+
140+
def getImage(self, normalized=False):
141+
if normalized:
142+
return self.pcrMin + (self.pcrMax - self.pcrMin) * self.image / 65535
143+
return self.image

src/ltrace/ltrace/algorithms/partition.py

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
1-
from typing import List
2-
from collections import namedtuple, Counter
3-
import multiprocessing
41
import json
2+
from collections import namedtuple
53
from pathlib import Path
6-
import dask.array as da
7-
from loguru import logger
8-
from ltrace.slicer import helpers
9-
import scipy.ndimage as spim
10-
import scipy.spatial as sptl
11-
from skimage.feature import peak_local_max
12-
from skimage.segmentation import watershed
13-
from skimage.morphology import square, cube
14-
from recordtype import recordtype
4+
from typing import List
155

16-
import pandas as pd
176
import numpy as np
18-
from scipy import ndimage
19-
from numba import njit, prange
20-
from porespy.filters import snow_partitioning
21-
227
import slicer
8+
from recordtype import recordtype
9+
from scipy import ndimage
2310

24-
from porespy.tools import extend_slice
11+
from ltrace.slicer import helpers
2512
from ltrace.slicer.helpers import (
2613
createOutput,
2714
createTemporaryNode,

0 commit comments

Comments
 (0)