-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#16 Added test scripts for diffusion and connected components.
WIP; not ready for automated testing.
- Loading branch information
1 parent
63abddf
commit bf1b8e1
Showing
2 changed files
with
207 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,93 @@ | ||
''' | ||
Unit test for connected_components | ||
''' | ||
import cc3d | ||
import lib.cpp.cpu.connected_components as cc | ||
import datetime | ||
from functools import partial | ||
import multiprocessing as mp | ||
from multiprocessing.pool import ThreadPool as tp | ||
import numpy as np | ||
import scipy.ndimage as ndi | ||
|
||
def test1(): | ||
a = np.array([ | ||
[0,0,0], | ||
[1,1,1], | ||
|
||
[1,0,2], | ||
[1,0,2], | ||
|
||
[1,0,2], | ||
[1,0,2], | ||
|
||
[1,1,1], | ||
[0,0,0], | ||
], dtype=np.int64).reshape(4, 2, 1, 3) | ||
labels_a = np.array([1, 2, 2, 1], dtype=np.int64) | ||
print (a.shape, labels_a.shape) | ||
print (a.reshape(8,3)) | ||
new_labels = cc.merge_labeled_chunks(a, labels_a, True) | ||
print (a.reshape(8,3)) | ||
print (new_labels) | ||
|
||
def test2(): | ||
a = np.array([ | ||
[0,0,0,0,0,0,0,0,0,0,0,0], | ||
[1,1,1,0,2,2,2,0,3,0,0,5], | ||
[1,0,2,2,2,0,3,0,0,4,0,6], | ||
[0,0,0,0,0,0,0,0,0,0,0,0], | ||
], dtype=np.int64).reshape(2, 2, 1, 12) | ||
labels_a = np.array([5,6], dtype=np.int64) | ||
print (a.shape, labels_a.shape) | ||
print (a.reshape(4,12)) | ||
new_labels = cc.merge_labeled_chunks(a, labels_a, True) | ||
print (a.reshape(4,12)) | ||
print (new_labels) | ||
|
||
def test3(): | ||
a = np.array([ | ||
[0,0,0,0,0,0,0,0,0,4,0,0], | ||
[1,1,1,0,2,2,2,0,3,0,0,5], | ||
|
||
[1,0,2,0,3,0,4,0,0,5,0,6], | ||
[1,0,2,0,3,0,4,0,0,0,0,6], | ||
|
||
[1,0,2,0,3,0,4,0,0,0,0,6], | ||
[1,0,2,0,3,0,4,0,0,5,0,6], | ||
|
||
[1,0,2,2,2,0,3,0,4,0,0,6], | ||
[0,0,0,0,0,0,0,0,0,5,0,0], | ||
], dtype=np.int64).reshape(4, 2, 1, 12) | ||
labels_a = np.array([5,6,6,6], dtype=np.int64) | ||
print (a.shape, labels_a.shape) | ||
print (a.reshape(8,12)) | ||
new_labels = cc.merge_labeled_chunks(a, labels_a, True) | ||
print (a.reshape(8,12)) | ||
print (new_labels) | ||
|
||
def test4(): | ||
a = np.array([ | ||
[0,0,0,0,0,0,0,4,0,5,0,0], | ||
[0,0,2,2,2,2,2,0,0,5,0,0], | ||
[0,0,2,0,0,0,2,0,0,5,0,0], | ||
[1,0,2,0,3,0,2,0,0,5,0,6], | ||
|
||
[1,0,2,0,3,0,1,0,0,5,0,6], | ||
[1,0,0,0,0,0,1,0,0,5,0,0], | ||
[1,1,1,1,1,1,1,0,0,5,0,0], | ||
[0,0,0,0,0,0,0,4,0,5,0,0], | ||
], dtype=np.int64).reshape(2, 4, 1, 12) | ||
labels_a = np.array([6,6], dtype=np.int64) | ||
|
||
print (a.shape, labels_a.shape) | ||
print (a.reshape(8,12)) | ||
new_labels = cc.merge_labeled_chunks(a, labels_a, True) | ||
print (a.reshape(8,12)) | ||
print (new_labels) | ||
|
||
if __name__ == '__main__': | ||
test1() | ||
test2() | ||
test3() | ||
test4() |
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,114 @@ | ||
''' | ||
Unit test for diffusion. | ||
Currently only tests in-memory diffusion, not the file-based one. | ||
''' | ||
import sys | ||
sys.path.append(sys.path[0]+'/../') | ||
import datetime | ||
import matplotlib | ||
matplotlib.use('Agg') | ||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
import scipy.ndimage as ndi | ||
|
||
from lib.cpp.cpu.diffusion import diffusion as diffusion_cpu | ||
from lib.cpp.gpu.diffusion import diffusion as diffusion_gpu | ||
|
||
n = 333 | ||
sigma = 4 # Radius has to be <= 16 for the GPU implementation | ||
reps = 1 | ||
plot = False | ||
|
||
# Generate a random 3d array and binarize it | ||
np.random.seed(42) | ||
a = np.random.rand(n, n, n) | ||
a = a > 0.99 | ||
|
||
# Get a gaussian kernel | ||
# Stolen from ndimage | ||
radius = round(4.0 * sigma) # stolen from the default scipy parameters | ||
sigma2 = sigma * sigma | ||
x = np.arange(-radius, radius+1) | ||
phi_x = np.exp(-0.5 / sigma2 * x ** 2) | ||
phi_x = phi_x / phi_x.sum() | ||
kernel = phi_x.astype(np.float32) | ||
print (f'Kernel shape: {kernel.shape}, radius: {radius}') | ||
|
||
# | ||
# Python implementation | ||
# | ||
python_start = datetime.datetime.now() | ||
buf0 = a.copy().astype(np.float32) | ||
buf1 = np.zeros_like(buf0) | ||
for _ in range(reps): | ||
buf1[:] = ndi.convolve1d(buf0, kernel, axis=0, mode='constant') | ||
buf0[:] = ndi.convolve1d(buf1, kernel, axis=1, mode='constant') | ||
buf1[:] = ndi.convolve1d(buf0, kernel, axis=2, mode='constant') | ||
buf1[a] = 1 | ||
buf0, buf1 = buf1, buf0 | ||
python_impl = np.floor(buf0 * 65535).astype(np.uint16) | ||
del buf1 | ||
python_end = datetime.datetime.now() | ||
print (f"Python implementation took {python_end - python_start}") | ||
|
||
if plot: | ||
plt.imshow(python_impl[n//2], cmap='gray') | ||
plt.savefig('python_impl.png') | ||
plt.close() | ||
plt.imshow(a[n//2], cmap='gray') | ||
plt.savefig('original.png') | ||
plt.close() | ||
|
||
# | ||
# Parallel CPU C++ implementation | ||
# | ||
cpp_start = datetime.datetime.now() | ||
cpp_impl = np.empty(a.shape, np.uint16) | ||
diffusion_cpu(a.astype(np.uint8), kernel, cpp_impl, reps) | ||
cpp_end = datetime.datetime.now() | ||
print (f"Parallel CPU C++ implementation took {cpp_end - cpp_start} ({(python_end - python_start) / (cpp_end - cpp_start):.2f}x)") | ||
|
||
if plot: | ||
plt.imshow(cpp_impl[n//2], cmap='gray') | ||
plt.savefig('cpp_impl.png') | ||
plt.close() | ||
|
||
# Check if the results are the same | ||
diff = np.abs(python_impl.astype(np.int32) - cpp_impl.astype(np.int32)) | ||
divergers = np.sum(diff > 0) | ||
divergers2 = np.sum(diff > 1) | ||
if divergers2 > 0: | ||
print (f"Found {divergers} diverging pixels out of ({n**3}) ({divergers / n**3 * 100:.2f}%)") | ||
print (f"Found {divergers2} pixels with a difference greater than 1 ({divergers2 / n**3 * 100:.2f}%)") | ||
assert np.all(diff <= 1) | ||
|
||
# | ||
# Parallel GPU C++ implementation | ||
# | ||
gpu_start = datetime.datetime.now() | ||
gpu_impl = np.empty(a.shape, np.uint16) | ||
diffusion_gpu(a.astype(np.uint8), kernel, gpu_impl, reps) | ||
gpu_end = datetime.datetime.now() | ||
print (f"Parallel GPU C++ implementation took {gpu_end - gpu_start} ({(python_end - python_start) / (gpu_end - gpu_start):.2f}x)") | ||
|
||
if plot: | ||
plt.imshow(gpu_impl[n//2], cmap='gray') | ||
plt.savefig('gpu_impl.png') | ||
plt.close() | ||
|
||
# Check if the results are the same | ||
diff = np.abs(python_impl.astype(np.int32) - gpu_impl.astype(np.int32)) | ||
divergers = np.sum(diff > 0) | ||
divergers2 = np.sum(diff > 1) | ||
if divergers2 > 0: | ||
print (f"Found {divergers} diverging pixels out of ({n**3}) ({divergers / n**3 * 100:.2f}%)") | ||
print (f"Found {divergers2} pixels with a difference greater than 1 ({divergers2 / n**3 * 100:.2f}%)") | ||
if plot: | ||
plt.imshow(diff[n//2]) | ||
plt.colorbar() | ||
plt.savefig('diff.png') | ||
plt.close() | ||
checksum = np.sum(gpu_impl) | ||
print (f"Checksum of GPU: {checksum != 0} ({checksum})") | ||
assert np.all(diff <= 1) |