code wiki / (root) / nx_features_test.nx

nx_features_test.nx source

↩ module page · 194 lines · 6806 B

1// nx_features_test.nx -- smoke for image + feature primitives. 2// 3// Uses SYNTHETIC test images (generated procedurally) so the smoke 4// has no external dependency. 5 6import "syscalls.nx" 7import "nx_axioms.nx" 8import "nx_image.nx" 9import "nx_features.nx" 10import "nx_qed_freek.nx" 11 12func main() -> i64 { 13 // === Test 1: build a 16x16 RGB image (solid white) 14 // and verify pixel access. 15 let img: *Image = nx_image_alloc(16, 16, 3) 16 var y: i64 = 0 17 while y < 16 { 18 var x: i64 = 0 19 while x < 16 { 20 nx_image_set(img, x, y, 0, 200) // R 21 nx_image_set(img, x, y, 1, 150) // G 22 nx_image_set(img, x, y, 2, 100) // B 23 x = x + 1 24 } 25 y = y + 1 26 } 27 if nx_image_get(img, 5, 5, 0) != 200 { return 1 } 28 if nx_image_get(img, 5, 5, 1) != 150 { return 2 } 29 if nx_image_get(img, 5, 5, 2) != 100 { return 3 } 30 if nx_image_get(img, 100, 100, 0) != 0 { return 4 } // out of bounds returns 0 31 32 // === Test 2: grayscale conversion 33 let gray: *Image = nx_image_to_grayscale(img) 34 if gray.channels != 1 { return 10 } 35 // Expected: (218*200 + 732*150 + 74*100) / 1024 36 // = (43600 + 109800 + 7400) / 1024 37 // = 160800 / 1024 ~= 157 38 let g_expected: i64 = (218 * 200 + 732 * 150 + 74 * 100) / 1024 39 if nx_image_get(gray, 5, 5, 0) != g_expected { return 11 } 40 41 // === Test 3: build a synthetic edge image 42 // (left half black, right half white) 43 let edge: *Image = nx_image_alloc(16, 16, 1) 44 var y2: i64 = 0 45 while y2 < 16 { 46 var x2: i64 = 0 47 while x2 < 16 { 48 var v: i64 = 0 49 if x2 >= 8 { v = 255 } 50 nx_image_set(edge, x2, y2, 0, v) 51 x2 = x2 + 1 52 } 53 y2 = y2 + 1 54 } 55 // Sobel x should detect the vertical edge at x=8. 56 let gx: *ImageS64 = nx_image_sobel_x(edge) 57 // At (7, 8) we expect a strong positive response (pixels to the 58 // right are 255, pixels to the left are 0). 59 let gx_at_7: i64 = nx_image_s64_get(gx, 7, 8) 60 if gx_at_7 <= 0 { return 20 } 61 // At (3, 8) we're inside the dark region, gradient should be 0. 62 let gx_at_3: i64 = nx_image_s64_get(gx, 3, 8) 63 if gx_at_3 != 0 { return 21 } 64 65 // === Test 4: Sobel y on a horizontal edge 66 let hedge: *Image = nx_image_alloc(16, 16, 1) 67 var y3: i64 = 0 68 while y3 < 16 { 69 var x3: i64 = 0 70 while x3 < 16 { 71 var v: i64 = 0 72 if y3 >= 8 { v = 255 } 73 nx_image_set(hedge, x3, y3, 0, v) 74 x3 = x3 + 1 75 } 76 y3 = y3 + 1 77 } 78 let gy: *ImageS64 = nx_image_sobel_y(hedge) 79 let gy_at_8: i64 = nx_image_s64_get(gy, 8, 7) 80 if gy_at_8 <= 0 { return 30 } 81 82 // === Test 5: gradient magnitude 83 let edge_gx: *ImageS64 = nx_image_sobel_x(edge) 84 let edge_gy: *ImageS64 = nx_image_sobel_y(edge) 85 let mag: *ImageS64 = nx_image_gradient_magnitude(edge_gx, edge_gy) 86 let mag_at_7: i64 = nx_image_s64_get(mag, 7, 8) 87 if mag_at_7 <= 0 { return 40 } 88 89 // === Test 6: histogram of edge image 90 let bins: *i64 = (sys_mmap(256 * 8)) as *i64 91 nx_image_histogram_256(edge, 0, bins) 92 // half black (0) + half white (255). 8 columns * 16 rows = 128 each. 93 if bins[0] != 128 { return 50 } 94 if bins[255] != 128 { return 51 } 95 // Middle bins all zero. 96 if bins[128] != 0 { return 52 } 97 98 // === Test 7: Otsu threshold should land between black and white 99 let t: i64 = nx_image_otsu_threshold(edge, 0) 100 if t < 1 { return 60 } 101 if t > 254 { return 61 } 102 103 // === Test 8: threshold to binary mask 104 let mask: *Image = nx_image_threshold(edge, 0, 128) 105 if nx_image_get(mask, 3, 8, 0) != 0 { return 70 } 106 if nx_image_get(mask, 12, 8, 0) != 255 { return 71 } 107 108 // === Test 9: edge mask via Sobel + threshold 109 let emask: *Image = nx_feat_edge_mask(edge, 100) 110 // Edge should be detected near x=7-8. 111 if nx_image_get(emask, 7, 8, 0) != 255 { return 80 } 112 // Interior should not be edge. 113 if nx_image_get(emask, 2, 8, 0) != 0 { return 81 } 114 115 // === Test 10: connected components on a synthetic mask with 2 blobs 116 let blob: *Image = nx_image_alloc(16, 16, 1) 117 // Blob 1: 3x3 at (2,2) 118 var by1: i64 = 2 119 while by1 < 5 { 120 var bx1: i64 = 2 121 while bx1 < 5 { 122 nx_image_set(blob, bx1, by1, 0, 255) 123 bx1 = bx1 + 1 124 } 125 by1 = by1 + 1 126 } 127 // Blob 2: 4x4 at (10, 10) 128 var by2: i64 = 10 129 while by2 < 14 { 130 var bx2: i64 = 10 131 while bx2 < 14 { 132 nx_image_set(blob, bx2, by2, 0, 255) 133 bx2 = bx2 + 1 134 } 135 by2 = by2 + 1 136 } 137 let cc: *CCResult = nx_feat_connected_components(blob) 138 if cc.n_components != 2 { return 90 } 139 140 // === Test 11: component stats 141 let stats: *i64 = (sys_mmap(2 * 7 * 8)) as *i64 142 nx_feat_component_stats(cc, stats) 143 // Blob 1 has 9 pixels, Blob 2 has 16 pixels. 144 let b1_count: i64 = stats[0] 145 let b2_count: i64 = stats[7] 146 var ok_count: i64 = 0 147 if b1_count == 9 { if b2_count == 16 { ok_count = 1 } } 148 if b1_count == 16 { if b2_count == 9 { ok_count = 1 } } 149 if ok_count != 1 { return 100 } 150 151 // === Test 12: Hu moments on the blob 152 let hu: *i64 = (sys_mmap(7 * 8)) as *i64 153 nx_feat_hu_moments(blob, hu) 154 // Hu1 should be positive (sum of central moments). 155 if hu[0] <= 0 { return 110 } 156 157 // === Test 13: Hamming descriptor matching 158 let d_match: i64 = nx_feat_match_brief(0xFF, 0xFF) 159 if d_match != 0 { return 120 } 160 let d_diff: i64 = nx_feat_match_brief(0xFF, 0x00) 161 if d_diff != 8 { return 121 } 162 163 // === Test 14: Harris response on a corner-rich image (checkerboard) 164 let cb: *Image = nx_image_alloc(16, 16, 1) 165 var cby: i64 = 0 166 while cby < 16 { 167 var cbx: i64 = 0 168 while cbx < 16 { 169 let blockx: i64 = cbx / 4 170 let blocky: i64 = cby / 4 171 let on: i64 = (blockx + blocky) - ((blockx + blocky) / 2) * 2 172 var v: i64 = 0 173 if on == 1 { v = 255 } 174 nx_image_set(cb, cbx, cby, 0, v) 175 cbx = cbx + 1 176 } 177 cby = cby + 1 178 } 179 let resp: *ImageS64 = nx_feat_harris_response(cb) 180 // Some pixels should have positive Harris response (corners). 181 var found_corner: i64 = 0 182 var ry: i64 = 1 183 while ry < 15 { 184 var rx: i64 = 1 185 while rx < 15 { 186 if nx_image_s64_get(resp, rx, ry) > 0 { found_corner = 1 } 187 rx = rx + 1 188 } 189 ry = ry + 1 190 } 191 if found_corner != 1 { return 130 } 192 193 return 0 194}