diff options
author | Alban Desmaison <alban@moodstocks.com> | 2015-11-04 21:52:56 +0300 |
---|---|---|
committer | Alban Desmaison <alban@moodstocks.com> | 2015-11-04 21:52:56 +0300 |
commit | 4beeb6023ee7ec7a17f482dc1baaa4e2c574892e (patch) | |
tree | feaecadd041746db95481cb6ac2bdcb8ae1fd2ff | |
parent | 5c94858530b6c15a2d2d5ec273fe338f1288bb62 (diff) |
merge all unit tests
make them available at image.test()
-rw-r--r-- | .travis.yml | 12 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | assets/ascii.pgm (renamed from test/ascii.pgm) | 0 | ||||
-rw-r--r-- | assets/corrupt-ihdr.png (renamed from test/corrupt-ihdr.png) | bin | 275 -> 275 bytes | |||
-rw-r--r-- | assets/fabio.jpg (renamed from fabio.jpg) | bin | 17958 -> 17958 bytes | |||
-rw-r--r-- | assets/fabio.png (renamed from fabio.png) | bin | 65067 -> 65067 bytes | |||
-rw-r--r-- | assets/gray16-1x2.png (renamed from test/gray16-1x2.png) | bin | 75 -> 75 bytes | |||
-rw-r--r-- | assets/gray3x1.png (renamed from test/gray3x1.png) | bin | 73 -> 73 bytes | |||
-rw-r--r-- | assets/lena.jpg (renamed from lena.jpg) | bin | 303179 -> 303179 bytes | |||
-rw-r--r-- | assets/lena.png (renamed from lena.png) | bin | 453965 -> 453965 bytes | |||
-rw-r--r-- | assets/rgb16-2x1.png (renamed from test/rgb16-2x1.png) | bin | 79 -> 79 bytes | |||
-rw-r--r-- | assets/rgb2x1.png (renamed from test/rgb2x1.png) | bin | 76 -> 76 bytes | |||
-rw-r--r-- | assets/test.pgm (renamed from test/test.pgm) | 0 | ||||
-rw-r--r-- | assets/test.ppm (renamed from test/test.ppm) | bin | 313 -> 313 bytes | |||
-rw-r--r-- | init.lua | 13 | ||||
-rw-r--r-- | test/test.lua | 495 | ||||
-rwxr-xr-x | test/test_compress_jpg.lua | 43 | ||||
-rw-r--r-- | test/test_conversion.lua | 29 | ||||
-rwxr-xr-x | test/test_decompress_jpg.lua | 64 | ||||
-rwxr-xr-x | test/test_flip.lua | 63 | ||||
-rw-r--r-- | test/test_gaussian.lua | 133 | ||||
-rw-r--r-- | test/test_gaussianpyramid.lua | 25 | ||||
-rw-r--r-- | test/test_png.lua | 75 | ||||
-rw-r--r-- | test/test_ppm.lua | 53 | ||||
-rw-r--r-- | test/test_scale.lua | 80 | ||||
-rw-r--r-- | test/test_vflip.lua | 77 |
27 files changed, 513 insertions, 658 deletions
diff --git a/.travis.yml b/.travis.yml index d839fc8..debe30a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,16 +51,6 @@ script: - ${INSTALL_PREFIX}/bin/luarocks make - ${INSTALL_PREFIX}/bin/luajit -limage -e "print('image loaded succesfully')" - cd test -- ${INSTALL_PREFIX}/bin/luarocks install totem - ${INSTALL_PREFIX}/bin/luarocks install graphicsmagick -- ${INSTALL_PREFIX}/bin/luajit ./test_compress_jpg.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_conversion.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_decompress_jpg.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_flip.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_gaussian.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_gaussianpyramid.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_png.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_ppm.lua - ${INSTALL_PREFIX}/bin/luajit ./test_rotate.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_scale.lua -- ${INSTALL_PREFIX}/bin/luajit ./test_vflip.lua +- ${INSTALL_PREFIX}/bin/luajit -limage -e "t=image.test(); if t.errors[1] then os.exit(1) end" diff --git a/CMakeLists.txt b/CMakeLists.txt index 0086cb1..cd86226 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,11 +66,12 @@ else (PNG_FOUND) endif (PNG_FOUND) SET(src image.c) -SET(luasrc init.lua fabio.jpg fabio.png lena.jpg lena.png win.ui) +SET(luasrc init.lua win.ui test/test.lua) ADD_TORCH_PACKAGE(image "${src}" "${luasrc}" "Image Processing") TARGET_LINK_LIBRARIES(image luaT TH) IF(LUALIB) TARGET_LINK_LIBRARIES(image ${LUALIB}) ENDIF() +INSTALL(DIRECTORY "assets" DESTINATION "${Torch_INSTALL_LUA_PATH_SUBDIR}/image") INSTALL(FILES "README.md" DESTINATION "${Torch_INSTALL_LUA_PATH_SUBDIR}/image") @@ -25,6 +25,12 @@ Otherwise, to update or manually re-install it: $ luarocks install image ``` +You can test your install with: + +```bash +$ luajit -limage -e "image.test()" +``` + ## Usage ```lua diff --git a/test/ascii.pgm b/assets/ascii.pgm index 0e76d7d..0e76d7d 100644 --- a/test/ascii.pgm +++ b/assets/ascii.pgm diff --git a/test/corrupt-ihdr.png b/assets/corrupt-ihdr.png Binary files differindex ca53ac9..ca53ac9 100644 --- a/test/corrupt-ihdr.png +++ b/assets/corrupt-ihdr.png diff --git a/fabio.jpg b/assets/fabio.jpg Binary files differindex 895b2bc..895b2bc 100644 --- a/fabio.jpg +++ b/assets/fabio.jpg diff --git a/fabio.png b/assets/fabio.png Binary files differindex 0a7b14c..0a7b14c 100644 --- a/fabio.png +++ b/assets/fabio.png diff --git a/test/gray16-1x2.png b/assets/gray16-1x2.png Binary files differindex 9b3cb5e..9b3cb5e 100644 --- a/test/gray16-1x2.png +++ b/assets/gray16-1x2.png diff --git a/test/gray3x1.png b/assets/gray3x1.png Binary files differindex ce89719..ce89719 100644 --- a/test/gray3x1.png +++ b/assets/gray3x1.png diff --git a/lena.jpg b/assets/lena.jpg Binary files differindex 2fd59ba..2fd59ba 100644 --- a/lena.jpg +++ b/assets/lena.jpg diff --git a/lena.png b/assets/lena.png Binary files differindex c808105..c808105 100644 --- a/lena.png +++ b/assets/lena.png diff --git a/test/rgb16-2x1.png b/assets/rgb16-2x1.png Binary files differindex 3aab682..3aab682 100644 --- a/test/rgb16-2x1.png +++ b/assets/rgb16-2x1.png diff --git a/test/rgb2x1.png b/assets/rgb2x1.png Binary files differindex 60a0e9f..60a0e9f 100644 --- a/test/rgb2x1.png +++ b/assets/rgb2x1.png diff --git a/test/test.pgm b/assets/test.pgm index b4ea2fb..b4ea2fb 100644 --- a/test/test.pgm +++ b/assets/test.pgm diff --git a/test/test.ppm b/assets/test.ppm Binary files differindex 68b997c..68b997c 100644 --- a/test/test.ppm +++ b/assets/test.ppm @@ -36,6 +36,11 @@ require 'dok' require 'libimage' ---------------------------------------------------------------------- +-- include unit test function +-- +include('test.lua') + +---------------------------------------------------------------------- -- types lookups -- local type2tensor = { @@ -1449,9 +1454,9 @@ rawset(image, 'window', window) local function lena() local fname = 'lena' if xlua.require 'libjpeg' then - lena = image.load(paths.concat(sys.fpath(), fname .. '.jpg'), 3) + lena = image.load(paths.concat(sys.fpath(), 'assets', fname .. '.jpg'), 3) elseif xlua.require 'libpng' then - lena = image.load(paths.concat(sys.fpath(), fname .. '.png'), 3) + lena = image.load(paths.concat(sys.fpath(), 'assets', fname .. '.png'), 3) else dok.error('no bindings available to load images (libjpeg AND libpng missing)', 'image.lena') end @@ -1468,9 +1473,9 @@ rawset(image, 'lena', lena) local function fabio() local fname = 'fabio' if xlua.require 'libjpeg' then - lena = image.load(paths.concat(sys.fpath(), fname .. '.jpg'), 1) + lena = image.load(paths.concat(sys.fpath(), 'assets', fname .. '.jpg'), 1) elseif xlua.require 'libpng' then - lena = image.load(paths.concat(sys.fpath(), fname .. '.png'), 1) + lena = image.load(paths.concat(sys.fpath(), 'assets', fname .. '.png'), 1) else dok.error('no bindings available to load images (libjpeg AND libpng missing)', 'image.fabio') end diff --git a/test/test.lua b/test/test.lua new file mode 100644 index 0000000..0882936 --- /dev/null +++ b/test/test.lua @@ -0,0 +1,495 @@ +local test = {} +torch.setdefaulttensortype('torch.DoubleTensor') +local precision = 1e-4 +local precision_mean = 1e-3 +local precision_std = 1e-1 +-- Specific precision for Lab conversion +local Lab_precision = 1e-4 + +local function getTestImagePath(name) + return paths.concat(sys.fpath(), 'assets', name) +end + +---------------------------------------------------------------------- +-- Flip test +-- +function test.FlipAgainstHFlip() + for ndims = 1, 5 do + for flip_dim = 1, ndims do + local sz = {} + for i = 1, ndims do + sz[i] = math.random(5,10) + end + + local input = torch.rand(unpack(sz)) + local output = image.flip(input, flip_dim) + + -- Now perform the same operation using HFLIP + local input_tran = input + if (flip_dim < ndims) then + -- First permute the flip dimension to X dim + input_tran = input:transpose(flip_dim, ndims):contiguous() + end + -- Now reshape it to 3D + local original_hflip_sz = input_tran:size() + if ndims == 1 then + input_tran:resize(1, original_hflip_sz[1]) + end + if ndims > 3 then + sz1 = 1 + for i = 1, ndims - 2 do + sz1 = sz1 * original_hflip_sz[i] + end + input_tran:resize(sz1, original_hflip_sz[input_tran:dim()-1], + original_hflip_sz[input_tran:dim()]) + end + + local output_hflip = image.hflip(input_tran) + + -- Put it back to Ndim + output_hflip:resize(original_hflip_sz) + + if (flip_dim < ndims) then + -- permute bacx the flip dimension + output_hflip = output_hflip:transpose(flip_dim, ndims):contiguous() + end + + local err = output_hflip - output + tester:asserteq(err:abs():max(), 0, 'error - bad flip! (ndims='.. + ndims..',flip_dim='..flip_dim..')') + end + end +end + +---------------------------------------------------------------------- +-- Gaussian tests +-- +-- The old gaussian function, commit: 71670e1dcfcfe040aba5403c800a0d316987c2ed +local function naive_gaussian(...) + -- process args + local _, size, sigma, amplitude, normalize, + width, height, sigma_horz, sigma_vert, mean_horz, mean_vert = dok.unpack( + {...}, + 'image.gaussian', + 'returns a 2D gaussian kernel', + {arg='size', type='number', help='kernel size (size x size)', default=3}, + {arg='sigma', type='number', help='sigma (horizontal and vertical)', default=0.25}, + {arg='amplitude', type='number', help='amplitute of the gaussian (max value)', default=1}, + {arg='normalize', type='number', help='normalize kernel (exc Amplitude)', default=false}, + {arg='width', type='number', help='kernel width', defaulta='size'}, + {arg='height', type='number', help='kernel height', defaulta='size'}, + {arg='sigma_horz', type='number', help='horizontal sigma', defaulta='sigma'}, + {arg='sigma_vert', type='number', help='vertical sigma', defaulta='sigma'}, + {arg='mean_horz', type='number', help='horizontal mean', default=0.5}, + {arg='mean_vert', type='number', help='vertical mean', default=0.5} + ) + + -- local vars + local center_x = mean_horz * width + 0.5 + local center_y = mean_vert * height + 0.5 + + -- generate kernel + local gauss = torch.Tensor(height, width) + for i=1,height do + for j=1,width do + gauss[i][j] = amplitude * math.exp(-(math.pow((j-center_x) + /(sigma_horz*width),2)/2 + + math.pow((i-center_y) + /(sigma_vert*height),2)/2)) + end + end + if normalize then + gauss:div(gauss:sum()) + end + return gauss +end + +function test.gaussian() + local sigma_horz = 0.1 + math.random() * 0.3; -- [0.1, 0.4] + local sigma_vert = 0.1 + math.random() * 0.3; -- [0.1, 0.4] + local mean_horz = 0.1 + math.random() * 0.8; -- [0.1, 0.9] + local mean_vert = 0.1 + math.random() * 0.8; -- [0.1, 0.9] + local width = 640 + local height = 480 + local amplitude = 10 + + for _, normalize in pairs{true, false} do + im1 = image.gaussian{amplitude=amplitude, + normalize=normalize, + width=width, + height=height, + sigma_horz=sigma_horz, + sigma_vert=sigma_vert, + mean_horz=mean_horz, + mean_vert=mean_vert} + + im2 = naive_gaussian{amplitude=amplitude, + normalize=normalize, + width=width, + height=height, + sigma_horz=sigma_horz, + sigma_vert=sigma_vert, + mean_horz=mean_horz, + mean_vert=mean_vert} + + tester:assertlt(im1:add(-1, im2):sum(), precision, "Incorrect gaussian") + end +end + +---------------------------------------------------------------------- +-- Gaussian pyramid test +-- +function test.gaussianpyramid() + -- Char, Short and Int tensors not supported. + types = { + 'torch.ByteTensor', + 'torch.FloatTensor', + 'torch.DoubleTensor' + } + for _, type in ipairs(types) do + local output = unpack(image.gaussianpyramid(torch.rand(8, 8):type(type), {0.5})) + tester:assert(output:type() == type, 'Type ' .. type .. ' produces a different output.') + end +end + +---------------------------------------------------------------------- +-- Scale test +-- +local function outerProduct(x) + x = torch.Tensor(x) + return torch.ger(x, x) +end + + +function test.bilinearUpscale() + local im = outerProduct{1, 2, 4, 2} + local expected = outerProduct{1, 1.5, 2, 3, 4, 3, 2} + local actual = image.scale(im, expected:size(1), expected:size(2), 'bilinear') + tester:assertTensorEq(actual, expected, 1e-5) +end + + +function test.bilinearDownscale() + local im = outerProduct{1, 2, 4, 2} + local expected = outerProduct{1.25, 3, 2.5} + local actual = image.scale(im, expected:size(1), expected:size(2), 'bilinear') + tester:assertTensorEq(actual, expected, 1e-5) +end + + +function test.bicubicUpscale() + local im = outerProduct{1, 2, 4, 2} + local expected = outerProduct{1, 1.4375, 2, 3.1875, 4, 3.25, 2} + local actual = image.scale(im, expected:size(1), expected:size(2), 'bicubic') + tester:assertTensorEq(actual, expected, 1e-5) +end + + +function test.bicubicDownscale() + local im = outerProduct{1, 2, 4, 2} + local expected = outerProduct{1, 3.1875, 2} + local actual = image.scale(im, expected:size(1), expected:size(2), 'bicubic') + tester:assertTensorEq(actual, expected, 1e-5) +end + +---------------------------------------------------------------------- +-- Scale test +-- +local flip_tests = {} +function flip_tests.test_transformation_largeByteImage(flip) + local x_real = image.fabio():double():mul(255) + local x_byte = x_real:clone():byte() + + assert(x_byte:size(1) > 256 and x_byte:size(2) > 256, 'Tricky case only occurs for images larger than 256 px, pick another example') + + local f_real, f_byte + f_real = image[flip](x_real) + f_byte = image[flip](x_byte) + tester:assertTensorEq(f_real:byte():double(), f_byte:double(), 1e-16, flip .. ': result for double and byte images do not match') +end + +function flip_tests.test_inplace(flip) + local im = image.lena() + local not_inplace = image[flip](im) + local in_place = im:clone() + image[flip](in_place, in_place) + tester:assertTensorEq(in_place, not_inplace, 1e-16, flip .. ': result in-place does not match result not in-place') +end + +for _, flip in pairs{'vflip', 'hflip'} do + for name, flip_test in pairs(flip_tests) do + test[name .. '_' .. flip] = function() return flip_test(flip) end + end +end + +function test.test_vflip_simple() + local im_even = torch.Tensor{{1,2}, {3, 4}} + local expected_even = torch.Tensor{{3, 4}, {1, 2}} + local x_even = image.vflip(im_even) + tester:assertTensorEq(expected_even, x_even, 1e-16, 'vflip: fails on even size') + -- test inplace + image.vflip(im_even, im_even) + tester:assertTensorEq(expected_even, im_even, 1e-16, 'vflip: fails on even size in place') + + local im_odd = torch.Tensor{{1,2}, {3, 4}, {5, 6}} + local expected_odd = torch.Tensor{{5,6}, {3, 4}, {1, 2}} + local x_odd = image.vflip(im_odd) + tester:assertTensorEq(expected_odd, x_odd, 1e-16, 'vflip: fails on odd size') + -- test inplace + image.vflip(im_odd, im_odd) + tester:assertTensorEq(expected_odd, im_odd, 1e-16, 'vflip: fails on odd size in place') +end + +function test.test_hflip_simple() + local im_even = torch.Tensor{{1, 2}, {3, 4}} + local expected_even = torch.Tensor{{2, 1}, {4, 3}} + local x_even = image.hflip(im_even) + tester:assertTensorEq(expected_even, x_even, 1e-16, 'hflip: fails on even size') + -- test inplace + image.hflip(im_even, im_even) + tester:assertTensorEq(expected_even, im_even, 1e-16, 'hflip: fails on even size in place') + + local im_odd = torch.Tensor{{1,2, 3}, {4, 5, 6}} + local expected_odd = torch.Tensor{{3, 2, 1}, {6, 5, 4}} + local x_odd = image.hflip(im_odd) + tester:assertTensorEq(expected_odd, x_odd, 1e-16, 'hflip: fails on odd size') + -- test inplace + image.hflip(im_odd, im_odd) + tester:assertTensorEq(expected_odd, im_odd, 1e-16, 'hflip: fails on odd size in place') +end + +---------------------------------------------------------------------- +-- decompress jpg test +-- +function test.CompareLoadAndDecompress() + -- This test breaks if someone removes lena from the repo or does not have graphics magick installed + local ok, gm = pcall(require, 'graphicsmagick') + if not ok then + error('This test require the graphicsmagick package to run. You can install it with "luarocks install graphicsmagick".') + end + local imfile = getTestImagePath('lena.jpg') + if not paths.filep(imfile) then + error(imfile .. ' is missing!') + end + + -- Load lena directly from the filename + local img = image.loadJPG(imfile) + + -- Make sure the returned image width and height match the height and width + -- reported by graphicsmagick (just a sanity check) + local info = gm.info(imfile) + local w = info.width + local h = info.height + tester:assert(w == img:size(3), 'image dimension error ') + tester:assert(h == img:size(3), 'image dimension error ') + + -- Now load the raw binary from the source file into a ByteTensor + local fin = torch.DiskFile(imfile, 'r') + fin:binary() + fin:seekEnd() + local file_size_bytes = fin:position() - 1 + fin:seek(1) + local img_binary = torch.ByteTensor(file_size_bytes) + fin:readByte(img_binary:storage()) + fin:close() + + -- Now decompress the image from the ByteTensor + local img_from_tensor = image.decompressJPG(img_binary) + + tester:assertlt((img_from_tensor - img):abs():max(), precision, + 'images from load and decompress dont match! ') +end + +function test.LoadInvalid() + -- Make sure nothing nasty happens if we try and load a "garbage" tensor + local file_size_bytes = 1000 + local img_binary = torch.rand(file_size_bytes):mul(255):byte() + + -- Now decompress the image from the ByteTensor + local ok, img_from_tensor = pcall(function() + return image.decompressJPG(img_binary) + end) + + tester:assert(not ok or img_from_tensor == nil, + 'A non-nil was returned on an invalid input! ') +end + +---------------------------------------------------------------------- +-- compress jpg test +-- + +function test.CompressAndDecompress() + -- This test is unfortunately a correlated test: it will only be valid + -- if decompressJPG is OK. However, since decompressJPG has it's own unit + -- test, this is problably fine. + + local img = image.lena() + + local quality = 100 + local img_compressed = image.compressJPG(img, quality) + local size_100 = img_compressed:size(1) + local img_decompressed = image.decompressJPG(img_compressed) + local err = img_decompressed - img + + -- Now in general we will get BIG compression artifacts (even at quality=100) + -- but they will be relatively small, so instead of a abs():max() test, we do + -- a mean and std test. + local mean_err = err:mean() + local std_err = err:std() + tester:assertlt(mean_err, precision_mean, 'compressJPG error is too high! ') + tester:assertlt(std_err, precision_std, 'compressJPG error is too high! ') + + -- Also check that the quality setting scales the size of the compressed image + quality = 25 + img_compressed = image.compressJPG(img, quality) + local size_25 = img_compressed:size(1) + tester:assertlt(size_25, size_100, 'compressJPG quality setting error! ') +end + +---------------------------------------------------------------------- +-- Lab conversion test +-- +function test.TestLabConversionBackAndForth() + -- This test breaks if someone removes lena from the repo + local imfile = getTestImagePath('lena.jpg') + if not paths.filep(imfile) then + error(imfile .. ' is missing!') + end + + -- Load lena directly from the filename + local img = image.loadJPG(imfile) + + -- Convert to LAB and back to RGB + local lab = image.rgb2lab(img) + local img2 = image.lab2rgb(lab) + -- Compare RGB images + tester:assertlt((img - img2):abs():max(), Lab_precision, + 'RGB <-> LAB conversion produces wrong results! ') +end + +---------------------------------------------------------------------- +-- PNG test +-- +local function toBlob(filename) + local f = torch.DiskFile(filename, 'r') + f:binary() + f:seekEnd() + local size = f:position() - 1 + f:seek(1) + local blob = torch.ByteTensor(size) + f:readByte(blob:storage()) + f:close() + return blob +end + +local function checkPNG(imfile, depth, tensortype, want) + local img = image.load(imfile, depth, tensortype) + -- Tensors have to be converted to double, since assertTensorEq does not support ByteTensor + --print('img: ', img) + --print('want: ', want) + tester:assertTensorEq(img:double(), want:double(), precision_mean, + string.format('%s: pixel values are unexpected', imfile)) +end + +function test.LoadPNG() + -- Gray 8-bit PNG image with width = 3, height = 1 + local gray8byte = torch.ByteTensor({{{0,127,255}}}) + checkPNG(getTestImagePath('gray3x1.png'), 1, 'byte', gray8byte) + + local gray8double = torch.DoubleTensor({{{0, 127/255, 1}}}) + checkPNG(getTestImagePath('gray3x1.png'), 1, 'double', gray8double) + + -- Gray 16-bit PNG image with width=1, height = 2 + local gray16byte = torch.ByteTensor({{{0, 255}}}) + checkPNG(getTestImagePath('gray16-1x2.png'), 1, 'byte', gray16byte) + + local gray16float = torch.FloatTensor({{{0, 65534/65535}}}) + checkPNG(getTestImagePath('gray16-1x2.png'), 1, 'float', gray16float) + + -- Color 8-bit PNG image with width = 2, height = 1 + local rgb8byte = torch.ByteTensor({{{255, 0, 0, 127, 63, 0}}}) + checkPNG(getTestImagePath('rgb2x1.png'), 3, 'byte', rgb8byte) + + local rgb8float = torch.FloatTensor({{{1, 0, 0, 127/255, 63/255, 0}}}) + checkPNG(getTestImagePath('rgb2x1.png'), 3, 'float', rgb8float) + + -- Color 16-bit PNG image with width = 2, height = 1 + local rgb16byte = torch.ByteTensor({{{255, 0, 0, 127, 63, 0}}}) + checkPNG(getTestImagePath('rgb16-2x1.png'), 3, 'byte', rgb16byte) + + local rgb16float = torch.FloatTensor({{{1, 0, 0, 32767/65535, 16383/65535, 0}}}) + checkPNG(getTestImagePath('rgb16-2x1.png'), 3, 'float', rgb16float) +end + +function test.DecompressPNG() + tester:assertTensorEq( + image.load(getTestImagePath('rgb2x1.png')), + image.decompressPNG(toBlob(getTestImagePath('rgb2x1.png'))), + precision_mean, + 'decompressed and loaded images should be equal' + ) +end + +function test.LoadCorruptedPNG() + local ok, _ = pcall(image.load, 'corrupt-ihdr.png') + tester:assert(not ok, 'corrupted image should not be loaded') +end + +---------------------------------------------------------------------- +-- PPM test +-- +function test.test_ppmload() + -- test.ppm is a 100x1 "French flag" like image, i.e the first pixel is blue + -- the 84 next pixels are white and the 15 last pixels are red. + -- This makes possible to implement a non regression test vs. the former + -- PPM loader which had for effect to skip the first 85 pixels because of + -- a header parser bug + local img = image.load(getTestImagePath("test.ppm")) + local pix = img[{ {}, {1}, {1} }] + + -- Check the first pixel is blue + local ref = torch.zeros(3, 1, 1) + ref[3][1][1] = 1 + tester:assertTensorEq(pix, ref, 0, "PPM load: first pixel check failed") +end + + +function test.test_pgmaload() + -- ascii.ppm is a PGMA file (ascii pgm) + -- example comes from ehere + -- http://people.sc.fsu.edu/~jburkardt/data/pgma/pgma.html + local img = image.load(getTestImagePath("ascii.pgm"), 1, 'byte') + local max_gray = 15 -- 4th line of ascii.pgm + local ascii_val = 3 -- pixel (2,2) in the file + local pix_val = math.floor(255 * ascii_val / max_gray) + + local pix = img[1][2][2] + + -- Check that Pixel(1, 2,2) == 3 + local ref = pix_val + tester:asserteq(pix, ref, "PGMA load: pixel check failed") +end + +function test.test_pgmload() + -- test.ppm is a 100x1 "French flag" like image, i.e the first pixel is blue + -- the 84 next pixels are white and the 15 last pixels are red. + -- This makes possible to implement a non regression test vs. the former + -- PPM loader which had for effect to skip the first 85 pixels because of + -- a header parser bug + local img = image.load(getTestImagePath("test.pgm")) + local pix = img[{ {}, {1}, {1} }] + + local ref = torch.zeros(1, 1, 1); ref[1][1][1] = 0.07 + tester:assertTensorEq(pix, ref, 0.001, "PPM load: first pixel check failed") +end + + +function image.test(tests, seed) + seed = seed or os.time() + print('seed: ', seed) + math.randomseed(seed) + tester = torch.Tester() + tester:add(test) + tester:run(tests) + return tester +end diff --git a/test/test_compress_jpg.lua b/test/test_compress_jpg.lua deleted file mode 100755 index 8a64bd8..0000000 --- a/test/test_compress_jpg.lua +++ /dev/null @@ -1,43 +0,0 @@ -require 'image' -require 'paths' - -torch.setdefaulttensortype('torch.DoubleTensor') -torch.setnumthreads(4) - --- Create an instance of the test framework -local mytester = torch.Tester() -local precision_mean = 1e-3 -local precision_std = 1e-1 -local test = {} - -function test.CompressAndDecompress() - -- This test is unfortunately a correlated test: it will only be valid - -- if decompressJPG is OK. However, since decompressJPG has it's own unit - -- test, this is problably fine. - - local img = image.lena() - - local quality = 100 - local img_compressed = image.compressJPG(img, quality) - local size_100 = img_compressed:size(1) - local img_decompressed = image.decompressJPG(img_compressed) - local err = img_decompressed - img - - -- Now in general we will get BIG compression artifacts (even at quality=100) - -- but they will be relatively small, so instead of a abs():max() test, we do - -- a mean and std test. - local mean_err = err:mean() - local std_err = err:std() - mytester:assertlt(mean_err, precision_mean, 'compressJPG error is too high! ') - mytester:assertlt(std_err, precision_std, 'compressJPG error is too high! ') - - -- Also check that the quality setting scales the size of the compressed image - quality = 25 - img_compressed = image.compressJPG(img, quality) - local size_25 = img_compressed:size(1) - mytester:assertlt(size_25, size_100, 'compressJPG quality setting error! ') -end - --- Now run the test above -mytester:add(test) -mytester:run() diff --git a/test/test_conversion.lua b/test/test_conversion.lua deleted file mode 100644 index dcc0d25..0000000 --- a/test/test_conversion.lua +++ /dev/null @@ -1,29 +0,0 @@ -require 'image' -require 'paths' - --- Create an instance of the test framework -local mytester = torch.Tester() -local precision = 1e-4 -local test = {} - -function test.TestLabConversionBackAndForth() - -- This test breaks if someone removes lena from the repo - local imfile = '../lena.jpg' - if not paths.filep(imfile) then - error(imfile .. ' is missing!') - end - - -- Load lena directly from the filename - local img = image.loadJPG(imfile) - - -- Convert to LAB and back to RGB - local lab = image.rgb2lab(img) - local img2 = image.lab2rgb(lab) - -- Compare RGB images - mytester:assertlt((img - img2):abs():max(), precision, - 'RGB <-> LAB conversion produces wrong results! ') -end - --- Now run the test above -mytester:add(test) -mytester:run() diff --git a/test/test_decompress_jpg.lua b/test/test_decompress_jpg.lua deleted file mode 100755 index 5728eaf..0000000 --- a/test/test_decompress_jpg.lua +++ /dev/null @@ -1,64 +0,0 @@ -require 'image' -require 'paths' -gm = require 'graphicsmagick' - -torch.setdefaulttensortype('torch.DoubleTensor') -torch.setnumthreads(4) - --- Create an instance of the test framework -local mytester = torch.Tester() -local precision = 1e-6 -local test = {} - -function test.CompareLoadAndDecompress() - -- This test breaks if someone removes lena from the repo - local imfile = '../lena.jpg' - if not paths.filep(imfile) then - error(imfile .. ' is missing!') - end - - -- Load lena directly from the filename - local img = image.loadJPG(imfile) - - -- Make sure the returned image width and height match the height and width - -- reported by graphicsmagick (just a sanity check) - local info = gm.info(imfile) - local w = info.width - local h = info.height - mytester:assert(w == img:size(3), 'image dimension error ') - mytester:assert(h == img:size(3), 'image dimension error ') - - -- Now load the raw binary from the source file into a ByteTensor - local fin = torch.DiskFile(imfile, 'r') - fin:binary() - fin:seekEnd() - local file_size_bytes = fin:position() - 1 - fin:seek(1) - local img_binary = torch.ByteTensor(file_size_bytes) - fin:readByte(img_binary:storage()) - fin:close() - - -- Now decompress the image from the ByteTensor - local img_from_tensor = image.decompressJPG(img_binary) - - mytester:assertlt((img_from_tensor - img):abs():max(), precision, - 'images from load and decompress dont match! ') -end - -function test.LoadInvalid() - -- Make sure nothing nasty happens if we try and load a "garbage" tensor - local file_size_bytes = 1000 - local img_binary = torch.rand(file_size_bytes):mul(255):byte() - - -- Now decompress the image from the ByteTensor - local ok, img_from_tensor = pcall(function() - return image.decompressJPG(img_binary) - end) - - mytester:assert(not ok or img_from_tensor == nil, - 'A non-nil was returned on an invalid input! ') -end - --- Now run the test above -mytester:add(test) -mytester:run() diff --git a/test/test_flip.lua b/test/test_flip.lua deleted file mode 100755 index c083c55..0000000 --- a/test/test_flip.lua +++ /dev/null @@ -1,63 +0,0 @@ -require 'image' - -torch.setdefaulttensortype('torch.DoubleTensor') -torch.setnumthreads(8) - --- Create an instance of the test framework -local precision = 1e-5 -local mytester = torch.Tester() -local test = {} -local unpack = unpack or table.unpack - --- This is a correlated test (which is kinda lazy). We're assuming HFLIP is OK. -function test.FlipAgainstHFlip() - for ndims = 1, 5 do - for flip_dim = 1, ndims do - local sz = {} - for i = 1, ndims do - sz[i] = math.random(5,10) - end - - local input = torch.rand(unpack(sz)) - local output = image.flip(input, flip_dim) - - -- Now perform the same operation using HFLIP - local input_tran = input - if (flip_dim < ndims) then - -- First permute the flip dimension to X dim - input_tran = input:transpose(flip_dim, ndims):contiguous() - end - -- Now reshape it to 3D - local original_hflip_sz = input_tran:size() - if ndims == 1 then - input_tran:resize(1, original_hflip_sz[1]) - end - if ndims > 3 then - sz1 = 1 - for i = 1, ndims - 2 do - sz1 = sz1 * original_hflip_sz[i] - end - input_tran:resize(sz1, original_hflip_sz[input_tran:dim()-1], - original_hflip_sz[input_tran:dim()]) - end - - local output_hflip = image.hflip(input_tran) - - -- Put it back to Ndim - output_hflip:resize(original_hflip_sz) - - if (flip_dim < ndims) then - -- permute bacx the flip dimension - output_hflip = output_hflip:transpose(flip_dim, ndims):contiguous() - end - - local err = output_hflip - output - mytester:asserteq(err:abs():max(), 0, 'error - bad flip! (ndims='.. - ndims..',flip_dim='..flip_dim..')') - end - end -end - --- Now run the test above -mytester:add(test) -mytester:run() diff --git a/test/test_gaussian.lua b/test/test_gaussian.lua deleted file mode 100644 index 493dc22..0000000 --- a/test/test_gaussian.lua +++ /dev/null @@ -1,133 +0,0 @@ -require 'image' - --- Just create 2 gaussians images/kernels: --- - one using code copy and pasted from the old --- - one using the c-based gaussian function --- This test is not particularly rigorous, but the function is very simple, so --- I'm not convinced it needs to be more complicated -local unpack = unpack or table.unpack - -sigma_horz = 0.1 + math.random() * 0.3; -- [0.1, 0.4] -sigma_vert = 0.1 + math.random() * 0.3; -- [0.1, 0.4] -mean_horz = 0.1 + math.random() * 0.8; -- [0.1, 0.9] -mean_vert = 0.1 + math.random() * 0.8; -- [0.1, 0.9] -width = 640 -height = 480 -normalize = false -amplitude = 10 - -im1 = image.gaussian{amplitude=amplitude, - normalize=normalize, - width=width, - height=height, - sigma_horz=sigma_horz, - sigma_vert=sigma_vert, - mean_horz=mean_horz, - mean_vert=mean_vert} - --- The old gaussian function, commit: 71670e1dcfcfe040aba5403c800a0d316987c2ed -function gaussian(...) - -- process args - local _, size, sigma, amplitude, normalize, - width, height, sigma_horz, sigma_vert, mean_horz, mean_vert = dok.unpack( - {...}, - 'image.gaussian', - 'returns a 2D gaussian kernel', - {arg='size', type='number', help='kernel size (size x size)', default=3}, - {arg='sigma', type='number', help='sigma (horizontal and vertical)', default=0.25}, - {arg='amplitude', type='number', help='amplitute of the gaussian (max value)', default=1}, - {arg='normalize', type='number', help='normalize kernel (exc Amplitude)', default=false}, - {arg='width', type='number', help='kernel width', defaulta='size'}, - {arg='height', type='number', help='kernel height', defaulta='size'}, - {arg='sigma_horz', type='number', help='horizontal sigma', defaulta='sigma'}, - {arg='sigma_vert', type='number', help='vertical sigma', defaulta='sigma'}, - {arg='mean_horz', type='number', help='horizontal mean', default=0.5}, - {arg='mean_vert', type='number', help='vertical mean', default=0.5} - ) - - -- local vars - local center_x = mean_horz * width + 0.5 - local center_y = mean_vert * height + 0.5 - - -- generate kernel - local gauss = torch.Tensor(height, width) - for i=1,height do - for j=1,width do - gauss[i][j] = amplitude * math.exp(-(math.pow((j-center_x) - /(sigma_horz*width),2)/2 - + math.pow((i-center_y) - /(sigma_vert*height),2)/2)) - end - end - if normalize then - gauss:div(gauss:sum()) - end - return gauss -end - -im2 = gaussian{amplitude=amplitude, - normalize=normalize, - width=width, - height=height, - sigma_horz=sigma_horz, - sigma_vert=sigma_vert, - mean_horz=mean_horz, - mean_vert=mean_vert} - --- make sure they're the same: -delta = im1:clone() -delta:mul(-1) -delta:add(im2) - -print("norm(im1 - im2) = " .. delta:norm(2)) - --- try one with normalization to make sure that works as well: -normalize = true -im1 = image.gaussian{amplitude=amplitude, - normalize=normalize, - width=width, - height=height, - sigma_horz=sigma_horz, - sigma_vert=sigma_vert, - mean_horz=mean_horz, - mean_vert=mean_vert} -im2 = gaussian{amplitude=amplitude, - normalize=normalize, - width=width, - height=height, - sigma_horz=sigma_horz, - sigma_vert=sigma_vert, - mean_horz=mean_horz, - mean_vert=mean_vert} - --- make sure they're the same: -delta = im1:clone() -delta:mul(-1) -delta:add(im2) - -print("norm(im1 - im2) = " .. delta:norm(2) .. " (with normalization)") - --- Now try profiling: -num_repeats = 10 -time = sys.clock() -for i=1,num_repeats do - im1 = image.gaussian{width=width, height=height} -end -time = sys.clock() - time -print("c-based gaussian with omp time: " .. time) - -time = sys.clock() -for i=1,num_repeats do - im1 = gaussian{width=width, height=height} -end -time = sys.clock() - time -print("lua-based gaussian time: " .. time) - - - - - - - - - diff --git a/test/test_gaussianpyramid.lua b/test/test_gaussianpyramid.lua deleted file mode 100644 index f0fc603..0000000 --- a/test/test_gaussianpyramid.lua +++ /dev/null @@ -1,25 +0,0 @@ -require 'totem' -require 'image' - - -local tester = totem.Tester() - - -local tests = {} - -function tests.doesNotCrash() - -- Char, Short and Int tensors not supported. - types = { - 'torch.ByteTensor', - 'torch.FloatTensor', - 'torch.DoubleTensor' - } - for _, type in ipairs(types) do - local output = unpack(image.gaussianpyramid(torch.rand(8, 8):type(type), {0.5})) - tester:assert(output:type() == type, 'Type ' .. type .. ' produces a different output.') - end -end - - -return tester:add(tests):run() - diff --git a/test/test_png.lua b/test/test_png.lua deleted file mode 100644 index 376ef6f..0000000 --- a/test/test_png.lua +++ /dev/null @@ -1,75 +0,0 @@ -require 'image' - --- Create an instance of the test framework -local mytester = torch.Tester() -local precision_mean = 1e-3 -local test = {} - -local function toBlob(filename) - local f = torch.DiskFile(filename, 'r') - f:binary() - f:seekEnd() - local size = f:position() - 1 - f:seek(1) - local blob = torch.ByteTensor(size) - f:readByte(blob:storage()) - f:close() - return blob -end - -local function checkPNG(imfile, depth, tensortype, want) - local img = image.load(imfile, depth, tensortype) - -- Tensors have to be converted to double, since assertTensorEq does not support ByteTensor - print('img: ', img) - print('want: ', want) - mytester:assertTensorEq(img:double(), want:double(), precision_mean, - string.format('%s: pixel values are unexpected', imfile)) -end - -function test.LoadPNG() - -- Gray 8-bit PNG image with width = 3, height = 1 - local gray8byte = torch.ByteTensor({{{0,127,255}}}) - checkPNG('gray3x1.png', 1, 'byte', gray8byte) - - local gray8double = torch.DoubleTensor({{{0, 127/255, 1}}}) - checkPNG('gray3x1.png', 1, 'double', gray8double) - - -- Gray 16-bit PNG image with width=1, height = 2 - local gray16byte = torch.ByteTensor({{{0, 255}}}) - checkPNG('gray16-1x2.png', 1, 'byte', gray16byte) - - local gray16float = torch.FloatTensor({{{0, 65534/65535}}}) - checkPNG('gray16-1x2.png', 1, 'float', gray16float) - - -- Color 8-bit PNG image with width = 2, height = 1 - local rgb8byte = torch.ByteTensor({{{255, 0, 0, 127, 63, 0}}}) - checkPNG('rgb2x1.png', 3, 'byte', rgb8byte) - - local rgb8float = torch.FloatTensor({{{1, 0, 0, 127/255, 63/255, 0}}}) - checkPNG('rgb2x1.png', 3, 'float', rgb8float) - - -- Color 16-bit PNG image with width = 2, height = 1 - local rgb16byte = torch.ByteTensor({{{255, 0, 0, 127, 63, 0}}}) - checkPNG('rgb16-2x1.png', 3, 'byte', rgb16byte) - - local rgb16float = torch.FloatTensor({{{1, 0, 0, 32767/65535, 16383/65535, 0}}}) - checkPNG('rgb16-2x1.png', 3, 'float', rgb16float) -end - -function test.DecompressPNG() - mytester:assertTensorEq( - image.load('rgb2x1.png'), - image.decompressPNG(toBlob('rgb2x1.png')), - precision_mean, - 'decompressed and loaded images should be equal' - ) -end - -function test.LoadCorruptedPNG() - local ok, _ = pcall(image.load, 'corrupt-ihdr.png') - mytester:assert(not ok, 'corrupted image should not be loaded') -end - --- Now run the test above -mytester:add(test) -mytester:run() diff --git a/test/test_ppm.lua b/test/test_ppm.lua deleted file mode 100644 index e955eed..0000000 --- a/test/test_ppm.lua +++ /dev/null @@ -1,53 +0,0 @@ -require 'totem' -require 'image' - -myTests = {} -local tester = totem.Tester() - -function myTests.test_ppmload() - -- test.ppm is a 100x1 "French flag" like image, i.e the first pixel is blue - -- the 84 next pixels are white and the 15 last pixels are red. - -- This makes possible to implement a non regression test vs. the former - -- PPM loader which had for effect to skip the first 85 pixels because of - -- a header parser bug - local img = image.load(paths.concat(sys.fpath(), "test.ppm")) - local pix = img[{ {}, {1}, {1} }] - - -- Check the first pixel is blue - local ref = torch.zeros(3, 1, 1); ref[3][1][1] = 1 - tester:assertTensorEq(pix, ref, 0, "PPM load: first pixel check failed") -end - - -function myTests.test_pgmaload() - -- ascii.ppm is a PGMA file (ascii pgm) - -- example comes from ehere - -- http://people.sc.fsu.edu/~jburkardt/data/pgma/pgma.html - local img = image.load(paths.concat(sys.fpath(), "ascii.pgm"), 1, 'byte') - local max_gray = 15 -- 4th line of ascii.pgm - local ascii_val = 3 -- pixel (2,2) in the file - local pix_val = math.floor(255 * ascii_val / max_gray) - - local pix = img[{ {}, {2}, {2} }] - - -- Check that Pixel(1, 2,2) == 3 - local ref = torch.zeros(1, 1, 1) - ref[1][1][1] = pix_val - tester:assertTensorEq(pix, ref, 0, "PGMA load: pixel check failed") -end - -function myTests.test_pgmload() - -- test.ppm is a 100x1 "French flag" like image, i.e the first pixel is blue - -- the 84 next pixels are white and the 15 last pixels are red. - -- This makes possible to implement a non regression test vs. the former - -- PPM loader which had for effect to skip the first 85 pixels because of - -- a header parser bug - local img = image.load(paths.concat(sys.fpath(), "test.pgm")) - local pix = img[{ {}, {1}, {1} }] - - local ref = torch.zeros(1, 1, 1); ref[1][1][1] = 0.07 - tester:assertTensorEq(pix, ref, 0.001, "PPM load: first pixel check failed") -end - -tester:add(myTests) -return tester:run(myTests) diff --git a/test/test_scale.lua b/test/test_scale.lua deleted file mode 100644 index 02f3410..0000000 --- a/test/test_scale.lua +++ /dev/null @@ -1,80 +0,0 @@ -require 'image' -require 'torch' - - -torch.setdefaulttensortype('torch.FloatTensor') - -local tester = torch.Tester() -local tests = {} - - -local function outerProduct(x) - x = torch.Tensor(x) - return torch.ger(x, x) -end - - -local function assertTensorEq(actual, expected) - if torch.type(expected) == 'torch.ByteTensor' then - local areEqual = torch.eq(actual, expected):all() - tester:assert(areEqual) - else - tester:assertTensorEq(actual, expected, 1e-5) - end -end - - -function tests.bilinearUpscale() - local im = outerProduct{1, 2, 4, 2} - local expected = outerProduct{1, 1.5, 2, 3, 4, 3, 2} - local actual = image.scale(im, expected:size(2), expected:size(1), 'bilinear') - assertTensorEq(actual, expected) -end - - -function tests.bilinearDownscale() - local im = outerProduct{1, 2, 4, 2} - local expected = outerProduct{1.25, 3, 2.5} - local actual = image.scale(im, expected:size(2), expected:size(1), 'bilinear') - assertTensorEq(actual, expected) -end - - -function tests.bicubicUpscale() - local im = outerProduct{1, 2, 4, 2} - local expected = outerProduct{1, 1.4375, 2, 3.1875, 4, 3.25, 2} - local actual = image.scale(im, expected:size(2), expected:size(1), 'bicubic') - assertTensorEq(actual, expected) -end - - -function tests.bicubicDownscale() - local im = outerProduct{1, 2, 4, 2} - local expected = outerProduct{1, 3.1875, 2} - local actual = image.scale(im, expected:size(2), expected:size(1), 'bicubic') - assertTensorEq(actual, expected) -end - - -function tests.bicubicUpscale_ByteTensor() - local im = torch.ByteTensor{{0, 1, 32}} - local expected = torch.ByteTensor{{0, 0, 9, 32}} - local actual = image.scale(im, expected:size(2), expected:size(1), 'bicubic') - assertTensorEq(actual, expected) -end - - -function tests.bilinearUpscale_ByteTensor() - local im = torch.ByteTensor{{1, 2}, - {2, 3}} - local expected = torch.ByteTensor{{1, 1, 2}, - {1, 1, 2}, - {2, 2, 3}} - local actual = image.scale(im, expected:size(2), expected:size(1)) - assertTensorEq(actual, expected) -end - - -tester:add(tests) -tester:run() - diff --git a/test/test_vflip.lua b/test/test_vflip.lua deleted file mode 100644 index 3bd56dd..0000000 --- a/test/test_vflip.lua +++ /dev/null @@ -1,77 +0,0 @@ -require 'totem' -require 'image' - -myTests = {} -local tester = totem.Tester() - - --- List of all possible tests -local all_tests = {} - -function all_tests.test_transformation_largeByteImage(flip) - local x_real = image.fabio():double():mul(255) - local x_byte = x_real:clone():byte() - - assert(x_byte:size(1) > 256 and x_byte:size(2) > 256, 'Tricky case only occurs for images larger than 256 px, pick another example') - - local f_real, f_byte - f_real = image[flip](x_real) - f_byte = image[flip](x_byte) - tester:assertTensorEq(f_real:byte():double(), f_byte:double(), 1e-16, flip .. ': result for double and byte images do not match') -end - -function all_tests.test_inplace(flip) - local im = image.lena() - local not_inplace = image[flip](im) - local in_place = im:clone() - image[flip](in_place, in_place) - tester:assertTensorEq(in_place, not_inplace, 1e-16, flip .. ': result in-place does not match result not in-place') -end - - --- Apply all tests to both vflip and hflip -for _, flip in pairs{'vflip', 'hflip'} do - for name, test in pairs(all_tests) do - myTests[name .. '_' .. flip] = function() return test(flip) end - end -end - -function myTests.test_vflip_simple() - local im_even = torch.Tensor{{1,2}, {3, 4}} - local expected_even = torch.Tensor{{3, 4}, {1, 2}} - local x_even = image.vflip(im_even) - tester:assertTensorEq(expected_even, x_even, 1e-16, 'vflip: fails on even size') - -- test inplace - image.vflip(im_even, im_even) - tester:assertTensorEq(expected_even, im_even, 1e-16, 'vflip: fails on even size in place') - - local im_odd = torch.Tensor{{1,2}, {3, 4}, {5, 6}} - local expected_odd = torch.Tensor{{5,6}, {3, 4}, {1, 2}} - local x_odd = image.vflip(im_odd) - tester:assertTensorEq(expected_odd, x_odd, 1e-16, 'vflip: fails on odd size') - -- test inplace - image.vflip(im_odd, im_odd) - tester:assertTensorEq(expected_odd, im_odd, 1e-16, 'vflip: fails on odd size in place') -end - -function myTests.test_hflip_simple() - local im_even = torch.Tensor{{1, 2}, {3, 4}} - local expected_even = torch.Tensor{{2, 1}, {4, 3}} - local x_even = image.hflip(im_even) - tester:assertTensorEq(expected_even, x_even, 1e-16, 'hflip: fails on even size') - -- test inplace - image.hflip(im_even, im_even) - tester:assertTensorEq(expected_even, im_even, 1e-16, 'hflip: fails on even size in place') - - local im_odd = torch.Tensor{{1,2, 3}, {4, 5, 6}} - local expected_odd = torch.Tensor{{3, 2, 1}, {6, 5, 4}} - local x_odd = image.hflip(im_odd) - tester:assertTensorEq(expected_odd, x_odd, 1e-16, 'hflip: fails on odd size') - -- test inplace - image.hflip(im_odd, im_odd) - tester:assertTensorEq(expected_odd, im_odd, 1e-16, 'hflip: fails on odd size in place') -end - - -tester:add(myTests) -return tester:run(myTests) |