Skip to content

Commit

Permalink
Add tests and initial translation for a Python version
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-riecken committed Jul 6, 2024
1 parent 7cfd81f commit 0fc974c
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 0 deletions.
99 changes: 99 additions & 0 deletions src/shape_carve.py
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}

170 changes: 170 additions & 0 deletions src/test_shape_carve.py
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'."

0 comments on commit 0fc974c

Please sign in to comment.