grainmorph 0.3.0__tar.gz → 0.3.1__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.
- {grainmorph-0.3.0/src/grainmorph.egg-info → grainmorph-0.3.1}/PKG-INFO +1 -1
- {grainmorph-0.3.0 → grainmorph-0.3.1}/pyproject.toml +1 -1
- grainmorph-0.3.1/src/grainmorph/wadell/discretize.py +59 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1/src/grainmorph.egg-info}/PKG-INFO +1 -1
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_discretize.py +6 -3
- grainmorph-0.3.0/src/grainmorph/wadell/discretize.py +0 -41
- {grainmorph-0.3.0 → grainmorph-0.3.1}/LICENSE +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/README.md +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/setup.cfg +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/__init__.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/analyzer.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/mask.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/metrics.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/utils/__init__.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/utils/particle.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/utils/plot.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/utils/shape.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/wadell/__init__.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/wadell/corner.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph/wadell/smoothing.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph.egg-info/SOURCES.txt +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph.egg-info/dependency_links.txt +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph.egg-info/requires.txt +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/src/grainmorph.egg-info/top_level.txt +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_analyzer.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_corner.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_mask.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_metrics.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_particle.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_plot.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_shape.py +0 -0
- {grainmorph-0.3.0 → grainmorph-0.3.1}/tests/test_smoothing.py +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def discretize_boundary(boundary, max_dev_thresh):
|
|
7
|
+
num = len(boundary)
|
|
8
|
+
# Separate columns and plain floats keep each of the many short calls cheap.
|
|
9
|
+
x = np.append(boundary[:, 0], boundary[0, 0])
|
|
10
|
+
y = np.append(boundary[:, 1], boundary[0, 1])
|
|
11
|
+
xs = x.tolist()
|
|
12
|
+
ys = y.tolist()
|
|
13
|
+
keep = [0]
|
|
14
|
+
|
|
15
|
+
start, end = 0, num
|
|
16
|
+
while start < num:
|
|
17
|
+
dev, idx = find_max_deviation(
|
|
18
|
+
x[start : end + 1],
|
|
19
|
+
y[start : end + 1],
|
|
20
|
+
xs[start],
|
|
21
|
+
ys[start],
|
|
22
|
+
xs[end],
|
|
23
|
+
ys[end],
|
|
24
|
+
)
|
|
25
|
+
# A peak at either end would not shrink the segment.
|
|
26
|
+
while dev > max_dev_thresh and 0 < idx < end - start:
|
|
27
|
+
end = start + idx
|
|
28
|
+
dev, idx = find_max_deviation(
|
|
29
|
+
x[start : end + 1],
|
|
30
|
+
y[start : end + 1],
|
|
31
|
+
xs[start],
|
|
32
|
+
ys[start],
|
|
33
|
+
xs[end],
|
|
34
|
+
ys[end],
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if end < num:
|
|
38
|
+
keep.append(end)
|
|
39
|
+
start, end = end, num
|
|
40
|
+
|
|
41
|
+
return boundary[keep]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_max_deviation(x, y, x0, y0, x1, y1):
|
|
45
|
+
dx = x1 - x0
|
|
46
|
+
dy = y0 - y1
|
|
47
|
+
chord_sq = dx * dx + dy * dy
|
|
48
|
+
|
|
49
|
+
if chord_sq < 1e-12:
|
|
50
|
+
dist_sq = np.square(x - x0) + np.square(y - y0)
|
|
51
|
+
idx = int(dist_sq.argmax())
|
|
52
|
+
return math.sqrt(float(dist_sq[idx])), idx
|
|
53
|
+
|
|
54
|
+
dist = dy * x
|
|
55
|
+
dist += dx * y
|
|
56
|
+
dist += y1 * x0 - y0 * x1
|
|
57
|
+
np.abs(dist, out=dist)
|
|
58
|
+
idx = int(dist.argmax())
|
|
59
|
+
return float(dist[idx]) / math.sqrt(chord_sq), idx
|
|
@@ -28,13 +28,16 @@ def test_max_deviation_is_invariant_to_rigid_transforms(angle, offset):
|
|
|
28
28
|
theta = np.deg2rad(angle)
|
|
29
29
|
axes = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
x, y = (points @ axes.T + offset).T
|
|
32
|
+
|
|
33
|
+
deviation, idx = find_max_deviation(x, y, x[0], y[0], x[-1], y[-1])
|
|
32
34
|
|
|
33
35
|
assert deviation == pytest.approx(2.0)
|
|
34
36
|
assert idx == 1
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def test_max_deviation_with_coincident_endpoints():
|
|
38
|
-
|
|
40
|
+
x = np.array([1.0, 4.0, 1.0])
|
|
41
|
+
y = np.array([2.0, 6.0, 2.0])
|
|
39
42
|
|
|
40
|
-
assert find_max_deviation(
|
|
43
|
+
assert find_max_deviation(x, y, 1.0, 2.0, 1.0, 2.0) == (5.0, 1)
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def discretize_boundary(boundary, max_dev_thresh):
|
|
7
|
-
num = len(boundary)
|
|
8
|
-
closed = np.vstack([boundary, boundary[0]])
|
|
9
|
-
keypoints = [boundary[0]]
|
|
10
|
-
|
|
11
|
-
start, end = 0, num
|
|
12
|
-
while start < num:
|
|
13
|
-
dev, idx = find_max_deviation(closed[start : end + 1])
|
|
14
|
-
# A peak at either end would not shrink the segment.
|
|
15
|
-
while dev > max_dev_thresh and 0 < idx < end - start:
|
|
16
|
-
end = start + idx
|
|
17
|
-
dev, idx = find_max_deviation(closed[start : end + 1])
|
|
18
|
-
|
|
19
|
-
if end < num:
|
|
20
|
-
keypoints.append(closed[end])
|
|
21
|
-
start, end = end, num
|
|
22
|
-
|
|
23
|
-
return np.array(keypoints)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def find_max_deviation(points):
|
|
27
|
-
x, y = points.T
|
|
28
|
-
x0, y0 = points[0].tolist()
|
|
29
|
-
x1, y1 = points[-1].tolist()
|
|
30
|
-
dx = x1 - x0
|
|
31
|
-
dy = y0 - y1
|
|
32
|
-
chord_sq = dx * dx + dy * dy
|
|
33
|
-
|
|
34
|
-
if chord_sq < 1e-12:
|
|
35
|
-
dist_sq = np.square(x - x0) + np.square(y - y0)
|
|
36
|
-
idx = int(dist_sq.argmax())
|
|
37
|
-
return math.sqrt(float(dist_sq[idx])), idx
|
|
38
|
-
|
|
39
|
-
dist = np.abs(dy * x + dx * y + (y1 * x0 - y0 * x1))
|
|
40
|
-
idx = int(dist.argmax())
|
|
41
|
-
return float(dist[idx]) / math.sqrt(chord_sq), idx
|
|
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
|
|
File without changes
|