[lua-torch-image] 01/05: New upstream version 0~20161010-g674c8d1

Zhou Mo cdluminate-guest at moszumanska.debian.org
Thu Nov 17 09:40:10 UTC 2016


This is an automated email from the git hooks/post-receive script.

cdluminate-guest pushed a commit to branch master
in repository lua-torch-image.

commit 27f06f7cea6eb870ce6fbab26ccc55429998e75e
Author: Zhou Mo <cdluminate at gmail.com>
Date:   Thu Nov 17 09:25:12 2016 +0000

    New upstream version 0~20161010-g674c8d1
---
 .travis.yml            |   1 +
 assets/bmp-without-ext | Bin 0 -> 142 bytes
 doc/paramtransform.md  |  16 +++++
 doc/saveload.md        |  32 ++++++---
 generic/image.c        |   6 +-
 generic/ppm.c          |  45 +++++++++++++
 init.lua               | 177 +++++++++++++++++++++++++++++++++++++++++++++++++
 test/test.lua          |  11 +++
 test/test_warp.lua     |   7 ++
 9 files changed, 282 insertions(+), 13 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 060ae0a..c807010 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -55,6 +55,7 @@ script:
 - ${INSTALL_PREFIX}/bin/luarocks make 
 - export PATH=${INSTALL_PREFIX}/bin:$PATH
 - export TESTLUA=$(which luajit lua | head -n 1)
+- ${INSTALL_PREFIX}/bin/luarocks install luaffi
 - ${TESTLUA} -limage -e "print('image loaded succesfully')"
 - cd test
 - ${INSTALL_PREFIX}/bin/luarocks install graphicsmagick
diff --git a/assets/bmp-without-ext b/assets/bmp-without-ext
new file mode 100644
index 0000000..0d7f4eb
Binary files /dev/null and b/assets/bmp-without-ext differ
diff --git a/doc/paramtransform.md b/doc/paramtransform.md
index 839c754..a160a34 100644
--- a/doc/paramtransform.md
+++ b/doc/paramtransform.md
@@ -19,6 +19,22 @@ When `clamp_mode` equals `pad`, the user can specify the padding value with `pad
 If `dst` is specified, it is used to store the result of the warp.
 Otherwise, returns a new `res` Tensor.
 
+<a name="image.affinetransform"></a>
+### [res] image.affinetransform([dst,]src,matrix,[mode,translation,clamp_mode,pad_val]) ###
+Warps image `src` (of size`KxHxW`) 
+according to `(y,x)` affine transformation defined by `matrix`. 
+The latter has size `2x2`. String `mode` can 
+take on values [lanczos](https://en.wikipedia.org/wiki/Lanczos_resampling), 
+[bicubic](https://en.wikipedia.org/wiki/Bicubic_interpolation),
+[bilinear](https://en.wikipedia.org/wiki/Bilinear_interpolation) (the default), 
+or *simple*. 
+Additional translation can be added to the image before affine transformation with `translation`.( Default is `torch.Tensor{0, 0}`.)
+The `clamp_mode` variable specifies how to handle the interpolation of samples off the input image.
+Permitted values are strings *clamp* (the default) or *pad*.
+When `clamp_mode` equals `pad`, the user can specify the padding value with `pad_val` (default = 0). Note: setting this value when `clamp_mode` equals `clamp` will result in an error.
+If `dst` is specified, it is used to store the result of the warp.
+Otherwise, returns a new `res` Tensor.
+
 <a name="image.convolve"></a>
 ### [res] image.convolve([dst,] src, kernel, [mode]) ###
 Convolves Tensor `kernel` over image `src`. Valid string values for argument 
diff --git a/doc/saveload.md b/doc/saveload.md
index d90fc20..b9fa1fd 100644
--- a/doc/saveload.md
+++ b/doc/saveload.md
@@ -1,23 +1,23 @@
 <a name="image.saveload"></a>
 ## Saving and Loading ##
-This sections includes functions for saving and loading different types 
+This sections includes functions for saving and loading different types
 of images to and from disk.
 
 <a name="image.load"></a>
 ### [res] image.load(filename, [depth, tensortype]) ###
 Loads an image located at path `filename` having `depth` channels (1 or 3)
 into a [Tensor](https://github.com/torch/torch7/blob/master/doc/tensor.md#tensor)
-of type `tensortype` (*float*, *double* or *byte*). The last two arguments 
+of type `tensortype` (*float*, *double* or *byte*). The last two arguments
 are optional.
 
-The image format is determined from the `filename`'s 
-extension suffix. Supported formats are 
-[JPEG](https://en.wikipedia.org/wiki/JPEG), 
-[PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics), 
+The image format is determined from the `filename`'s
+extension suffix. Supported formats are
+[JPEG](https://en.wikipedia.org/wiki/JPEG),
+[PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics),
 [PPM and PGM](https://en.wikipedia.org/wiki/Netpbm_format).
- 
-The returned `res` Tensor has size `nChannel x height x width` where `nChannel` is 
-1 (greyscale) or 3 (usually [RGB](https://en.wikipedia.org/wiki/RGB_color_model) 
+
+The returned `res` Tensor has size `nChannel x height x width` where `nChannel` is
+1 (greyscale) or 3 (usually [RGB](https://en.wikipedia.org/wiki/RGB_color_model)
 or [YUV](https://en.wikipedia.org/wiki/YUV).
 
 Usage:
@@ -30,9 +30,21 @@ local img = image.load(imagefile,1,'byte')
 
 ```
 
+<a name="image.getSize"></a>
+### [res] image.getSize(filename) ###
+Return the size of an image located at path `filename` into a LongTensor.
+
+The image format is determined from the `filename`'s
+extension suffix. Supported formats are
+[JPEG](https://en.wikipedia.org/wiki/JPEG),
+[PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics),
+[PPM and PGM](https://en.wikipedia.org/wiki/Netpbm_format).
+
+The returned `res` Tensor has size `3` (nChannel, height, width).
+
 <a name="image.save"></a>
 ### image.save(filename, tensor) ###
-Saves Tensor `tensor` to disk at path `filename`. The format to which 
+Saves Tensor `tensor` to disk at path `filename`. The format to which
 the image is saved is extrapolated from the `filename`'s extension suffix.
 The `tensor` should be of size `nChannel x height x width`.
 To save with a minimal loss, the tensor values should lie in the range [0, 1] since the tensor is clamped between 0 and 1 before being saved to the disk.
diff --git a/generic/image.c b/generic/image.c
index f30fcad..1f5163b 100755
--- a/generic/image.c
+++ b/generic/image.c
@@ -2116,9 +2116,9 @@ static inline void image_(drawPixel)(THTensor *output, int y, int x,
   THTensor_(set3d)(output, 1, y, x, cg);
   THTensor_(set3d)(output, 2, y, x, cb);
 #else
-  THTensor_(set3d)(output, 0, y, x, cr / 255);
-  THTensor_(set3d)(output, 1, y, x, cg / 255);
-  THTensor_(set3d)(output, 2, y, x, cb / 255);
+  THTensor_(set3d)(output, 0, y, x, cr / 255.0f);
+  THTensor_(set3d)(output, 1, y, x, cg / 255.0f);
+  THTensor_(set3d)(output, 2, y, x, cb / 255.0f);
 #endif
 }
 static inline void image_(drawChar)(THTensor *output, int x, int y, unsigned char c, int size,
diff --git a/generic/ppm.c b/generic/ppm.c
index 6d324e9..7cd36e6 100644
--- a/generic/ppm.c
+++ b/generic/ppm.c
@@ -2,6 +2,50 @@
 #define TH_GENERIC_FILE "generic/ppm.c"
 #else
 
+static int libppm_(Main_size)(lua_State *L)
+{
+  const char *filename = luaL_checkstring(L, 1);
+  FILE* fp = fopen ( filename, "r" );
+  if ( !fp ) {
+    luaL_error(L, "cannot open file <%s> for reading", filename);
+  }
+
+  long W,H,C;
+  char p,n;
+
+  // magic number
+  p = (char)getc(fp);
+  if ( p != 'P' ) {
+    W = H = 0;
+    fclose(fp);
+    luaL_error(L, "corrupted file");
+  }
+
+  n = (char)getc(fp);
+
+  // Dimensions
+  W = ppm_get_long(fp);
+  H = ppm_get_long(fp);
+
+  if ( n=='3' || n == '6') {
+    C = 3;
+  } else if ( n=='2' || n=='5' ) {
+    C = 1;
+  } else {
+    W=H=C=0;
+    fclose ( fp );
+    luaL_error(L, "unsupported magic number: P%c", n);
+  }
+
+  fclose(fp);
+
+  lua_pushnumber(L, C);
+  lua_pushnumber(L, H);
+  lua_pushnumber(L, W);
+
+  return 3;
+}
+
 static int libppm_(Main_load)(lua_State *L)
 {
   const char *filename = luaL_checkstring(L, 1);
@@ -170,6 +214,7 @@ static const luaL_Reg libppm_(Main__)[] =
 {
   {"load", libppm_(Main_load)},
   {"save", libppm_(Main_save)},
+  {"size", libppm_(Main_size)},
   {NULL, NULL}
 };
 
diff --git a/init.lua b/init.lua
index 5f4b9ed..e77f309 100644
--- a/init.lua
+++ b/init.lua
@@ -309,6 +309,11 @@ local function savePGM(filename, tensor)
 end
 rawset(image, 'savePGM', savePGM)
 
+function image.getPPMsize(filename)
+   require 'libppm'
+   return torch.Tensor().libppm.size(filename)
+end
+
 local filetypes = {
    jpg = {loader = image.loadJPG, saver = image.saveJPG},
    png = {loader = image.loadPNG, saver = image.savePNG},
@@ -366,6 +371,8 @@ local function load(filename, depth, tensortype)
    local tensor
    if image.is_supported(ext) then
       tensor = filetypes[ext].loader(filename, depth, tensortype)
+   elseif not ext then
+      dok.error('unable to determine image type for file: ' .. filename, 'image.load')
    else
       dok.error('unknown image type: ' .. ext, 'image.load')
    end
@@ -374,6 +381,54 @@ local function load(filename, depth, tensortype)
 end
 rawset(image, 'load', load)
 
+filetypes.jpg.sizer = image.getJPGsize
+filetypes.png.sizer = image.getPNGsize
+filetypes.ppm.sizer = image.getPPMsize
+filetypes.pgm.sizer = image.getPPMsize -- sim. to loadPPM not loadPGM
+
+local function getSize(filename)
+   if not filename then
+      print(dok.usage('image.getSize',
+                       'returns size of image without loading', nil,
+                       {type='string', help='path to file', req=true}))
+      dok.error('missing file name', 'image.getSize')
+   end
+
+   local ext
+
+   local f, err = io.open(filename, 'rb')
+   if not f then
+      error(err)
+   end
+   local hdr = f:read(4) or ''
+   f:close()
+
+   if startswith(hdr, magicJPG) then
+      ext = 'jpg'
+   elseif startswith(hdr, magicPNG) then
+      ext = 'png'
+   elseif hdr:match('^P[25]') then
+      ext = 'pgm'
+   elseif hdr:match('^P[36]') then
+      ext = 'ppm'
+   end
+
+   if not ext then
+      ext = string.match(filename,'%.(%a+)$')
+   end
+   local size
+   if image.is_supported(ext) then
+      size = {filetypes[ext].sizer(filename)}
+   elseif not ext then
+      dok.error('unable to determine image type for file: ' .. filename, 'image.getSize')
+   else
+      dok.error('unknown image type: ' .. ext, 'image.load')
+   end
+
+   return torch.LongTensor(size)
+end
+rawset(image, 'getSize', getSize)
+
 local function save(filename, tensor)
    if not filename or not tensor then
       print(dok.usage('image.save',
@@ -969,6 +1024,128 @@ end
 rawset(image, 'warp', warp)
 
 ----------------------------------------------------------------------
+-- affine transform
+--
+local function affinetransform(...)
+   local dst,src,matrix
+   local mode = 'bilinear'
+   local translation = torch.Tensor{0,0}
+   local clamp_mode = 'clamp'
+   local pad_value = 0
+   local args = {...}
+   local nargs = select('#',...)
+   local bad_args = false
+   if nargs == 2 then
+      src = args[1]
+      matrix = args[2]
+   elseif nargs >= 3 then
+      if type(args[3]) == 'string' then
+         -- No destination tensor
+         src = args[1]
+         matrix = args[2]
+         mode = args[3]
+         if nargs >= 4 then translation = args[4] end
+         if nargs >= 5 then clamp_mode = args[5] end
+         if nargs >= 6 then
+           assert(clamp_mode == 'pad', 'pad_value can only be specified if' ..
+                                       ' clamp_mode = "pad"')
+           pad_value = args[6]
+         end
+         if nargs >= 7 then bad_args = true end
+      else
+         -- With Destination tensor
+         dst = args[1]
+         src = args[2]
+         matrix = args[3]
+         if nargs >= 4 then mode = args[4] end
+         if nargs >= 5 then translation = args[5] end
+         if nargs >= 6 then clamp_mode = args[6] end
+         if nargs >= 7 then
+           assert(clamp_mode == 'pad', 'pad_value can only be specified if' ..
+                                       ' clamp_mode = "pad"')
+           pad_value = args[7]
+         end
+         if nargs >= 8 then bad_args = true end
+      end
+   end
+   if bad_args then
+      print(dok.usage('image.warp',
+         'warp an image, according to given affine transform', nil,
+         {type='torch.Tensor', help='input image (KxHxW)', req=true},
+         {type='torch.Tensor', help='(y,x) affine translation matrix', req=true},
+         {type='string', help='mode: lanczos | bicubic | bilinear | simple', default='bilinear'},
+         {type='torch.Tensor', help='extra (y,x) translation to be done before transform', default=torch.Tensor{0,0}},
+         {type='string', help='clamp mode: how to handle interp of samples off the input image (clamp | pad)', default='clamp'},
+         '',
+         {type='torch.Tensor', help='input image (KxHxW)', req=true},
+         {type='torch.Tensor', help='(y,x) affine translation matrix', req=true},
+         {type='string', help='mode: lanczos | bicubic | bilinear | simple', default='bilinear'},
+         {type='torch.Tensor', help='extra (y,x) translation to be done before transform', default=torch.Tensor{0,0}},
+         {type='string', help='clamp mode: how to handle interp of samples off the input image (clamp | pad)', default='clamp'},
+         {type='number', help='pad value: value to pad image. Can only be set when clamp mode equals "pad"', default=0}))
+      dok.error('incorrect arguments', 'image.warp')
+   end
+   -- This is a little messy, but convert mode string to an enum
+   if (mode == 'simple') then
+      mode = 0
+   elseif (mode == 'bilinear') then
+      mode = 1
+   elseif (mode == 'bicubic') then
+      mode = 2
+   elseif (mode == 'lanczos') then
+      mode = 3
+   else
+      dok.error('Incorrect arguments (mode is not lanczos | bicubic | bilinear | simple)!', 'image.warp')
+   end
+   if (clamp_mode == 'clamp') then
+      clamp_mode = 0
+   elseif (clamp_mode == 'pad') then
+      clamp_mode = 1
+   else
+      dok.error('Incorrect arguments (clamp_mode is not clamp | pad)!', 'image.warp')
+   end
+
+   local dim2 = false
+   if src:nDimension() == 2 then
+      dim2 = true
+      src = src:reshape(1,src:size(1),src:size(2))
+   end
+   dst = dst or src.new()
+   dst:resize(src:size(1), src:size(2), src:size(3))
+
+   -- create field
+   local height = src:size(2)
+   local width = src:size(3)
+
+   local grid_y = torch.ger( torch.linspace(-1,1,height), torch.ones(width) )
+   local grid_x = torch.ger( torch.ones(height), torch.linspace(-1,1,width) )
+
+   local grid_xy = torch.Tensor()
+   grid_xy:resize(2,height,width)
+   grid_xy[1] = grid_y * ((height-1)/2) * -1
+   grid_xy[2] = grid_x * ((width-1)/2) * -1
+   local view_xy = grid_xy:reshape(2,height*width)
+
+   local matrix = matrix:typeAs(torch.Tensor()) -- coerce matrix to default tensor type
+   local field = torch.mm(matrix, view_xy)
+   field = (grid_xy - field:reshape( 2, height, width ))
+
+   -- offset field for translation
+   translation = torch.Tensor(translation)
+   field[1] = field[1] - translation[1]
+   field[2] = field[2] - translation[2]
+
+
+   local offset_mode = true
+   src.image.warp(dst, src, field, mode, offset_mode, clamp_mode, pad_value)
+   if dim2 then
+      dst = dst[1]
+   end
+   return dst
+end
+rawset(image, 'affinetransform', affinetransform)
+
+----------------------------------------------------------------------
 -- hflip
 --
 local function hflip(...)
diff --git a/test/test.lua b/test/test.lua
index 80299e9..0a25cd9 100644
--- a/test/test.lua
+++ b/test/test.lua
@@ -635,6 +635,17 @@ function test.test_pbmload()
 end
 
 ----------------------------------------------------------------------
+-- Load unknown image type without extension test
+--
+function test.LoadUnknownImageTypeWithoutExtension()
+  tester:assertErrorPattern(
+    function() image.load(getTestImagePath("bmp-without-ext")) end,
+    "unable to determine image type for file",
+    "unknown image type should not be loaded or unexpected error message"
+  )
+end
+
+----------------------------------------------------------------------
 -- Text drawing test
 --
 function test.test_textdraw()
diff --git a/test/test_warp.lua b/test/test_warp.lua
index 5c4a1ed..eb0a88e 100644
--- a/test/test_warp.lua
+++ b/test/test_warp.lua
@@ -137,3 +137,10 @@ image.display{image = im_lanczos, zoom = 4, legend = 'rotation lanczos (pad 1)'}
 
 image.display{image = im, zoom = 4, legend = 'source image'}
 
+-- ***********************************************
+-- NOW MAKE SURE BOTH FLOAT AND DOUBLE INPUTS WORK
+-- ***********************************************
+
+mtx = torch.zeros(2, 32, 32)
+out = image.warp(im:float(), mtx:float(), 'bilinear')
+out = image.warp(im:double(), mtx:double(), 'bilinear')

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/lua-torch-image.git



More information about the debian-science-commits mailing list