4 dyncnn is a deep-learning algorithm for the prediction of
5 interacting object dynamics
7 Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
8 Written by Francois Fleuret <francois.fleuret@idiap.ch>
10 This file is part of dyncnn.
12 dyncnn is free software: you can redistribute it and/or modify it
13 under the terms of the GNU General Public License version 3 as
14 published by the Free Software Foundation.
16 dyncnn is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with dyncnn. If not, see <http://www.gnu.org/licenses/>.
30 The combineImage function takes as input a parameter c which is the
31 value to use for the background of the resulting image (padding and
32 such), and t which is either a 2d tensor, a 3d tensor, or a table.
34 * If t is a 3d tensor, it is returned unchanged.
36 * If t is a 2d tensor [r x c], it is reshaped to [1 x r x c] and
39 * If t is a table, combineImage first calls itself recursively on
42 It then creates a new tensor by concatenating the results
43 horizontally if t.vertical is nil, vertically otherwise.
45 It adds a padding of t.pad pixels if this field is set.
49 x = torch.Tensor(64, 64):fill(0.5)
50 y = torch.Tensor(100, 30):fill(0.85)
52 i = combineImages(1.0,
59 { pad = 4, torch.Tensor(32, 16):fill(0.25) },
60 { pad = 1, torch.Tensor(45, 54):uniform(0.25, 0.9) },
65 image.save('example.png', i)
69 function combineImages(c, t)
71 if torch.isTensor(t) then
75 elseif t:dim() == 2 then
76 return torch.Tensor(1, t:size(1), t:size(2)):copy(t)
78 error('can only deal with [height x width] or [channel x height x width] tensors.')
83 local subImages = {} -- The subimages
84 local nc = 0 -- Nb of columns
85 local nr = 0 -- Nb of rows
87 for i, x in ipairs(t) do
88 subImages[i] = combineImages(c, x)
90 nr = nr + subImages[i]:size(2)
91 nc = math.max(nc, subImages[i]:size(3))
93 nr = math.max(nr, subImages[i]:size(2))
94 nc = nc + subImages[i]:size(3)
98 local pad = t.pad or 0
99 local result = torch.Tensor(subImages[1]:size(1), nr + 2 * pad, nc + 2 * pad):fill(c)
100 local co = 1 + pad -- Origin column
101 local ro = 1 + pad -- Origin row
103 for i in ipairs(t) do
105 result:sub(1, subImages[1]:size(1),
106 ro, ro + subImages[i]:size(2) - 1,
107 co, co + subImages[i]:size(3) - 1):copy(subImages[i])
110 ro = ro + subImages[i]:size(2)
112 co = co + subImages[i]:size(3)
125 The imageFromTensors function gets as input a list of tensors of
126 arbitrary dimensions each, but whose two last dimensions stand for
127 height x width. It creates an image tensor (2d, one channel) with each
128 argument tensor unfolded per row.
132 function imageFromTensors(bt, signed)
138 for _, t in pairs(bt) do
140 local h, w = t:size(d - 1), t:size(d)
141 local n = t:nElement() / (w * h)
142 width = math.max(width, gap + n * (gap + w))
143 height = height + gap + tgap + gap + h
146 local e = torch.Tensor(3, height, width):fill(1.0)
149 for _, t in pairs(bt) do
151 local h, w = t:size(d - 1), t:size(d)
152 local n = t:nElement() / (w * h)
153 local z = t:norm() / math.sqrt(t:nElement())
155 local x0 = 1 + gap + math.floor( (width - n * (w + gap)) /2 )
156 local u = torch.Tensor(t:size()):copy(t):resize(n, h, w)
161 e[c][y0 + y - 1][x0 - 1] = 0.0
162 e[c][y0 + y - 1][x0 + w ] = 0.0
165 e[c][y0 - 1][x0 + x - 1] = 0.0
166 e[c][y0 + h ][x0 + x - 1] = 0.0
172 local v = u[m][y][x] / z
176 r, g, b = 0.0, 0.0, 1.0
178 r, g, b = 1.0, 0.0, 0.0
180 r, g, b = 1.0, 1.0 - v, 1.0 - v
182 r, g, b = 1.0 + v, 1.0 + v, 1.0
186 r, g, b = 1.0, 1.0, 1.0
188 r, g, b = 0.0, 0.0, 0.0
190 r, g, b = 1.0 - v, 1.0 - v, 1.0 - v
193 e[1][y0 + y - 1][x0 + x - 1] = r
194 e[2][y0 + y - 1][x0 + x - 1] = g
195 e[3][y0 + y - 1][x0 + x - 1] = b
200 y0 = y0 + h + gap + tgap + gap