1
1
const std = @import ("std" );
2
+ const expectEqual = std .testing .expectEqual ;
2
3
const Allocator = std .mem .Allocator ;
3
4
const Rgba = @import ("color.zig" ).Rgba ;
4
5
const as = @import ("meta.zig" ).as ;
@@ -154,10 +155,14 @@ pub fn Image(comptime T: type) type {
154
155
}
155
156
156
157
/// Computes the integral image of self.
157
- pub fn integralImage (self : Self , allocator : Allocator ) ! (if (isScalar (T )) Image (f32 ) else if (isStruct (T )) Image ([std .meta .fields (T ).len ]f32 ) else @compileError ("Can't compute the integral image of " ++ @typeName (T ) ++ "." )) {
158
+ pub fn integralImage (
159
+ self : Self ,
160
+ allocator : Allocator ,
161
+ integral : * Image (if (isScalar (T )) f32 else if (isStruct (T )) [std .meta .fields (T ).len ]f32 else @compileError ("Can't compute the integral image of " ++ @typeName (T ) ++ "." )),
162
+ ) ! void {
158
163
switch (@typeInfo (T )) {
159
164
.ComptimeInt , .Int , .ComptimeFloat , .Float = > {
160
- var integral = try Image (f32 ).initAlloc (allocator , self .rows , self .cols );
165
+ integral .* = try Image (f32 ).initAlloc (allocator , self .rows , self .cols );
161
166
var tmp : f32 = 0 ;
162
167
for (0.. self .cols ) | c | {
163
168
tmp += as (f32 , (self .data [c ]));
@@ -172,32 +177,74 @@ pub fn Image(comptime T: type) type {
172
177
integral .data [curr_pos ] = tmp + integral .data [prev_pos ];
173
178
}
174
179
}
175
- return integral ;
176
180
},
177
181
.Struct = > {
178
- var integral = try Image ([std .meta .fields (T ).len ]f32 ).initAlloc (allocator , self .rows , self .cols );
179
- var tmp : f32 = 0 ;
182
+ const num_fields = std .meta .fields (T ).len ;
183
+ integral .* = try Image ([num_fields ]f32 ).initAlloc (allocator , self .rows , self .cols );
184
+ var tmp = [_ ]f32 {0 } ** num_fields ;
180
185
for (0.. self .cols ) | c | {
181
186
inline for (std .meta .fields (T ), 0.. ) | f , i | {
182
- tmp += as (f32 , @field (self .data [c ], f .name ));
183
- integral .data [c ][i ] = tmp ;
187
+ if (c < 1 ) {
188
+ std .log .debug ("{s}: {d}" , .{ f .name , @field (self .data [c ], f .name ) });
189
+ }
190
+ tmp [i ] += as (f32 , @field (self .data [c ], f .name ));
191
+ integral .data [c ][i ] = tmp [i ];
184
192
}
185
193
}
186
194
for (1.. self .rows ) | r | {
187
- tmp = 0 ;
195
+ tmp = [ _ ] f32 { 0 } ** num_fields ;
188
196
for (0.. self .cols ) | c | {
189
197
const curr_pos = r * self .cols + c ;
190
198
const prev_pos = (r - 1 ) * self .cols + c ;
191
199
inline for (std .meta .fields (T ), 0.. ) | f , i | {
192
- tmp += as (f32 , @field (self .data [curr_pos ], f .name ));
193
- integral .data [curr_pos ][i ] = tmp + integral .data [prev_pos ][i ];
200
+ tmp [ i ] += as (f32 , @field (self .data [curr_pos ], f .name ));
201
+ integral .data [curr_pos ][i ] = tmp [ i ] + integral .data [prev_pos ][i ];
194
202
}
195
203
}
196
204
}
197
- return integral ;
198
205
},
199
206
else = > @compileError ("Can't compute the integral image of " ++ @typeName (T ) ++ "." ),
200
207
}
201
208
}
202
209
};
203
210
}
211
+
212
+ test "integral image scalar" {
213
+ var image = try Image (u8 ).initAlloc (std .testing .allocator , 21 , 13 );
214
+ defer image .deinit (std .testing .allocator );
215
+ for (image .data ) | * i | i .* = 1 ;
216
+ var integral : Image (f32 ) = undefined ;
217
+ try image .integralImage (std .testing .allocator , & integral );
218
+ defer integral .deinit (std .testing .allocator );
219
+ try expectEqual (image .rows , integral .rows );
220
+ try expectEqual (image .cols , integral .cols );
221
+ try expectEqual (image .data .len , integral .data .len );
222
+ for (0.. image .rows ) | r | {
223
+ for (0.. image .cols ) | c | {
224
+ const pos = r * image .cols + c ;
225
+ const area_at_pos : f32 = @floatFromInt ((r + 1 ) * (c + 1 ));
226
+ try expectEqual (area_at_pos , integral .data [pos ]);
227
+ }
228
+ }
229
+ }
230
+
231
+ test "integral image struct" {
232
+ var image = try Image (Rgba ).initAlloc (std .testing .allocator , 21 , 13 );
233
+ defer image .deinit (std .testing .allocator );
234
+ for (image .data ) | * i | i .* = .{ .r = 1 , .g = 1 , .b = 1 , .a = 1 };
235
+ var integral : Image ([4 ]f32 ) = undefined ;
236
+ try image .integralImage (std .testing .allocator , & integral );
237
+ defer integral .deinit (std .testing .allocator );
238
+ try expectEqual (image .rows , integral .rows );
239
+ try expectEqual (image .cols , integral .cols );
240
+ try expectEqual (image .data .len , integral .data .len );
241
+ for (0.. image .rows ) | r | {
242
+ for (0.. image .cols ) | c | {
243
+ const pos = r * image .cols + c ;
244
+ const area_at_pos : f32 = @floatFromInt ((r + 1 ) * (c + 1 ));
245
+ for (0.. 4) | i | {
246
+ try expectEqual (area_at_pos , integral .data [pos ][i ]);
247
+ }
248
+ }
249
+ }
250
+ }
0 commit comments