nx_scale_test.nx source
↩ module page · 108 lines · 3926 B
1// nx_scale_test.nx -- smoke for V6 scale pyramid primitives.
2
3import "syscalls.nx"
4import "nx_image.nx"
5import "nx_scale.nx"
6
7func main() -> i64 {
8 // === Test 1: Gaussian blur preserves uniform field ===
9 // All pixels 100. After blur all pixels should still be 100
10 // (binomial sums to 16, /16 = 1). Border pixels lose energy
11 // due to zero-padded out-of-bounds reads -- but the interior
12 // should be exactly 100.
13 let img1: *Image = nx_image_alloc(16, 16, 1)
14 var y: i64 = 0
15 while y < 16 {
16 var x: i64 = 0
17 while x < 16 {
18 nx_image_set(img1, x, y, 0, 100)
19 x = x + 1
20 }
21 y = y + 1
22 }
23 let b1: *Image = nx_scale_gauss_blur(img1)
24 // Interior pixel (8, 8) should be exactly 100.
25 if nx_image_get(b1, 8, 8, 0) != 100 { return 1 }
26
27 // === Test 2: downsample 2x dimensions ===
28 let d1: *Image = nx_scale_downsample_2x(img1)
29 if d1.width != 8 { return 10 }
30 if d1.height != 8 { return 11 }
31 // Interior value preserved
32 if nx_image_get(d1, 4, 4, 0) != 100 { return 12 }
33
34 // === Test 3: full Gaussian pyramid ===
35 let py: *GaussPyramid = nx_scale_gauss_pyramid(img1, 4)
36 if py.n_levels != 4 { return 20 }
37 let l0: *Image = nx_scale_pyramid_get(py, 0)
38 let l1: *Image = nx_scale_pyramid_get(py, 1)
39 let l2: *Image = nx_scale_pyramid_get(py, 2)
40 let l3: *Image = nx_scale_pyramid_get(py, 3)
41 if l0.width != 16 { return 21 }
42 if l1.width != 8 { return 22 }
43 if l2.width != 4 { return 23 }
44 if l3.width != 2 { return 24 }
45
46 // === Test 4: DoG on uniform image is zero ===
47 let dog1: *ImageS64 = nx_scale_dog(img1)
48 if nx_image_s64_get(dog1, 8, 8) != 0 { return 30 }
49
50 // === Test 5: DoG on a single bright spot ===
51 // Build 32x32 image with bright square at center.
52 let img2: *Image = nx_image_alloc(32, 32, 1)
53 // Background 50
54 var y2: i64 = 0
55 while y2 < 32 {
56 var x2: i64 = 0
57 while x2 < 32 {
58 nx_image_set(img2, x2, y2, 0, 50)
59 x2 = x2 + 1
60 }
61 y2 = y2 + 1
62 }
63 // Bright 6x6 blob at center
64 var yb: i64 = 13
65 while yb < 19 {
66 var xb: i64 = 13
67 while xb < 19 {
68 nx_image_set(img2, xb, yb, 0, 200)
69 xb = xb + 1
70 }
71 yb = yb + 1
72 }
73 let dog2: *ImageS64 = nx_scale_dog(img2)
74 // Detect extrema.
75 let bx: *i64 = (sys_mmap(50 * 8)) as *i64
76 let by: *i64 = (sys_mmap(50 * 8)) as *i64
77 let bs: *i64 = (sys_mmap(50 * 8)) as *i64
78 let n_blobs: i64 = nx_scale_dog_extrema(dog2, 2, 50, bx, by, bs)
79 if n_blobs == 0 { return 40 }
80 // At least one extremum should be near the blob center (16, 16).
81 var found_blob: i64 = 0
82 var bi: i64 = 0
83 while bi < n_blobs {
84 let dx: i64 = bx[bi] - 16
85 let dy: i64 = by[bi] - 16
86 let d2: i64 = dx * dx + dy * dy
87 if d2 <= 25 { found_blob = 1 } // within 5px
88 bi = bi + 1
89 }
90 if found_blob != 1 { return 41 }
91
92 // === Test 6: pyramid preserves bright-blob center across scales ===
93 let py2: *GaussPyramid = nx_scale_gauss_pyramid(img2, 3)
94 let l0p: *Image = nx_scale_pyramid_get(py2, 0)
95 let l1p: *Image = nx_scale_pyramid_get(py2, 1)
96 let l2p: *Image = nx_scale_pyramid_get(py2, 2)
97 // Level 1 is 16x16. Blob originally at (13..18, 13..18) maps to (6.5..9, 6.5..9).
98 // Pixel (8, 8) at level 1 should be much brighter than (1, 1).
99 let v1_center: i64 = nx_image_get(l1p, 8, 8, 0)
100 let v1_corner: i64 = nx_image_get(l1p, 1, 1, 0)
101 if v1_center <= v1_corner { return 50 }
102 // Level 2 is 8x8. Blob center maps to (4, 4).
103 let v2_center: i64 = nx_image_get(l2p, 4, 4, 0)
104 let v2_corner: i64 = nx_image_get(l2p, 0, 0, 0)
105 if v2_center <= v2_corner { return 51 }
106
107 return 0
108}