[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