--[[ 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