import numpy as np import pytest from fastai.transforms import * t_rand_img128x128x1 = np.random.uniform(size=[128,128,1]) t_rand_img128x128x3 = np.random.uniform(size=[128,128,3]) # # # as per https://stackoverflow.com/questions/7100242/python-numpy-first-occurrence-of-subarray # def rolling_window(a, size): # shape = a.shape[:-1] + (a.shape[-1] - size + 1, size) # strides = a.strides + (a. strides[-1],) # return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) def test_scale_min_works_with_masks(): mask = np.ones([128, 256], dtype=np.float32) mask[0:64,0:128] = 20 em = np.array([[20., 20., 1., 1.], [1., 1., 1., 1.]], dtype=np.float32) msmall = scale_min(mask, 2, cv2.INTER_NEAREST) np.testing.assert_equal(msmall, em, "sacle_min can scale down a mask") mlarge = scale_min(msmall, 128, cv2.INTER_NEAREST) np.testing.assert_equal(mlarge, mask, "sacle_min can scale up a mask") def test_scale_min_works_with_rgb(): r_layer = np.ones([128, 256], dtype=np.float32) r_layer[0:64, 0:128] = 0.5 im = np.stack([r_layer, np.zeros_like(r_layer), np.ones_like(r_layer)], axis=-1) r_layer_small = np.array([[0.5, 0.5, 1., 1.], [1., 1., 1., 1.]]) im_small = scale_min(im, 2, cv2.INTER_AREA) np.testing.assert_equal(im_small[..., 0], r_layer_small, "sacle_min can scale down an rgb image") assert im_small[..., 1].sum() == 0, "sacle_min can scale down an rgb image" assert im_small[..., 2].max() == im_small[..., 2].min() == 1, "sacle_min can scale down an rgb image" im_large = scale_min(im_small, 128, cv2.INTER_AREA) np.testing.assert_equal(im_large[..., 0], r_layer, "sacle_min can scale up an rgb image") assert im_large[..., 1].sum() == 0, "sacle_min can scale down an rgb image" assert im_large[..., 2].max() == im_large[..., 2].min() == 1, "sacle_min can scale down an rgb image" def test_zoom_cv(): r_layer = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) im = np.stack([r_layer, np.zeros_like(r_layer), np.ones_like(r_layer)], axis=-1) np.testing.assert_equal(zoom_cv(im, 0), im, "Z==0 leaves image unchanged") # TODO: Figure out why the circle is moved slightly to the top left corner. expect = np.array([[0, 0, 0, 0, 0.], [0, 0.01562, 0.12109, 0.00391, 0.], [0, 0.12109, 0.93848, 0.03027, 0.], [0, 0.00391, 0.03027, 0.00098, 0.], [0, 0, 0, 0, 0.],], dtype=np.float32) actual = zoom_cv(im, 0.1)[..., 0] print(actual) np.testing.assert_array_almost_equal(actual, expect, decimal=5) def test_stretch_cv(): im = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) np.testing.assert_equal(stretch_cv(im, sr=0, sc=0), im, "sr==0 && sc==0 leaves image unchanged") expect = np.array([[0, 0, 0, 0, 0.], [0, 0., 0, 0, 0.], [0, 0., 0.64, 0.24, 0.], [0, 0., 0.24, 0.09, 0.], [0, 0, 0, 0, 0.],], dtype=np.float32) actual = stretch_cv(im, 0.1, 0.1) print(actual) np.testing.assert_array_almost_equal(actual, expect, decimal=5) expect = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) actual = stretch_cv(im, 1, 0) print(actual) np.testing.assert_array_almost_equal(actual, expect, decimal=5) expect = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) actual = stretch_cv(im, 1, 1) print(actual) np.testing.assert_array_almost_equal(actual, expect, decimal=5) expect = np.array([[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) actual = stretch_cv(im, 2, 2) print(actual) np.testing.assert_array_almost_equal(actual, expect, decimal=5) @pytest.mark.skip(reason="It does not work for some reason see #429") def test_zoom_cv_equals_stretch_cv(): im = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) np.testing.assert_array_almost_equal(zoom_cv(im, 2), stretch_cv(im, 2, 2), decimal=4) def test_dihedral(): im = np.array([ [0., 0.1, 0., ], [0.01, 0.2, 0.03,], [0., 0.3, 0., ],]) e = im a = dihedral(im, 0) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.03, 0., ], [0.1, 0.2, 0.3, ], [0., 0.01, 0., ]]) a = dihedral(im, 1) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.3, 0., ], [0.03, 0.2, 0.01,], [0., 0.1, 0., ]]) a = dihedral(im, 2) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.01, 0., ], [0.3, 0.2, 0.1, ], [0., 0.03, 0., ]]) a = dihedral(im, 3) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.1, 0., ], [0.03, 0.2, 0.01,], [0., 0.3, 0., ]]) a = dihedral(im, 4) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.03, 0., ], [0.3, 0.2, 0.1, ], [0., 0.01, 0., ]]) a = dihedral(im, 5) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.3, 0., ], [0.01, 0.2, 0.03,], [0., 0.1, 0., ]]) a = dihedral(im, 6) np.testing.assert_array_equal(a, e) e = np.array([ [0., 0.01, 0., ], [0.1, 0.2, 0.3, ], [0., 0.03, 0., ]]) a = dihedral(im, 7) np.testing.assert_array_equal(a, e) def test_lighting(): im = np.array([ [0., 0.1, 0., ], [0.01, 0.2, 0.03,], [0., 0.3, 0., ],]) e = im a = lighting(im, 0, 1) # TODO: better test taht allows for visual inspection np.testing.assert_array_equal(a, e) e =np.array([[0.5 , 0.6 , 0.5 ], [0.51, 0.7 , 0.53], [0.5 , 0.8 , 0.5 ]], dtype=np.float32) a = lighting(im, 0.5, 1) np.testing.assert_array_equal(a, e) @pytest.mark.skip(reason="It does not work for some reason see #431") def test_rotate_cv(): im = np.array([ [0., 0.1, 0., ], [0., 0.2, 0., ], [0., 0.3, 0., ],]) a = rotate_cv(im, 90) # TODO: find out why this test breaks e = np.array([[0. , 0. , 0. ], [0.1, 0.2, 0.3], [0. , 0. , 0. ],]) np.testing.assert_array_equal(a, e) @pytest.mark.skip(reason="It does not work for some reason see #431") def test_rotate_cv_vs_dihedral(): im = np.array([ [0., 0.1, 0., ], [0., 0.2, 0., ], [0., 0.3, 0., ],]) a = rotate_cv(im, 180) e = dihedral(im, 6) np.testing.assert_array_equal(a, e) def test_no_crop(): im = np.array([ [0., 0.1, 0., ], [0., 0.2, 0., ],]) a = no_crop(im, 4) e = np.array([[0. , 0.066 , 0.066, 0 ], [0, 0.066, 0.066, 0 ], [0. , 0.133 , 0.133, 0 ], [0. , 0.133 , 0.133, 0 ]]) np.testing.assert_array_almost_equal(a, e, decimal=3) def test_center_crop(): im = np.array([ [0., 0.1, 0., ], [0.01, 0.2, 0.03,], [0., 0.3, 0., ],]) a = center_crop(im, 1) e = np.array([[0.2]]) np.testing.assert_array_equal(a, e) im = np.array([ [0., 0.1, 0., 0], [0.01, 0.2, 0.9, 0.04], [0., 0.3, 0., 0],]) a = center_crop(im, 1) e = np.array([[0.9]]) np.testing.assert_array_equal(a, e) def test_googlenet_resize(): # TODO: figure out how to test this in a way it make sense pass def test_cutout(): im = np.ones([128,128,3], np.float32) with_holes = cutout(im, 1, 10) assert (with_holes == 0).sum() == 300, "There is one cut out hole 10px x 10px in size (over 3 channels)" def test_scale_to(): h=10 w=20 ratio = 127./h assert scale_to(h, ratio, 127) == 127 assert scale_to(w, ratio, 127) == 254 def test_crop(): im = np.ones([128,128,3], np.float32) assert crop(im, 1, 1, 10).shape == (10,10,3) def test_to_bb(): im = np.array([[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0], ], dtype=np.float32) expect = [1,1,3,3] np.testing.assert_array_equal(to_bb(im, "not used"), expect) ### tests for transformation objects def test_RandomCrop(): tfm = RandomCrop(23) x = t_rand_img128x128x1 x2, cls = tfm(x, None) assert x2.shape == (23,23,1) def test_AddPadding(): tfm = AddPadding(1) x = t_rand_img128x128x3 x2, cls = tfm(x, None) assert x2.shape == (130,130,3) def test_CenterCrop(): tfm = CenterCrop(10) x = t_rand_img128x128x3 x2, cls = tfm(x, None) assert x2.shape == (10,10,3) def test_NoCrop(): tfm = NoCrop(10) x = t_rand_img128x128x3 x2, cls = tfm(x, None) assert x2.shape == (10,10,3) def test_applying_tranfrom_multiple_times_reset_the_state(): tfm = RandomScale(10, 1000, p=1) x1,_ = tfm(t_rand_img128x128x3, None) x2,_ = tfm(t_rand_img128x128x3, None) x3,_ = tfm(t_rand_img128x128x3, None) assert x1.shape[0] != x2.shape[0] or x1.shape[0] != x3.shape[0], "Each transfromation should give a bit different shape" assert x1.shape[0] < 10000 assert x2.shape[0] < 10000 assert x3.shape[0] < 10000 stats = inception_stats tfm_norm = Normalize(*stats, tfm_y=TfmType.COORD) tfm_denorm = Denormalize(*stats) buggy_offset = 2 # This is a bug in the current transform_coord, I will fix it in the next commit def test_transforms_works_with_coords(): # test of backward compatible behavior sz = 16 transforms = image_gen(tfm_norm, tfm_denorm, sz, tfms=None, max_zoom=None, pad=0, crop_type=CropType.NO, tfm_y=TfmType.COORD, sz_y=sz, pad_mode=cv2.BORDER_REFLECT) x, y = transforms(t_rand_img128x128x3, np.array([0,0,128,128, 0,0,64,64])) bbs = partition(y, 4) assert x.shape[0] == 3, "The image was converted from NHWC to NCHW (channle first pytorch format)" h,w = x.shape[1:] np.testing.assert_equal(bbs[0], [0, 0, h-buggy_offset, w-buggy_offset], "The outer bounding box was converted correctly") np.testing.assert_equal(bbs[1], [0, 0, h/2-buggy_offset, w/2-buggy_offset], "The inner bounding box was converted correctly")