Skip to content

Commit 8e35bcf

Browse files
committed
Get numpy imaging application working
1 parent 7c1c760 commit 8e35bcf

File tree

3 files changed

+260
-69
lines changed

3 files changed

+260
-69
lines changed

numpy/image.py

+112-69
Original file line numberDiff line numberDiff line change
@@ -3,76 +3,119 @@
33
import os
44
import pytest
55
import matplotlib.pyplot as plt
6+
import sparse
7+
from util import ImagePydataSparseTensorLoader, safeCastPydataTensorToInts, plot_image
8+
9+
10+
11+
@pytest.mark.parametrize("num", list(range(1, 99)))
12+
@pytest.mark.parametrize("pt1", [0.5])
13+
def bench_edge_detection_pydata(tacoBench, num, pt1, plot):
14+
loader = ImagePydataSparseTensorLoader()
15+
sparse_bin_img1 = safeCastPydataTensorToInts(loader.sparse_image(num, pt1, 1))
16+
sparse_bin_img2 = safeCastPydataTensorToInts(loader.sparse_image(num, pt1+0.05, 2))
17+
bin_img1 = loader.dense_image(num, pt1, 1)
18+
bin_img2 = loader.dense_image(num, pt1 + 0.05, 2)
19+
if plot:
20+
print(sparse_bin_img1.shape)
21+
print(sparse_bin_img2.shape)
22+
23+
def sparse_bench():
24+
sparse_xor_img = np.logical_xor(sparse_bin_img1, sparse_bin_img2).astype('int')
25+
return sparse_xor_img
26+
27+
def dense_bench():
28+
xor_img = np.logical_xor(bin_img1, bin_img2).astype('int')
29+
return xor_img
30+
ret = tacoBench(sparse_bench)
31+
sparse_xor_img = sparse_bench()
32+
xor_img = dense_bench()
33+
34+
assert(sparse_xor_img.nnz == np.sum(xor_img != 0))
35+
36+
if plot:
37+
num_elements = float(np.prod(bin_img1.shape))
38+
print("Sparse xor NNZ = ", sparse_xor_img.nnz, "\t", "Dense xor NNZ = ", np.sum(xor_img != 0))
39+
print("Sparsity img 1 ", np.sum(bin_img1 != 0) / num_elements)
40+
print("Sparsity img 2 ", np.sum(bin_img2 != 0) / num_elements)
41+
print("Sparsity xor ", np.sum(xor_img != 0) / num_elements)
42+
sparse_xor_img = sparse_xor_img.todense()
43+
t1 = round(loader.max[num]*pt1, 2)
44+
t2 = round(loader.max[num]*(pt1 + 0.05), 2)
45+
plot_image(loader.img[num], bin_img1, bin_img2, xor_img, sparse_xor_img, t1, t2)
46+
47+
@pytest.mark.parametrize("num", list(range(1, 99)))
48+
@pytest.mark.parametrize("pt1", [0.5])
49+
def bench_edge_detection_dense(tacoBench, num, pt1):
50+
loader = ImagePydataSparseTensorLoader()
51+
bin_img1 = loader.dense_image(num, pt1, 1)
52+
bin_img2 = loader.dense_image(num, pt1 + 0.05, 2)
53+
54+
def dense_bench():
55+
xor_img = np.logical_xor(bin_img1, bin_img2).astype('int')
56+
return xor_img
57+
tacoBench(dense_bench)
58+
59+
@pytest.mark.parametrize("num", list(range(1, 99)))
60+
@pytest.mark.parametrize("pt1", [0.5])
61+
def bench_edge_detection_fused_pydata(tacoBench, num, pt1, plot):
62+
loader = ImagePydataSparseTensorLoader()
63+
sparse_bin_img1 = safeCastPydataTensorToInts(loader.sparse_image(num, pt1, 1))
64+
sparse_bin_img2 = safeCastPydataTensorToInts(loader.sparse_image(num, pt1+0.05, 2))
65+
sparse_bin_window = loader.sparse_window(num, 3)
66+
bin_img1 = loader.dense_image(num, pt1, 1)
67+
bin_img2 = loader.dense_image(num, pt1 + 0.05, 2)
68+
bin_window = loader.dense_window(num)
69+
70+
if plot:
71+
print(sparse_bin_img1.shape)
72+
print(sparse_bin_img2.shape)
73+
74+
def sparse_bench():
75+
sbi1 = np.logical_and(sparse_bin_img1, sparse_bin_window)
76+
sbi2 = np.logical_and(sparse_bin_img2, sparse_bin_window)
77+
sparse_xor_img = np.logical_xor(sbi1, sbi2).astype('int')
78+
return sparse_xor_img
79+
80+
def dense_bench():
81+
bi1 = np.logical_and(bin_img1, bin_window).astype('int')
82+
bi2 = np.logical_and(bin_img2, bin_window).astype('int')
83+
xor_img = np.logical_xor(bi1, bi2).astype('int')
84+
return xor_img
85+
ret = tacoBench(sparse_bench)
86+
sparse_xor_img = sparse_bench()
87+
xor_img = dense_bench()
88+
89+
if plot:
90+
num_elements = float(np.prod(bin_img1.shape))
91+
print("Sparse xor NNZ = ", sparse_xor_img.nnz, "\t", "Dense xor NNZ = ", np.sum(xor_img != 0))
92+
print("Sparsity img 1 ", np.sum(bin_img1 != 0) / num_elements)
93+
print("Sparsity img 2 ", np.sum(bin_img2 != 0) / num_elements)
94+
print("Sparsity xor ", np.sum(xor_img != 0) / num_elements)
95+
sparse_xor_img = sparse_xor_img.todense()
96+
t1 = round(loader.max[num]*pt1, 2)
97+
t2 = round(loader.max[num]*(pt1 + 0.05), 2)
98+
plot_image(loader.img[num], bin_img1, bin_img2, xor_img, sparse_xor_img, t1, t2, bin_window)
99+
100+
assert(sparse_xor_img.nnz == np.sum(xor_img != 0))
101+
102+
@pytest.mark.parametrize("num", list(range(1, 99)))
103+
@pytest.mark.parametrize("pt1", [0.5])
104+
def bench_edge_detection_fused_dense(tacoBench, num, pt1):
105+
loader = ImagePydataSparseTensorLoader()
106+
bin_img1 = loader.dense_image(num, pt1, 1)
107+
bin_img2 = loader.dense_image(num, pt1 + 0.05, 2)
108+
bin_window = loader.dense_window(num)
109+
110+
def dense_bench():
111+
bi1 = np.logical_and(bin_img1, bin_window).astype('int')
112+
bi2 = np.logical_and(bin_img2, bin_window).astype('int')
113+
xor_img = np.logical_xor(bin_img1, bin_img2).astype('int')
114+
return xor_img
115+
tacoBench(dense_bench)
116+
117+
#TODO: Add in a benchmark that uses windowing for medical imaging as well.
6118

7-
images_path = "./numpy/images"
8-
9-
def load_dataset(image_folder):
10-
files = sorted(os.listdir(image_folder))
11-
images = []
12-
for f in files:
13-
path = os.path.join(image_folder, f)
14-
img = cv2.imread(path)
15-
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
16-
images.append(img)
17-
18-
images = np.stack(images, axis=0)
19-
return images
20-
21-
def thresh(images, t=85):
22-
if len(images.shape) < 3:
23-
images = np.expand_dims(images, axis=0)
24-
thresh_imgs = []
25-
for i in range(images.shape[0]):
26-
img = images[i]
27-
ret, thresh_img = cv2.threshold(img, t, 255, cv2.THRESH_BINARY)
28-
thresh_imgs.append(thresh_img)
29-
30-
thresh_imgs = np.stack(thresh_imgs, axis=0)
31-
return thresh_imgs
32-
33-
def plot_image(img, img1, img2, xor_img, t1, t2):
34-
f, ax = plt.subplots(2, 2)
35-
ax[0, 0].imshow(img1, 'gray')
36-
ax[0, 0].title.set_text("Binned Image 1. t1 = " + str(t1))
37-
38-
ax[0, 1].imshow(img2, 'gray')
39-
ax[0, 1].title.set_text("Binned Image 2. t2 = " + str(t2))
40-
41-
ax[1, 0].imshow(img, 'gray')
42-
ax[1, 0].title.set_text("Saturdated Image")
43-
44-
ax[1, 1].imshow(xor_img, 'gray')
45-
ax[1, 1].title.set_text("XOR Image")
46-
47-
f.tight_layout()
48-
plt.show()
49-
50-
@pytest.mark.parametrize("t1", [100, 150, 200, 250])
51-
def bench_edge_detection(tacoBench, t1, plot):
52-
images = load_dataset(images_path)
53-
54-
sat_images = images[:,:,:,1]
55-
56-
img = sat_images[0]
57-
58-
t2 = t1 - 50
59-
60-
bin_img1 = thresh(img, t1)
61-
bin_img2 = thresh(img, t2)
62-
num_elements = float(np.prod(bin_img1.shape))
63-
64-
def bench():
65-
xor_img = np.logical_xor(bin_img1[0], bin_img2[0]).astype('int')
66-
return xor_img
67-
ret = tacoBench(bench)
68-
xor_img = bench()
69-
if plot:
70-
plot_image(img, bin_img1[0], bin_img2[0], xor_img, t1, t2)
71-
72-
print("Sparsity img 1 ", np.sum(bin_img1 != 0) / num_elements)
73-
print("Sparsity img 2 ", np.sum(bin_img2 != 0) / num_elements)
74-
print("Sparsity xor ", np.sum(xor_img != 0) / num_elements)
75-
76119
if __name__=="__main__":
77120
main()
78121

numpy/util.py

+147
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import os
55
import glob
66
import numpy
7+
import cv2
8+
import matplotlib.pyplot as plt
79

810
# Get the path to the directory holding random tensors. Error out
911
# if this isn't set.
@@ -52,6 +54,9 @@ def dump_dict_to_file(self, shape, data, path):
5254
strings = coords + [str(line[-1])]
5355
f.write(" ".join(strings))
5456
f.write("\n")
57+
shape_strings = [str(elem) for elem in shape] + ['0']
58+
f.write(" ".join(shape_strings))
59+
f.write("\n")
5560

5661
# ScipySparseTensorLoader loads a sparse tensor from a file into a
5762
# scipy.sparse CSR matrix.
@@ -284,3 +289,145 @@ def safeCastPydataTensorToInts(tensor):
284289
else:
285290
data[i] = int(tensor.data[i])
286291
return sparse.COO(tensor.coords, data, tensor.shape)
292+
293+
294+
###########################
295+
# Imaging Benchmark Utils #
296+
###########################
297+
298+
# load_image loads an image with the correct color format for the numpy/image.py
299+
# benchmark
300+
def load_image(image_folder, num):
301+
if image_folder == 'no':
302+
image_folder = "./data/image/no"
303+
else:
304+
image_folder = "./data/image/yes"
305+
306+
name = "image" + str(num) + '.'
307+
file_names = [fn for fn in os.listdir(image_folder)
308+
if fn.startswith(name)]
309+
path = os.path.join(image_folder, file_names[0])
310+
img = cv2.imread(path)
311+
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
312+
return img
313+
314+
# plot_image plots the given original, binned, xor, and sparse xor images
315+
# for the numpy/image.py. Used for debugging only with the --plot flag
316+
def plot_image(img, img1, img2, xor_img, sparse_xor_img, t1, t2, window=None):
317+
f, ax = plt.subplots(2, 3)
318+
ax[0, 0].imshow(img1, 'gray')
319+
ax[0, 0].title.set_text("Binned Image 1. t1 = " + str(t1))
320+
321+
ax[0, 1].imshow(img2, 'gray')
322+
ax[0, 1].title.set_text("Binned Image 2. t2 = " + str(t2))
323+
324+
ax[1, 0].imshow(img, 'gray')
325+
ax[1, 0].title.set_text("Saturdated Image")
326+
327+
ax[1, 1].imshow(xor_img, 'gray')
328+
ax[1, 1].title.set_text("XOR Image")
329+
330+
ax[1, 2].imshow(sparse_xor_img, 'gray')
331+
ax[1, 2].title.set_text("Sparse XOR Image")
332+
333+
if window is not None:
334+
ax[0, 2].imshow(window, 'gray')
335+
ax[0, 2].title.set_text("Fused Window Image")
336+
337+
f.tight_layout()
338+
plt.show()
339+
340+
# thresh thresholdes the given image by a threshold
341+
def thresh(images, t=85):
342+
if len(images.shape) < 3:
343+
images = numpy.expand_dims(images, axis=0)
344+
thresh_imgs = []
345+
for i in range(images.shape[0]):
346+
img = images[i]
347+
ret, thresh_img = cv2.threshold(img, t, 255, cv2.THRESH_BINARY)
348+
thresh_imgs.append(thresh_img)
349+
350+
thresh_imgs = numpy.stack(thresh_imgs, axis=0)
351+
return thresh_imgs
352+
353+
# construct_image_tensor_key constructs a unique key that represents
354+
# an image tensor parameterized by the image number and threshold.
355+
# The key itself is formatted by the image number, followed by the
356+
# threshold. For example, image1.* image with threshold of 0.5
357+
# would have a key of image1-0.05.tns.
358+
def construct_image_tensor_key(num, pt, variant):
359+
path = TENSOR_PATH
360+
name = "image" + str(num)
361+
if variant is None:
362+
key = "{}-{}.tns".format(dims, pt)
363+
else:
364+
key = "{}-{}-{}.tns".format(name, pt, variant)
365+
return os.path.join(path, "image", "tensors", key)
366+
367+
# ImagePydataSparseTensorLoader is the same as RandomPydataSparseTensorLoader
368+
# but for images loaded from memory and converted to sparse.COO tensors
369+
class ImagePydataSparseTensorLoader:
370+
def __init__(self):
371+
self.loader = PydataSparseTensorLoader()
372+
self.img = dict()
373+
self.max = dict()
374+
self.shape = dict()
375+
376+
def dense_image(self, num, pt, variant=None, path='no'):
377+
# Used for verification and baseline only.
378+
# Do not need to write to output file
379+
if num not in self.img.keys():
380+
self.img[num] = load_image(path, num)
381+
self.max[num] = numpy.max(self.img[num])
382+
383+
img = self.img[num]
384+
t = self.max[num]*pt
385+
bin_img = thresh(img, t)[0]
386+
self.shape[num] = bin_img.shape
387+
return bin_img
388+
389+
def sparse_image(self, num, pt, variant=None, path='no'):
390+
key = construct_image_tensor_key(num, pt, variant)
391+
# If an image with these properties exists already, then load it.
392+
if os.path.exists(key):
393+
result = self.loader.load(key)
394+
self.shape[num] = result.shape
395+
return result
396+
else:
397+
# Otherwise, we must create load the image and preprocess it with the desired properties.
398+
# dump it to the output file, then return it.
399+
bin_img = self.dense_image(num, pt, variant, path)
400+
result = sparse.COO.from_numpy(bin_img)
401+
dok = sparse.DOK(result)
402+
TnsFileDumper().dump_dict_to_file(self.shape[num], dok.data, key)
403+
return result
404+
405+
# sparse_window and dense_window must be called after the image calls
406+
def sparse_window(self, num, variant=3):
407+
path = TENSOR_PATH
408+
key = "image"+str(num) + "-" + str(variant) + ".tns"
409+
key = os.path.join(path, "image", "tensors", key)
410+
411+
shape = self.shape[num]
412+
413+
if os.path.exists(key):
414+
return self.loader.load(key)
415+
else:
416+
result_np = self.dense_window(num)
417+
result = sparse.COO.from_numpy(result_np)
418+
dok = sparse.DOK(result)
419+
TnsFileDumper().dump_dict_to_file(shape, dok.data, key)
420+
return result
421+
422+
def dense_window(self, num):
423+
shape = self.shape[num]
424+
result_np = numpy.zeros(shape)
425+
m0 = int(shape[0] / 2)
426+
m1 = int(shape[1] / 2)
427+
dm0 = int(0.2*m0)
428+
dm1 = int(0.2*m1)
429+
result_np[m0+dm0:m0+3*dm0, m1+dm1:m1+3*dm1] = 1
430+
result_np[m0-3*dm0:m0-dm0, m1+dm1:m1+3*dm1] = 1
431+
result_np[m0-3*dm0:m0-dm0, m1-3*dm1:m1-dm1] = 1
432+
result_np[m0+dm0:m0+3*dm0, m1-3*dm1:m1-dm1] = 1
433+
return result_np

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
attrs==20.3.0
2+
matplotlib==3.1.1
23
importlib-metadata==3.7.3
34
iniconfig==1.1.1
45
llvmlite==0.36.0

0 commit comments

Comments
 (0)