X-Git-Url: https://fleuret.org/cgi-bin/gitweb/gitweb.cgi?p=dyncnn.git;a=blobdiff_plain;f=img.lua;fp=img.lua;h=afed4e0af0ae3b787269558e1e46f70a45637b7c;hp=0000000000000000000000000000000000000000;hb=fe5dee151313b6abd8ffee2c5fc5593f326e663f;hpb=be0c7d53f21ce96c70e7c13ef0ba2c9eca10ca23 diff --git a/img.lua b/img.lua new file mode 100755 index 0000000..afed4e0 --- /dev/null +++ b/img.lua @@ -0,0 +1,204 @@ + +--[[ + + dyncnn is a deep-learning algorithm for the prediction of + interacting object dynamics + + Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ + Written by Francois Fleuret + + This file is part of dyncnn. + + dyncnn is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License version 3 as + published by the Free Software Foundation. + + dyncnn is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with dyncnn. If not, see . + +]]-- + +require 'torch' + +--[[ + +The combineImage function takes as input a parameter c which is the +value to use for the background of the resulting image (padding and +such), and t which is either a 2d tensor, a 3d tensor, or a table. + + * If t is a 3d tensor, it is returned unchanged. + + * If t is a 2d tensor [r x c], it is reshaped to [1 x r x c] and + returned. + + * If t is a table, combineImage first calls itself recursively on + t[1], t[2], etc. + + It then creates a new tensor by concatenating the results + horizontally if t.vertical is nil, vertically otherwise. + + It adds a padding of t.pad pixels if this field is set. + + * Example + + x = torch.Tensor(64, 64):fill(0.5) + y = torch.Tensor(100, 30):fill(0.85) + + i = combineImages(1.0, + { + pad = 1, + vertical = true, + { pad = 1, x }, + { + y, + { pad = 4, torch.Tensor(32, 16):fill(0.25) }, + { pad = 1, torch.Tensor(45, 54):uniform(0.25, 0.9) }, + } + } + ) + + image.save('example.png', i) + +]]-- + +function combineImages(c, t) + + if torch.isTensor(t) then + + if t:dim() == 3 then + return t + elseif t:dim() == 2 then + return torch.Tensor(1, t:size(1), t:size(2)):copy(t) + else + error('can only deal with [height x width] or [channel x height x width] tensors.') + end + + else + + local subImages = {} -- The subimages + local nc = 0 -- Nb of columns + local nr = 0 -- Nb of rows + + for i, x in ipairs(t) do + subImages[i] = combineImages(c, x) + if t.vertical then + nr = nr + subImages[i]:size(2) + nc = math.max(nc, subImages[i]:size(3)) + else + nr = math.max(nr, subImages[i]:size(2)) + nc = nc + subImages[i]:size(3) + end + end + + local pad = t.pad or 0 + local result = torch.Tensor(subImages[1]:size(1), nr + 2 * pad, nc + 2 * pad):fill(c) + local co = 1 + pad -- Origin column + local ro = 1 + pad -- Origin row + + for i in ipairs(t) do + + result:sub(1, subImages[1]:size(1), + ro, ro + subImages[i]:size(2) - 1, + co, co + subImages[i]:size(3) - 1):copy(subImages[i]) + + if t.vertical then + ro = ro + subImages[i]:size(2) + else + co = co + subImages[i]:size(3) + end + + end + + return result + + end + +end + +--[[ + +The imageFromTensors function gets as input a list of tensors of +arbitrary dimensions each, but whose two last dimensions stand for +height x width. It creates an image tensor (2d, one channel) with each +argument tensor unfolded per row. + +]]-- + +function imageFromTensors(bt, signed) + local gap = 1 + local tgap = -1 + local width = 0 + local height = gap + + for _, t in pairs(bt) do + local d = t:dim() + local h, w = t:size(d - 1), t:size(d) + local n = t:nElement() / (w * h) + width = math.max(width, gap + n * (gap + w)) + height = height + gap + tgap + gap + h + end + + local e = torch.Tensor(3, height, width):fill(1.0) + local y0 = 1 + gap + + for _, t in pairs(bt) do + local d = t:dim() + local h, w = t:size(d - 1), t:size(d) + local n = t:nElement() / (w * h) + local z = t:norm() / math.sqrt(t:nElement()) + + local x0 = 1 + gap + math.floor( (width - n * (w + gap)) /2 ) + local u = torch.Tensor(t:size()):copy(t):resize(n, h, w) + for m = 1, n do + + for c = 1, 3 do + for y = 0, h+1 do + e[c][y0 + y - 1][x0 - 1] = 0.0 + e[c][y0 + y - 1][x0 + w ] = 0.0 + end + for x = 0, w+1 do + e[c][y0 - 1][x0 + x - 1] = 0.0 + e[c][y0 + h ][x0 + x - 1] = 0.0 + end + end + + for y = 1, h do + for x = 1, w do + local v = u[m][y][x] / z + local r, g, b + if signed then + if v < -1 then + r, g, b = 0.0, 0.0, 1.0 + elseif v > 1 then + r, g, b = 1.0, 0.0, 0.0 + elseif v >= 0 then + r, g, b = 1.0, 1.0 - v, 1.0 - v + else + r, g, b = 1.0 + v, 1.0 + v, 1.0 + end + else + if v <= 0 then + r, g, b = 1.0, 1.0, 1.0 + elseif v > 1 then + r, g, b = 0.0, 0.0, 0.0 + else + r, g, b = 1.0 - v, 1.0 - v, 1.0 - v + end + end + e[1][y0 + y - 1][x0 + x - 1] = r + e[2][y0 + y - 1][x0 + x - 1] = g + e[3][y0 + y - 1][x0 + x - 1] = b + end + end + x0 = x0 + w + gap + end + y0 = y0 + h + gap + tgap + gap + end + + return e +end