1## Copyright (C) 2019 Avinoam Kalma <a.kalma@gmail.com>
2##
3## This program is free software: you can redistribute it and/or modify
4## it under the terms of the GNU General Public License as published by
5## the Free Software Foundation, either version 3 of the License, or
6## (at your option) any later version.
7##
8## This program is distributed in the hope that it will be useful,
9## but WITHOUT ANY WARRANTY; without even the implied warranty of
10## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11## GNU General Public License for more details.
12##
13## You should have received a copy of the GNU General Public License
14## along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16## -*- texinfo -*-
17## @deftypefn  {Function File} {} integralImage (@var{img})
18## Calculate the 3D integral image.
19##
20## @var{img} is the input image for 3D integral image calculation.
21##
22## The value of the 3D integral image is J = cumsum (cumsum (cumsum (I), 2), 3)
23## with padding.
24## The padding adds a zeros plane, zero rows and zero column, so size (J) = size (I) + 1.
25##
26## @seealso{integralImage, cumsum}
27## @end deftypefn
28
29function J = integralImage3 (I)
30
31  if (nargin != 1)
32    print_usage ();
33endif
34
35  if (! isimage (I))
36    error ("integralImage3: I should be an image");
37  endif
38
39  if (ndims (I) > 3)
40    error ("integralImage3: I should be a 3-dimensional image");
41  endif
42
43  if (! isa (I, "double"))
44    I = double (I);
45  endif
46
47  J = cumsum (cumsum (cumsum (I), 2), 3);
48  J = padarray (J, [1 1 1], "pre");
49
50endfunction
51
52%!test
53%! assert (integralImage3 (zeros (4)), zeros (5, 5, 2));
54
55%!test
56%! J_res = zeros (2, 2, 2);
57%! J_res(2, 2, 2) = 10;
58%! assert (integralImage3 (10), J_res);
59
60%!test
61%! J = integralImage3 (10);
62%! assert (class (J), "double");
63%! J = integralImage3 (uint8 (10));
64%! assert (class (J), "double");
65
66%!test
67%! I = [1, 2; 3, 4];
68%! J = integralImage3 (I);
69%! J_res = zeros (3, 3, 2);
70%! J_res(2:3, 2:3, 2) = [1 3; 4 10];
71%! assert (J, J_res)
72
73%!test
74%! I1 = [1, 2; 3, 4];
75%! I2 = [5, 6; 7, 8];
76%! I3 = [9, 10; 11, 12];
77%! I = cat (3, I1, I2, I3);
78%! J = integralImage3 (I);
79%! J2 = [0 0 0; 0 1 3; 0 4 10];
80%! J3 = [0 0 0; 0 6 14; 0 16 36];
81%! J4 = [0 0 0; 0 15 33; 0 36 78];
82%! J_res = cat (3, zeros (3), J2, J3, J4);
83%! assert (J, J_res)
84
85%!test
86%! I = magic (5);
87%! J = integralImage3 (I);
88%! J_res = zeros (6, 6, 2);
89%! J_res(:, :, 2) = [0   0   0  0    0   0;
90%!                    0  17  41 42   50  65;
91%!                    0  40  69 77   99 130;
92%!                    0  44  79 100 142 195;
93%!                    0  54 101 141 204 260;
94%!                    0  65 130 195 260 325];
95%! assert (J, J_res)
96
97%!# test of 3d input image:
98
99%!test
100%! K = magic (8);
101%! K = reshape (K, [4 4 4]);
102%! L = integralImage3 (K);
103%! L1_ML = zeros (5);
104%! L2_ML = [0 0 0 0 0;
105%!    0 64 96 98 132;
106%!    0 73 146 203 260;
107%!    0 90 212 316 388;
108%!    0 130 260 390 520];
109%! L3_ML = [0 0 0 0 0;
110%!   0 67 134 197 260;
111%!   0 130 260 390 520;
112%!   0 193 386 583 780;
113%!   0 260 520 780 1040];
114%! L4_ML = [0 0 0 0 0;
115%!   0 127 222 291 392;
116%!   0 203 406 593 780;
117%!   0 287 606 903 1168;
118%!   0 390 780 1170 1560];
119%! L5_ML = [0 0 0 0 0;
120%!   0 134 268 394 520;
121%!   0 260 520 780 1040;
122%!   0 386 772 1166 1560;
123%!   0 520 1040 1560 2080];
124%! L_ML = cat (3, L1_ML, L2_ML, L3_ML, L4_ML, L5_ML);
125%! assert (L, L_ML)
126
127%!# test of 2d input image:
128%!test
129%! X = ones (3);
130%! Y = integralImage3 (X);
131%! Y_ML = zeros (4, 4, 2);
132%! Y_ML(:, :, 2) = [0 0 0 0; 0 1 2 3; 0 2 4 6; 0 3 6 9];
133%! assert(Y, Y_ML);
134
135%!error <Invalid call to integralImage3>
136%! integralImage3 ();
137
138%!error <Invalid call to integralImage3>
139%! integralImage3 (zeros (3), zeros (3));
140
141%!error <integralImage3: I should be an image>
142%! integralImage3 ("abcd");
143
144%!error <integralImage3: I should be an image>
145%! integralImage3 (1+i);
146
147%!error <integralImage3: I should be a 3-dimensional image>
148%! integralImage3 (reshape (1:81, 3, 3, 3, 3));
149