Skip to content

Commit e5efbed

Browse files
committed
Update GaussKernel.ts
1 parent ddf7cf0 commit e5efbed

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

‎test/unit/utils/GaussKernel.ts‎

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from "node:assert/strict";
22
import { describe, it } from "node:test";
33
import { GaussKernel } from "postprocessing";
4+
import { assertClose, assertCloseSequence } from "../../support/assert.ts";
45

56
describe("GaussKernel", () => {
67

@@ -10,4 +11,130 @@ describe("GaussKernel", () => {
1011

1112
});
1213

14+
it("produces the expected discrete offsets and weights", () => {
15+
16+
const kernel = GaussKernel.create(9, 1);
17+
18+
assert.equal(kernel.steps, 5);
19+
20+
// Offsets run from the center (index 0) outwards by one sample each step.
21+
assertCloseSequence(kernel.offsets, [0, 1, 2, 3, 4]);
22+
23+
// Center-aligned discrete Gaussian for sigma = 1, normalized so the symmetric kernel sums to 1.
24+
// The center weight is exp(0) / sum = 1 / 2.5066...
25+
assertCloseSequence(kernel.weights, [
26+
0.39894346935609781,
27+
0.24197144565660075,
28+
0.053991127420704416,
29+
0.0044318616200312664,
30+
0.00013383062461474178
31+
]);
32+
33+
});
34+
35+
it("produces the expected linear offsets and weights", () => {
36+
37+
const kernel = GaussKernel.create(9, 1);
38+
39+
assert.equal(kernel.linearSteps, 3);
40+
41+
// linearWeights combine the adjacent discrete samples for bilinear filtering,
42+
// and linearOffsets are their weighted centroids.
43+
assertCloseSequence(kernel.linearWeights, [
44+
0.39894346935609781,
45+
0.29596257307730517,
46+
0.0045656922446460080
47+
]);
48+
49+
assertCloseSequence(kernel.linearOffsets, [
50+
0,
51+
1.1824255238063563,
52+
3.0293122307513562
53+
]);
54+
55+
});
56+
57+
it("normalizes the symmetric kernel to sum to one", () => {
58+
59+
for(const [kernelSize, sigma] of [[3, 0.7], [5, 1.5], [9, 1], [15, 2], [9, 3]] as const) {
60+
61+
const kernel = GaussKernel.create(kernelSize, sigma);
62+
63+
// The stored weights cover only the center and one side;
64+
// the full symmetric kernel therefore sums as weights[0] + 2 * (sum of the remaining weights).
65+
const sum = Array.from(kernel.weights).reduce(
66+
(total, weight, index) => total + weight * (index === 0 ? 1 : 2),
67+
0.0
68+
);
69+
70+
assertClose(sum, 1.0);
71+
72+
}
73+
74+
});
75+
76+
it("keeps the weights centered, positive, and monotonically decreasing", () => {
77+
78+
const kernel = GaussKernel.create(15, 1.5);
79+
80+
assert.equal(kernel.offsets[0], 0);
81+
82+
for(let i = 0; i < kernel.steps; ++i) {
83+
84+
const weight = kernel.weights[i];
85+
86+
assert.ok(weight > 0.0, `weight[${i}] should be positive`);
87+
88+
if(i > 0) {
89+
90+
const previous = kernel.weights[i - 1];
91+
assert.ok(weight < previous, `weight[${i}] should decrease from weight[${i - 1}]`);
92+
93+
}
94+
95+
}
96+
97+
});
98+
99+
it("partitions the half-kernel energy across the linear weights", () => {
100+
101+
for(const [kernelSize, sigma] of [[5, 2], [7, 0.5], [9, 1], [11, 1], [9, 3]] as const) {
102+
103+
const kernel = GaussKernel.create(kernelSize, sigma);
104+
105+
const linearSum = Array.from(kernel.linearWeights).reduce(
106+
(total, weight) => total + weight,
107+
0.0
108+
);
109+
110+
// The linear weights must account for exactly the discrete half-kernel
111+
// (center plus one side), which is (1 + centerWeight) / 2.
112+
assertClose(linearSum, (1.0 + kernel.weights[0]) / 2.0);
113+
114+
}
115+
116+
});
117+
118+
it("rejects invalid kernel sizes and sigma", () => {
119+
120+
for(const kernelSize of [0, 2, 4, -1, 9.5, 1021, Number.NaN, Number.POSITIVE_INFINITY]) {
121+
122+
assert.throws(
123+
() => GaussKernel.create(kernelSize, 1.0),
124+
{ name: "Error", message: /kernel size/i }
125+
);
126+
127+
}
128+
129+
for(const sigma of [0, -1, Number.NaN, Number.POSITIVE_INFINITY]) {
130+
131+
assert.throws(
132+
() => GaussKernel.create(9, sigma),
133+
{ name: "Error", message: /sigma/i }
134+
);
135+
136+
}
137+
138+
});
139+
13140
});

0 commit comments

Comments
 (0)