code wiki / (root) / nx_garment_extract_measurements_test.nx

nx_garment_extract_measurements_test.nx source

↩ module page · 151 lines · 6971 B

1// nx_garment_extract_measurements_test.nx -- smoke for product-photo extractor. 2 3import "nx_syscalls.nx" 4import "nx_tier.nx" 5import "nx_image.nx" 6import "nx_garment_fit_match.nx" 7import "nx_body_measurement_extract.nx" 8import "nx_garment_extract_measurements.nx" 9 10func _paint_band(sil: *Image, y0: nx_int, y1: nx_int, cx: nx_int, hw: nx_int) -> nx_int { 11 let w: nx_int = sil.width 12 var y: nx_int = y0 13 while y < y1 { 14 var x: nx_int = cx - hw 15 let xe: nx_int = cx + hw 16 if x < 0 { x = 0 } 17 while x < xe { 18 if x < w { 19 nx_image_set(sil, x, y, 0, 1) 20 } 21 x = x + 1 22 } 23 y = y + 1 24 } 25 return 0 26} 27 28func main() -> nx_int { 29 // === Test 1: synthetic dress silhouette, verify mm output === 30 // 31 // Dress in a 128x150 frame: 32 // top (shoulder) row 10, half-width 18 (full 36 px) 33 // bust row 25, half-width 20 (full 40 px) 34 // waist row 50, half-width 14 (full 28 px) 35 // hip row 75, half-width 22 (full 44 px) 36 // hem row 110 37 // sleeveless 38 // 39 // Reference: 50 px = 100 mm (so 1 px = 2 mm). 40 let sil: *Image = nx_image_alloc(128, 150, 1) 41 _paint_band(sil, 10, 25, 64, 18) // top of dress (shoulder seam) 42 _paint_band(sil, 25, 50, 64, 20) // bust 43 _paint_band(sil, 50, 75, 64, 14) // waist (narrowest) 44 _paint_band(sil, 75, 110, 64, 22) // hip + hem flare 45 46 let landmarks: *nx_int = (sys_mmap(NX_GME_LM_COUNT * NX_SIZEOF_NX_INT)) as *nx_int 47 landmarks[NX_GME_LM_TOP] = 10 48 landmarks[NX_GME_LM_BUST] = 30 // mid-bust band 49 landmarks[NX_GME_LM_WAIST] = 60 // mid-waist band 50 landmarks[NX_GME_LM_HIP] = 85 // mid-hip band 51 landmarks[NX_GME_LM_HEM] = 110 52 landmarks[NX_GME_LM_SLEEVE_END] = 0 // sleeveless 53 landmarks[NX_GME_LM_INSEAM_TOP] = 0 // not pants 54 55 let rep: *GarmentExtractReport = (sys_mmap(16 * NX_SIZEOF_NX_INT)) as *GarmentExtractReport 56 let rc: nx_int = nx_garment_extract_measurements( 57 sil, 50, 100, landmarks, NX_FIT_CUT_FIT_AND_FLARE, rep 58 ) 59 if rc != 0 { return 1 } 60 if rep.scale_px_per_mm_q10 != 512 { return 2 } 61 // Top width: row 10 in the 10-25 band, half-width 18 -> 36 px -> 72 mm 62 if rep.garment.shoulder_width_mm != 72 { return 3 } 63 // Bust: row 30 in 25-50 band, half-width 20 -> 40 px -> 80 mm 64 if rep.garment.bust_mm != 80 { return 4 } 65 // Waist: row 60 in 50-75 band, half-width 14 -> 28 px -> 56 mm 66 if rep.garment.waist_mm != 56 { return 5 } 67 // Hip: row 85 in 75-110 band, half-width 22 -> 44 px -> 88 mm 68 if rep.garment.hip_mm != 88 { return 6 } 69 // Length: (110 - 10) * 2 = 200 mm 70 if rep.garment.length_mm != 200 { return 7 } 71 // Sleeveless -> sleeve_length_mm == 0 72 if rep.garment.sleeve_length_mm != 0 { return 8 } 73 // Not pants -> inseam_mm == 0 74 if rep.garment.inseam_mm != 0 { return 9 } 75 // Cut propagated 76 if rep.garment.cut != NX_FIT_CUT_FIT_AND_FLARE { return 10 } 77 78 // === Test 2: fidelity HIGH on clean silhouette === 79 if rep.fidelity_band != NX_GME_FIDELITY_HIGH { return 20 } 80 81 // === Test 3: invalid scale (zero reference) -> error === 82 let rep2: *GarmentExtractReport = (sys_mmap(16 * NX_SIZEOF_NX_INT)) as *GarmentExtractReport 83 if nx_garment_extract_measurements(sil, 0, 100, landmarks, 84 NX_FIT_CUT_FIT_AND_FLARE, rep2) == 0 { return 30 } 85 if nx_garment_extract_measurements(sil, 50, 0, landmarks, 86 NX_FIT_CUT_FIT_AND_FLARE, rep2) == 0 { return 31 } 87 88 // === Test 4: sleeved dress -- sleeve_end_y populated === 89 let sil_sleeved: *Image = nx_image_alloc(128, 150, 1) 90 // Same dress shape with sleeves dropping to row 50 91 _paint_band(sil_sleeved, 10, 25, 64, 18) 92 _paint_band(sil_sleeved, 25, 50, 64, 20) 93 _paint_band(sil_sleeved, 50, 75, 64, 14) 94 _paint_band(sil_sleeved, 75, 110, 64, 22) 95 let lm_s: *nx_int = (sys_mmap(NX_GME_LM_COUNT * NX_SIZEOF_NX_INT)) as *nx_int 96 lm_s[NX_GME_LM_TOP] = 10 97 lm_s[NX_GME_LM_BUST] = 30 98 lm_s[NX_GME_LM_WAIST] = 60 99 lm_s[NX_GME_LM_HIP] = 85 100 lm_s[NX_GME_LM_HEM] = 110 101 lm_s[NX_GME_LM_SLEEVE_END] = 50 // drops to mid-torso (3/4 sleeve) 102 lm_s[NX_GME_LM_INSEAM_TOP] = 0 103 nx_garment_extract_measurements(sil_sleeved, 50, 100, lm_s, 104 NX_FIT_CUT_SHEATH, rep2) 105 // sleeve length: (50 - 10) * 2 = 80 mm 106 if rep2.garment.sleeve_length_mm != 80 { return 40 } 107 108 // === Test 5: pants -- inseam_top_y populated === 109 let sil_pants: *Image = nx_image_alloc(128, 150, 1) 110 _paint_band(sil_pants, 10, 30, 64, 18) // waistband 111 _paint_band(sil_pants, 30, 50, 64, 22) // hip 112 _paint_band(sil_pants, 50, 110, 50, 8) // left leg 113 _paint_band(sil_pants, 50, 110, 78, 8) // right leg 114 let lm_p: *nx_int = (sys_mmap(NX_GME_LM_COUNT * NX_SIZEOF_NX_INT)) as *nx_int 115 lm_p[NX_GME_LM_TOP] = 10 116 lm_p[NX_GME_LM_BUST] = 20 // not applicable for pants -- use waistband 117 lm_p[NX_GME_LM_WAIST] = 20 // waistband 118 lm_p[NX_GME_LM_HIP] = 40 // hip 119 lm_p[NX_GME_LM_HEM] = 110 120 lm_p[NX_GME_LM_SLEEVE_END] = 0 121 lm_p[NX_GME_LM_INSEAM_TOP] = 50 // crotch 122 nx_garment_extract_measurements(sil_pants, 50, 100, lm_p, 123 NX_FIT_CUT_SHIFT, rep2) 124 // inseam: (110 - 50) * 2 = 120 mm 125 if rep2.garment.inseam_mm != 120 { return 50 } 126 127 // === Test 6: extracted dims feed into nx_garment_fit_match === 128 // Use Test 1's garment vs a body that's a perfect match. 129 let body: *BodyDimensions = (sys_mmap(8 * NX_SIZEOF_NX_INT)) as *BodyDimensions 130 body.bust_mm = 80 // matches garment bust exactly 131 body.waist_mm = 56 // matches 132 body.hip_mm = 88 // matches 133 body.height_mm = 1650 134 body.shoulder_width_mm = 72 135 body.arm_length_mm = 600 136 body.inseam_mm = 0 137 body.archetype = NX_FIT_ARCHETYPE_AVERAGE 138 let fit_rep: *FitMatchReport = (sys_mmap(16 * NX_SIZEOF_NX_INT)) as *FitMatchReport 139 nx_garment_fit_match(rep.garment, body, fit_rep) 140 // All axes exact match -> PERFECT_TAILORED on a FIT_AND_FLARE for AVERAGE archetype 141 if fit_rep.verdict != NX_FIT_PERFECT_TAILORED { return 60 } 142 143 // === Test 7: sealed-enum validity === 144 if nx_garment_extract_fidelity_is_valid(NX_GME_FIDELITY_HIGH) != 1 { return 70 } 145 if nx_garment_extract_fidelity_is_valid(NX_GME_FIDELITY_UNUSABLE) != 1 { return 71 } 146 if nx_garment_extract_fidelity_is_valid(99) != 0 { return 72 } 147 if nx_garment_extract_landmark_is_valid(NX_GME_LM_HEM) != 1 { return 73 } 148 if nx_garment_extract_landmark_is_valid(99) != 0 { return 74 } 149 150 return 0 151}