-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests and initial translation for a Python version
- Loading branch information
1 parent
7cfd81f
commit 0fc974c
Showing
2 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
def ShapeCarve(dims, views, mask_color, skip): | ||
x = [0] * 3 | ||
volume = [-1] * (dims[0] * dims[1] * dims[2]) | ||
depth = [] | ||
|
||
# Initialize volume | ||
for i in range(len(volume)): | ||
volume[i] = -1 | ||
|
||
# Initialize depth fields | ||
for d in range(3): | ||
u = (d+1)%3 | ||
v = (d+2)%3 | ||
for s in range(0, dims[d], max(1, dims[d] - 1)): | ||
vals = [0] * (dims[u] * dims[v]) | ||
view = views[len(depth)] | ||
s_op = dims[d]-1 if s == 0 else 0 | ||
for i in range(len(vals)): | ||
vals[i] = s_op if not skip[len(depth)] and view[i] == mask_color else s | ||
depth.append(vals) | ||
|
||
# Clear out volume | ||
for x[v] in range(dims[v]): | ||
for x[u] in range(dims[u]): | ||
for x[d] in range(depth[2*d+1][x[u]+x[v]*dims[u]], depth[2*d][x[u]+x[v]*dims[u]] + 1): | ||
volume[x[0]+dims[0]*(x[1] + dims[1]*x[2])] = mask_color | ||
|
||
# Perform iterative seam carving until convergence | ||
removed = 1 | ||
while removed > 0: | ||
removed = 0 | ||
for d in range(3): | ||
u = (d+1)%3 | ||
v = (d+2)%3 | ||
|
||
# Do front/back sweep | ||
for s in range(-1, 2, 2): | ||
v_num = 2*d + (1 if s<0 else 0) | ||
if skip[v_num]: | ||
continue | ||
|
||
aview = views[v_num] | ||
adepth = depth[v_num] | ||
|
||
for x[v] in range(dims[v]): | ||
for x[u] in range(dims[u]): | ||
|
||
# March along ray | ||
buf_idx = x[u] + x[v]*dims[u] | ||
for x[d] in range(adepth[buf_idx], dims[d], s): | ||
|
||
# Read volume color | ||
vol_idx = x[0] + dims[0] * (x[1] + dims[1] * x[2]) | ||
color = volume[vol_idx] | ||
if color == mask_color: | ||
continue | ||
|
||
color = volume[vol_idx] = aview[x[u] + dims[u] * x[v]] | ||
|
||
# Check photoconsistency of volume at x | ||
consistent = True | ||
for a in range(3): | ||
if not consistent: | ||
break | ||
|
||
b = (a+1)%3 | ||
c = (a+2)%3 | ||
idx = x[b] + dims[b] * x[c] | ||
for t in range(2): | ||
fnum = 2*a+t | ||
if skip[fnum]: | ||
continue | ||
fcolor = views[fnum][idx] | ||
fdepth = depth[fnum][idx] | ||
if (t and fdepth <= x[a]) or (not t and x[a] <= fdepth): | ||
if fcolor != color: | ||
consistent = False | ||
break | ||
if consistent: | ||
break | ||
|
||
# Clear out voxel | ||
removed += 1 | ||
volume[vol_idx] = mask_color | ||
|
||
# Update depth value | ||
adepth[buf_idx] = x[d] | ||
|
||
# Do a final pass to fill in any missing colors | ||
n = 0 | ||
for x[2] in range(dims[2]): | ||
for x[1] in range(dims[1]): | ||
for x[0] in range(dims[0]): | ||
if volume[n] < 0: | ||
volume[n] = 0xff00ff | ||
n += 1 | ||
|
||
return {"volume": volume, "dims": dims} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import unittest | ||
from greedy import * | ||
from shape_carve import * | ||
|
||
# views has bhwc format. For simplicity we only allow square faces. For now we assume one color channel that can be 0 | ||
# (black) or 1 (white) | ||
# case 0: 1x1x1 cube, all white | ||
views = [ | ||
[[[1]]], # left | ||
[[[1]]], # back | ||
[[[1]]], # bottom | ||
[[[1]]], # right | ||
[[[1]]], # front | ||
[[[1]]], # top | ||
] | ||
|
||
# case 1: 2x2x2 cube. Top half is red, bottom half is blue. | ||
# colors given in comments are from my Rubik's cube. | ||
# the turning in rubik notation is: | ||
# u', f, u', f, u' | ||
views = [ | ||
[ | ||
[[1, 0, 0], [1, 0, 0]], | ||
[[0, 0, 1], [0, 0, 1]], | ||
], # left, blue | ||
[ | ||
[[1, 0, 0], [1, 0, 0]], | ||
[[0, 0, 1], [0, 0, 1]], | ||
], # back, red | ||
[ | ||
[[0, 0, 1], [0, 0, 1]], | ||
[[0, 0, 1], [0, 0, 1]], | ||
], # bottom, yellow | ||
[ | ||
[[1, 0, 0], [0, 0, 1]], | ||
[[1, 0, 0], [0, 0, 1]], | ||
], # right, green | ||
[ | ||
[[1, 0, 0], [0, 0, 1]], | ||
[[1, 0, 0], [0, 0, 1]], | ||
], # front, orange | ||
[ | ||
[[1, 0, 0], [1, 0, 0]], | ||
[[1, 0, 0], [1, 0, 0]], | ||
], # top, white | ||
] | ||
|
||
# case 2: 3x3x3 cube of a 3x1x3 frame in the back. | ||
views = [ | ||
[ | ||
[[1], [0], [0]], | ||
[[1], [0], [0]], | ||
[[1], [0], [0]], | ||
], # left, blue | ||
[ | ||
[[1], [1], [1]], | ||
[[1], [0], [1]], | ||
[[1], [1], [1]], | ||
], # back, red | ||
[ | ||
[[1], [1], [1]], | ||
[[0], [0], [0]], | ||
[[0], [0], [0]], | ||
], # bottom, yellow | ||
[ | ||
[[1], [1], [1]], | ||
[[0], [0], [0]], | ||
[[0], [0], [0]], | ||
], # right, green | ||
[ | ||
[[1], [1], [1]], | ||
[[1], [0], [1]], | ||
[[1], [1], [1]], | ||
], # front, orange | ||
[ | ||
[[1], [0], [0]], | ||
[[1], [0], [0]], | ||
[[1], [0], [0]], | ||
], # top, white | ||
] | ||
|
||
# case 3, 3x3x3 cube of a 3d plus with the Rubik cube's colors, where each color | ||
# wins over the two colors following it (blue > red, blue > yellow, etc.) | ||
# yellow: [1, 1, 0] | ||
# instead of orange we'll use magenta: [1, 0, 1] | ||
# color ring: brygowb | ||
views = [ | ||
[ | ||
[[0, 0, 0], [1, 1, 1], [0, 0, 0]], | ||
[[0, 0, 1], [0, 0, 0], [1, 0, 1]], | ||
[[0, 0, 0], [0, 0, 1], [0, 0, 0]], | ||
], # left, blue | ||
[ | ||
[[0, 0, 0], [1, 1, 1], [0, 0, 0]], | ||
[[1, 0, 0], [0, 0, 0], [0, 0, 1]], | ||
[[0, 0, 0], [1, 0, 0], [0, 0, 0]], | ||
], # back, red | ||
[ | ||
[[0, 0, 0], [1, 0, 0], [0, 0, 0]], | ||
[[1, 1, 0], [0, 0, 0], [0, 0, 1]], | ||
[[0, 0, 0], [1, 1, 0], [0, 0, 0]], | ||
], # bottom, yellow | ||
[ | ||
[[0, 0, 0], [1, 0, 0], [0, 0, 0]], | ||
[[0, 1, 0], [0, 0, 0], [1, 1, 0]], | ||
[[0, 0, 0], [0, 1, 0], [0, 0, 0]], | ||
], # right, green | ||
[ | ||
[[0, 0, 0], [0, 1, 0], [0, 0, 0]], | ||
[[1, 0, 1], [0, 0, 0], [1, 1, 0]], | ||
[[0, 0, 0], [1, 0, 1], [0, 0, 0]], | ||
], # front, orange | ||
[ | ||
[[0, 0, 0], [0, 1, 0], [0, 0, 0]], | ||
[[1, 1, 1], [0, 0, 0], [1, 0, 1]], | ||
[[0, 0, 0], [1, 1, 1], [0, 0, 0]], | ||
], # top, white | ||
] | ||
|
||
|
||
# class TestMeshFunctions(unittest.TestCase): | ||
# def test_GreedyMesh(self): | ||
# volume = [1, 2, 3, 4, 5] | ||
# dims = [1, 2, 2] | ||
# result = GreedyMesh(volume, dims) | ||
# self.assertIsInstance(result, dict) | ||
# self.assertIn('vertices', result) | ||
# self.assertIn('faces', result) | ||
|
||
# def test_ShapeCarve(self): | ||
# dims = [1, 2, 2] | ||
# views = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]] | ||
# mask_color = 1 | ||
# skip = [False, False] | ||
# result = ShapeCarve(dims, views, mask_color, skip) | ||
# self.assertIsInstance(result, dict) | ||
# self.assertIn('volume', result) | ||
# self.assertIn('dims', result) | ||
# self.assertEqual(result['dims'], dims) | ||
|
||
# if __name__ == '__main__': | ||
# unittest.main() | ||
|
||
# Prepare dummy data for GreedyMesh | ||
volume = [1, 2, 3, 4, 5] | ||
dims = [1, 2, 2] | ||
|
||
# Run GreedyMesh | ||
result_greedy = GreedyMesh(volume, dims) | ||
|
||
# Check the types and keys of the returned object from GreedyMesh | ||
assert isinstance(result_greedy, dict), "The result should be a dictionary." | ||
assert 'vertices' in result_greedy, "The key 'vertices' should be in the result." | ||
assert 'faces' in result_greedy, "The key 'faces' should be in the result." | ||
|
||
# Prepare dummy data for ShapeCarve | ||
dims = [1, 2, 2] | ||
views = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]] | ||
mask_color = 1 | ||
skip = [False, False] | ||
|
||
# Run ShapeCarve | ||
# result_shape = ShapeCarve(dims, views, mask_color, skip) | ||
|
||
# Check the types and keys of the returned object from ShapeCarve | ||
# assert isinstance(result_shape, dict), "The result should be a dictionary." | ||
# assert 'volume' in result_shape, "The key 'volume' should be in the result." | ||
# assert 'dims' in result_shape, "The key 'dims' should be in the result." | ||
# assert result_shape['dims'] == dims, "The 'dims' value should be equal to the input 'dims'." | ||
|