Skip to content

Commit 25c9de8

Browse files
author
Adrià Arrufat
committed
Fix integral image computation and at tests
1 parent bd64fc6 commit 25c9de8

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

build.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub fn build(b: *std.Build) void {
1515
const test_step = b.step("test", "Run library tests");
1616
for ([_][]const u8{
1717
"color",
18+
"image",
1819
"geometry",
1920
"matrix",
2021
"svd",

src/image.zig

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const std = @import("std");
2+
const expectEqual = std.testing.expectEqual;
23
const Allocator = std.mem.Allocator;
34
const Rgba = @import("color.zig").Rgba;
45
const as = @import("meta.zig").as;
@@ -154,10 +155,14 @@ pub fn Image(comptime T: type) type {
154155
}
155156

156157
/// 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 {
158163
switch (@typeInfo(T)) {
159164
.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);
161166
var tmp: f32 = 0;
162167
for (0..self.cols) |c| {
163168
tmp += as(f32, (self.data[c]));
@@ -172,32 +177,74 @@ pub fn Image(comptime T: type) type {
172177
integral.data[curr_pos] = tmp + integral.data[prev_pos];
173178
}
174179
}
175-
return integral;
176180
},
177181
.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;
180185
for (0..self.cols) |c| {
181186
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];
184192
}
185193
}
186194
for (1..self.rows) |r| {
187-
tmp = 0;
195+
tmp = [_]f32{0} ** num_fields;
188196
for (0..self.cols) |c| {
189197
const curr_pos = r * self.cols + c;
190198
const prev_pos = (r - 1) * self.cols + c;
191199
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];
194202
}
195203
}
196204
}
197-
return integral;
198205
},
199206
else => @compileError("Can't compute the integral image of " ++ @typeName(T) ++ "."),
200207
}
201208
}
202209
};
203210
}
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

Comments
 (0)