diff --git a/README.md b/README.md index 7211620..bdf0cf3 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,22 @@ From left to right: reference image, initial state, and optimization process. ![](https://raw.githubusercontent.com/hiroharu-kato/neural_renderer/master/examples/data/example4_ref.png) ![](https://raw.githubusercontent.com/hiroharu-kato/neural_renderer/master/examples/data/example4_init.png) ![](https://raw.githubusercontent.com/hiroharu-kato/neural_renderer/master/examples/data/example4_result.gif) +## Testing + +For development; be sure to use a `virtualenv` when you can! + +```sh +# Build. +pip install torch +# - Be sure to set your CUDA environment variables for building the kernels! +pip install -e . + +# Install test deps +pip install scikit-image +# Discover / run tests +cd ./tests +python -m unittest discover -t . +``` ## Citation diff --git a/tests/test_rasterize.py b/tests/test_rasterize.py index 3005b54..4c58b6e 100644 --- a/tests/test_rasterize.py +++ b/tests/test_rasterize.py @@ -77,9 +77,11 @@ def test_forward_case3(self): # load reference image by blender ref = imread(os.path.join(data_dir, 'teapot_blender.png')) - ref = (ref.min(axis=-1) != 255).astype(np.float32) + ref = utils.guess_foreground_mask(ref) - assert(np.allclose(ref, image)) + image = image.astype(bool) + iou = utils.calc_mask_iou(image.astype(bool), ref) + self.assertGreater(iou, 0.999) def test_backward_case1(self): """Backward if non-zero gradient is out of a face.""" diff --git a/tests/test_rasterize_depth.py b/tests/test_rasterize_depth.py index 52b2283..7ce903a 100644 --- a/tests/test_rasterize_depth.py +++ b/tests/test_rasterize_depth.py @@ -30,9 +30,10 @@ def test_forward_case1(self): # load reference image by blender ref = imread(os.path.join(data_dir, 'teapot_blender.png')) - ref = (ref.min(axis=-1) != 255).astype(np.float32) + ref = utils.guess_foreground_mask(ref) - assert(np.allclose(ref, image)) + iou = utils.calc_mask_iou(ref, image) + self.assertGreater(iou, 0.999) def test_forward_case2(self): # load teapot @@ -46,12 +47,23 @@ def test_forward_case2(self): images = renderer(vertices, faces, mode='depth') images = images.detach().cpu().numpy() image = images[2] + mask = image != image.max() image[image == image.max()] = image.min() image = (image - image.min()) / (image.max() - image.min()) ref = imread(os.path.join(data_dir, 'test_depth.png')).astype(np.float32) / 255. + ref_mask = ref != 0.0 - assert(np.allclose(image, ref, atol=1e-2)) + iou = utils.calc_mask_iou(ref_mask, mask) + self.assertGreater(iou, 0.998) + + # Check difference along intersection (which should be OK-ish). + intersect = mask & ref_mask + image[~intersect] = 0.0 + ref[~intersect] = 0.0 + + # Shrug. + np.testing.assert_allclose(image, ref, atol=0.0089, rtol=0.0) def test_backward_case1(self): vertices = [ diff --git a/tests/test_rasterize_silhouettes.py b/tests/test_rasterize_silhouettes.py index 63459c5..2e5679b 100644 --- a/tests/test_rasterize_silhouettes.py +++ b/tests/test_rasterize_silhouettes.py @@ -30,9 +30,10 @@ def test_case1(self): # load reference image by blender ref = imread(os.path.join(data_dir, 'teapot_blender.png')) - ref = (ref.min(-1) != 255).astype(np.float32) + ref = utils.guess_foreground_mask(ref) - assert(np.allclose(ref, image)) + iou = utils.calc_mask_iou(image.astype(bool), ref) + self.assertGreater(iou, 0.999) def test_backward_case1(self): """Backward if non-zero gradient is out of a face.""" diff --git a/tests/utils.py b/tests/utils.py index 842e33f..85d97db 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,6 @@ import os +import numpy as np import torch import neural_renderer as nr @@ -25,3 +26,19 @@ def load_teapot_batch(batch_size=4, target_num=2): textures = torch.ones((faces.shape[0], 4, 4, 4, 3), dtype=torch.float32) vertices, faces, textures = to_minibatch((vertices, faces, textures), batch_size, target_num) return vertices, faces, textures + +def guess_foreground_mask(ref, bg_uv=(0, 0)): + assert ref.ndim == 3 + bg_pixel = ref[bg_uv].reshape((1, 1, -1)) + return (ref != bg_pixel).any(axis=2) + +def calc_mask_iou(a, b): + assert a.dtype == bool + assert b.dtype == bool + assert a.shape == b.shape + union = np.sum(a | b) + if union == 0.0: + return 0.0 + else: + intersect = np.sum(a & b) + return intersect / union