1use crate::types::{ARParamLT, ARdouble, ARPixelFormat};
43use crate::icp::ICPHandleT;
44
45pub const AR2_TRACKING_6DOF: i32 = 1;
46pub const AR2_TRACKING_HOMOGRAPHY: i32 = 2;
47
48pub const AR2_SEARCH_FEATURE_MAX: usize = 500;
49pub const AR2_TRACKING_CANDIDATE_MAX: usize = 1000;
50pub const AR2_TRACKING_SURFACE_MAX: usize = 10;
51pub const AR2_THREAD_MAX: usize = 8; pub const AR2_BLUR_IMAGE_MAX: usize = 5;
53pub const AR2_TEMP_SCALE: i32 = 1;
54pub const AR2_TEMPLATE_NULL_PIXEL: u16 = 0xFFFF;
55
56#[derive(Debug, Clone, Copy, PartialEq)]
57pub struct AR2TemplateCandidate {
58 pub snum: i32,
59 pub level: i32,
60 pub num: i32,
61 pub flag: i32, pub sx: f32,
63 pub sy: f32,
64}
65
66impl Default for AR2TemplateCandidate {
67 fn default() -> Self {
68 Self {
69 snum: 0,
70 level: 0,
71 num: 0,
72 flag: -1,
73 sx: 0.0,
74 sy: 0.0,
75 }
76 }
77}
78
79#[derive(Debug, Default, Clone)]
80pub struct AR2Image {
81 pub img_bw_blur: Vec<Option<Vec<u8>>>,
82 pub xsize: i32,
83 pub ysize: i32,
84 pub dpi: f32,
85}
86
87#[derive(Debug, Default, Clone)]
88pub struct AR2ImageSet {
89 pub scale: Vec<AR2Image>,
90}
91
92#[derive(Debug, Default, Clone)]
93pub struct AR2FeatureCoord {
94 pub x: i32,
95 pub y: i32,
96 pub mx: f32,
97 pub my: f32,
98 pub max_sim: f32,
99}
100
101#[derive(Debug, Default, Clone)]
102pub struct AR2FeaturePoints {
103 pub coord: Vec<AR2FeatureCoord>,
104 pub scale: i32,
105 pub maxdpi: f32,
106 pub mindpi: f32,
107}
108
109#[derive(Debug, Default, Clone)]
110pub struct AR2FeatureSet {
111 pub list: Vec<AR2FeaturePoints>,
112}
113
114#[derive(Debug, Default, Clone)]
115pub struct AR2Template {
116 pub xts1: i32,
117 pub xts2: i32,
118 pub yts1: i32,
119 pub yts2: i32,
120 pub xsize: i32,
121 pub ysize: i32,
122 pub img1: Vec<u16>,
123 pub vlen: i32,
124 pub sum: i32,
125 pub valid_num: usize,
126}
127
128#[derive(Debug, Default, Clone)]
132pub struct AR2Surface {
133 pub image_set: Option<AR2ImageSet>,
134 pub feature_set: Option<AR2FeatureSet>,
135 pub trans: [[f32; 4]; 3],
136 pub itrans: [[f32; 4]; 3],
137}
138
139#[derive(Debug, Clone)]
140pub struct AR2SurfaceSet {
141 pub surface: Vec<AR2Surface>,
142 pub trans1: [[f32; 4]; 3],
143 pub trans2: [[f32; 4]; 3],
144 pub trans3: [[f32; 4]; 3],
145 pub cont_num: i32,
146 pub prev_feature: Vec<AR2TemplateCandidate>,
147}
148
149impl Default for AR2SurfaceSet {
150 fn default() -> Self {
151 Self {
152 surface: Vec::new(),
153 trans1: [[0.0; 4]; 3],
154 trans2: [[0.0; 4]; 3],
155 trans3: [[0.0; 4]; 3],
156 cont_num: 0,
157 prev_feature: vec![AR2TemplateCandidate::default(); AR2_SEARCH_FEATURE_MAX + 1],
158 }
159 }
160}
161
162pub struct AR2Handle {
163 pub tracking_mode: i32,
164 pub xsize: i32,
165 pub ysize: i32,
166 pub cparam_lt: *mut ARParamLT, pub icp_handle: *mut ICPHandleT,
168 pub pix_format: ARPixelFormat,
169
170 pub blur_method: i32,
171 pub blur_level: i32,
172 pub search_size: i32,
173 pub template_size1: i32,
174 pub template_size2: i32,
175 pub search_feature_num: i32,
176 pub sim_thresh: f32,
177 pub tracking_thresh: f32,
178
179 pub wtrans1: Vec<[[f32; 4]; 3]>,
180 pub wtrans2: Vec<[[f32; 4]; 3]>,
181 pub wtrans3: Vec<[[f32; 4]; 3]>,
182
183 pub pos: Vec<[f32; 2]>,
184 pub pos2d: Vec<[f32; 2]>,
185 pub pos3d: Vec<[f32; 3]>,
186
187 pub candidate: Vec<AR2TemplateCandidate>,
188 pub candidate2: Vec<AR2TemplateCandidate>,
189 pub used_feature: Vec<AR2TemplateCandidate>,
190
191 pub templ: Vec<AR2Template>, pub mf_image: Vec<u8>,
193
194 pub thread_num: i32,
195}
196
197impl AR2Handle {
198 pub fn new(xsize: i32, ysize: i32, pix_format: ARPixelFormat) -> Self {
199 Self {
200 tracking_mode: AR2_TRACKING_6DOF,
201 xsize,
202 ysize,
203 cparam_lt: std::ptr::null_mut(),
204 icp_handle: std::ptr::null_mut(),
205 pix_format,
206 blur_method: 0,
207 blur_level: 1,
208 search_size: 6,
209 template_size1: 16,
210 template_size2: 16,
211 search_feature_num: 10,
212 sim_thresh: 0.5,
213 tracking_thresh: 2.0,
214
215 wtrans1: vec![[[0.0; 4]; 3]; AR2_TRACKING_SURFACE_MAX],
216 wtrans2: vec![[[0.0; 4]; 3]; AR2_TRACKING_SURFACE_MAX],
217 wtrans3: vec![[[0.0; 4]; 3]; AR2_TRACKING_SURFACE_MAX],
218
219 pos: vec![[0.0; 2]; AR2_SEARCH_FEATURE_MAX + AR2_THREAD_MAX],
220 pos2d: vec![[0.0; 2]; AR2_SEARCH_FEATURE_MAX],
221 pos3d: vec![[0.0; 3]; AR2_SEARCH_FEATURE_MAX],
222
223 candidate: vec![AR2TemplateCandidate::default(); AR2_TRACKING_CANDIDATE_MAX + 1],
224 candidate2: vec![AR2TemplateCandidate::default(); AR2_TRACKING_CANDIDATE_MAX + 1],
225 used_feature: vec![AR2TemplateCandidate::default(); AR2_SEARCH_FEATURE_MAX],
226
227 templ: vec![AR2Template {
228 xts1: 16, xts2: 16, yts1: 16, yts2: 16,
229 xsize: 33, ysize: 33,
230 ..Default::default()
231 }; AR2_THREAD_MAX],
232 mf_image: vec![0; (xsize * ysize) as usize],
233
234 thread_num: 1,
235 }
236 }
237}
238
239pub fn marker_coord_to_screen_coord(
240 cparam_lt: Option<&ARParamLT>,
241 trans: &[[f32; 4]; 3],
242 mx: f32,
243 my: f32,
244) -> Result<(f32, f32), &'static str> {
245 let (ix, iy) = if let Some(lt) = cparam_lt {
246 let mut wtrans = [[0.0f32; 4]; 3];
247 crate::math::mat_mul_dff(<.param.mat, trans, &mut wtrans);
248
249 let hx = wtrans[0][0] * mx + wtrans[0][1] * my + wtrans[0][3];
250 let hy = wtrans[1][0] * mx + wtrans[1][1] * my + wtrans[1][3];
251 let h = wtrans[2][0] * mx + wtrans[2][1] * my + wtrans[2][3];
252 (hx / h, hy / h)
253 } else {
254 let hx = trans[0][0] * mx + trans[0][1] * my + trans[0][3];
255 let hy = trans[1][0] * mx + trans[1][1] * my + trans[1][3];
256 let h = trans[2][0] * mx + trans[2][1] * my + trans[2][3];
257 return Ok((hx / h, hy / h));
258 };
259
260 if let Some(lt) = cparam_lt {
261 let (sx, sy) = lt.param_ltf.ideal2observ(ix, iy)?;
262 Ok((sx, sy))
263 } else {
264 Ok((ix, iy))
265 }
266}
267
268pub fn marker_coord_to_screen_coord2(
269 cparam_lt: Option<&ARParamLT>,
270 trans: &[[f32; 4]; 3],
271 mx: f32,
272 my: f32,
273) -> Result<(f32, f32), &'static str> {
274 let (sx, sy) = marker_coord_to_screen_coord(cparam_lt, trans, mx, my)?;
275
276 if let Some(lt) = cparam_lt {
277 let (ix1, iy1) = lt.param_ltf.observ2ideal(sx, sy)?;
278 let (ix, iy) = {
283 let mut wtrans = [[0.0f32; 4]; 3];
284 crate::math::mat_mul_dff(<.param.mat, trans, &mut wtrans);
285 let hx = wtrans[0][0] * mx + wtrans[0][1] * my + wtrans[0][3];
286 let hy = wtrans[1][0] * mx + wtrans[1][1] * my + wtrans[1][3];
287 let h = wtrans[2][0] * mx + wtrans[2][1] * my + wtrans[2][3];
288 (hx / h, hy / h)
289 };
290 if (ix - ix1).powi(2) + (iy - iy1).powi(2) > 1.0 {
291 return Err("Reprojection error too high");
292 }
293 }
294
295 Ok((sx, sy))
296}
297
298pub fn ar2_screen_coord_2_marker_coord(
299 cparam_lt: Option<&ARParamLT>,
300 trans: &[[f32; 4]; 3],
301 sx: f32,
302 sy: f32,
303) -> Result<(f32, f32), &'static str> {
304 if let Some(lt) = cparam_lt {
305 let (ix, iy) = lt.param_ltf.observ2ideal(sx, sy)?;
306 let mut wtrans = [[0.0f32; 4]; 3];
307 crate::math::mat_mul_dff(<.param.mat, trans, &mut wtrans);
308
309 let c11 = wtrans[2][0] * ix - wtrans[0][0];
310 let c12 = wtrans[2][1] * ix - wtrans[0][1];
311 let c21 = wtrans[2][0] * iy - wtrans[1][0];
312 let c22 = wtrans[2][1] * iy - wtrans[1][1];
313 let b1 = wtrans[0][3] - wtrans[2][3] * ix;
314 let b2 = wtrans[1][3] - wtrans[2][3] * iy;
315
316 let m = c11 * c22 - c12 * c21;
317 if m.abs() < 1e-10 { return Err("Singular matrix in coord conversion"); }
318
319 let mx = (b1 * c22 - b2 * c12) / m;
320 let my = (c11 * b2 - c21 * b1) / m;
321 Ok((mx, my))
322 } else {
323 let c11 = trans[2][0] * sx - trans[0][0];
324 let c12 = trans[2][1] * sx - trans[0][1];
325 let c21 = trans[2][0] * sy - trans[1][0];
326 let c22 = trans[2][1] * sy - trans[1][1];
327 let b1 = trans[0][3] - trans[2][3] * sx;
328 let b2 = trans[1][3] - trans[2][3] * sy;
329
330 let m = c11 * c22 - c12 * c21;
331 if m.abs() < 1e-10 { return Err("Singular matrix in coord conversion"); }
332
333 let mx = (b1 * c22 - b2 * c12) / m;
334 let my = (c11 * b2 - c21 * b1) / m;
335 Ok((mx, my))
336 }
337}
338
339pub fn ar2_marker_coord_2_image_coord(
340 _xsize: i32,
341 ysize: i32,
342 dpi: f32,
343 mx: f32,
344 my: f32,
345) -> (f32, f32) {
346 let iix = mx * dpi / 25.4;
347 let iiy = (ysize as f32) - my * dpi / 25.4;
348 (iix, iiy)
349}
350
351pub fn ar2_get_image_value(
352 cparam_lt: Option<&ARParamLT>,
353 trans: &[[f32; 4]; 3],
354 image: &AR2Image,
355 sx: f32,
356 sy: f32,
357 blur_level: i32,
358) -> Result<u8, &'static str> {
359 let (mx, my) = ar2_screen_coord_2_marker_coord(cparam_lt, trans, sx, sy)?;
360 let (iix, iiy) = ar2_marker_coord_2_image_coord(image.xsize, image.ysize, image.dpi, mx, my);
361
362 let ix = (iix + 0.5) as i32;
363 let iy = (iiy + 0.5) as i32;
364
365 if ix < 0 || ix >= image.xsize || iy < 0 || iy >= image.ysize {
366 return Err("Coord out of image bounds");
367 }
368
369 if let Some(blur_vec) = &image.img_bw_blur[blur_level as usize] {
370 Ok(blur_vec[(iy * image.xsize + ix) as usize])
371 } else {
372 Err("Blur level not available")
373 }
374}
375
376pub fn ar2_set_template_sub(
377 cparam_lt: Option<&ARParamLT>,
378 trans: &[[f32; 4]; 3],
379 image_set: &AR2ImageSet,
380 feature_points: &AR2FeaturePoints,
381 num: usize,
382 blur_level: i32,
383 templ: &mut AR2Template,
384) -> Result<(), &'static str> {
385 let mx = feature_points.coord[num].mx;
386 let my = feature_points.coord[num].my;
387
388 let (sx, sy) = marker_coord_to_screen_coord(cparam_lt, trans, mx, my)?;
389 let ix = (sx + 0.5) as i32;
390 let iy = (sy + 0.5) as i32;
391
392 let mut sum = 0;
393 let mut sum2 = 0;
394 let mut k = 0;
395
396 templ.img1.clear();
397
398 let image = &image_set.scale[feature_points.scale as usize];
399
400 for j in -templ.yts1..=templ.yts2 {
401 let iy2 = iy + j * AR2_TEMP_SCALE;
402 for i in -templ.xts1..=templ.xts2 {
403 let ix2 = ix + i * AR2_TEMP_SCALE;
404
405 let res = if let Some(lt) = cparam_lt {
406 match lt.param_ltf.observ2ideal(ix2 as f32, iy2 as f32) {
407 Ok((isx, isy)) => ar2_get_image_value(cparam_lt, trans, image, isx, isy, blur_level),
408 Err(_) => Err("Ideal error"),
409 }
410 } else {
411 ar2_get_image_value(cparam_lt, trans, image, ix2 as f32, iy2 as f32, blur_level)
412 };
413
414 match res {
415 Ok(pixel) => {
416 templ.img1.push(pixel as u16);
417 sum += pixel as i32;
418 sum2 += (pixel as i32) * (pixel as i32);
419 k += 1;
420 }
421 Err(_) => {
422 templ.img1.push(AR2_TEMPLATE_NULL_PIXEL);
423 }
424 }
425 }
426 }
427
428 if k == 0 { return Err("No valid pixels in template"); }
429
430 let vlen = (sum2 - sum * sum / (k as i32)) as f32;
431 templ.vlen = vlen.sqrt() as i32;
432 templ.sum = sum;
433 templ.valid_num = k;
434
435 Ok(())
436}
437
438pub fn get_resolution(
439 cparam_lt: Option<&ARParamLT>,
440 trans: &[[f32; 4]; 3],
441 pos: [f32; 2],
442) -> Result<[f32; 2], &'static str> {
443 let cparam = cparam_lt.map(|lt| <.param);
444 get_resolution2(cparam, trans, pos)
445}
446
447pub fn get_resolution2(
448 cparam: Option<&crate::types::ARParam>,
449 trans: &[[f32; 4]; 3],
450 pos: [f32; 2],
451) -> Result<[f32; 2], &'static str> {
452 let mut mat = [[0.0f32; 4]; 3];
453 let (x0, y0, x1, y1, x2, y2);
454
455 if let Some(cp) = cparam {
456 crate::math::mat_mul_dff(&cp.mat, trans, &mut mat);
457
458 let project = |px, py| {
459 let hx = mat[0][0] * px + mat[0][1] * py + mat[0][3];
460 let hy = mat[1][0] * px + mat[1][1] * py + mat[1][3];
461 let h = mat[2][0] * px + mat[2][1] * py + mat[2][3];
462 (hx / h, hy / h)
463 };
464
465 let (p0x, p0y) = project(pos[0], pos[1]);
466 x0 = p0x; y0 = p0y;
467 let (p1x, p1y) = project(pos[0] + 10.0, pos[1]);
468 x1 = p1x; y1 = p1y;
469 let (p2x, p2y) = project(pos[0], pos[1] + 10.0);
470 x2 = p2x; y2 = p2y;
471 } else {
472 let project = |px, py| {
473 let hx = trans[0][0] * px + trans[0][1] * py + trans[0][3];
474 let hy = trans[1][0] * px + trans[1][1] * py + trans[1][3];
475 let h = trans[2][0] * px + trans[2][1] * py + trans[2][3];
476 (hx / h, hy / h)
477 };
478
479 let (p0x, p0y) = project(pos[0], pos[1]);
480 x0 = p0x; y0 = p0y;
481 let (p1x, p1y) = project(pos[0] + 10.0, pos[1]);
482 x1 = p1x; y1 = p1y;
483 let (p2x, p2y) = project(pos[0], pos[1] + 10.0);
484 x2 = p2x; y2 = p2y;
485 }
486
487 let d1 = (x1 - x0).powi(2) + (y1 - y0).powi(2);
488 let d2 = (x2 - x0).powi(2) + (y2 - y0).powi(2);
489
490 let mut dpi = [0.0; 2];
491 if d1 < d2 {
492 dpi[0] = d2.sqrt() * 2.54;
493 dpi[1] = d1.sqrt() * 2.54;
494 } else {
495 dpi[0] = d1.sqrt() * 2.54;
496 dpi[1] = d2.sqrt() * 2.54;
497 }
498
499 Ok(dpi)
500}
501
502pub fn extract_visible_features(
503 cparam_lt: &ARParamLT,
504 wtrans1: &[[[f32; 4]; 3]],
505 surface_set: &AR2SurfaceSet,
506 candidate: &mut [AR2TemplateCandidate],
507 candidate2: &mut [AR2TemplateCandidate],
508) -> Result<(), &'static str> {
509 let xsize = cparam_lt.param.xsize;
510 let ysize = cparam_lt.param.ysize;
511
512 let mut l = 0;
513 let mut l2 = 0;
514
515 for i in 0..surface_set.surface.len() {
516 let surface = &surface_set.surface[i];
517 let feature_set = match &surface.feature_set {
518 Some(fs) => fs,
519 None => continue,
520 };
521
522 let trans2 = &wtrans1[i];
523
524 for j in 0..feature_set.list.len() {
525 let feature_points = &feature_set.list[j];
526 for k in 0..feature_points.coord.len() {
527 let coord = &feature_points.coord[k];
528
529 let (sx, sy) = match marker_coord_to_screen_coord2(
530 Some(cparam_lt),
531 trans2,
532 coord.mx,
533 coord.my,
534 ) {
535 Ok(res) => res,
536 Err(_) => continue,
537 };
538
539 if sx < 0.0 || sx >= xsize as f32 || sy < 0.0 || sy >= ysize as f32 {
540 continue;
541 }
542
543 let vdir0 = trans2[0][0] * coord.mx + trans2[0][1] * coord.my + trans2[0][3];
545 let vdir1 = trans2[1][0] * coord.mx + trans2[1][1] * coord.my + trans2[1][3];
546 let vdir2 = trans2[2][0] * coord.mx + trans2[2][1] * coord.my + trans2[2][3];
547 let vlen = (vdir0 * vdir0 + vdir1 * vdir1 + vdir2 * vdir2).sqrt();
548 let vd0 = vdir0 / vlen;
549 let vd1 = vdir1 / vlen;
550 let vd2 = vdir2 / vlen;
551
552 if vd0 * trans2[0][2] + vd1 * trans2[1][2] + vd2 * trans2[2][2] > -0.1 {
553 continue;
554 }
555
556 let w = get_resolution(Some(cparam_lt), trans2, [coord.mx, coord.my])?;
557
558 if w[1] <= feature_points.maxdpi && w[1] >= feature_points.mindpi {
559 if l >= AR2_TRACKING_CANDIDATE_MAX {
560 candidate[l].flag = -1;
561 return Err("Feature candidates overflow");
562 }
563 candidate[l] = AR2TemplateCandidate {
564 snum: i as i32,
565 level: j as i32,
566 num: k as i32,
567 sx,
568 sy,
569 flag: 0,
570 };
571 l += 1;
572 } else if w[1] <= feature_points.maxdpi * 2.0 && w[1] >= feature_points.mindpi / 2.0 {
573 if l2 < AR2_TRACKING_CANDIDATE_MAX {
574 candidate2[l2] = AR2TemplateCandidate {
575 snum: i as i32,
576 level: j as i32,
577 num: k as i32,
578 sx,
579 sy,
580 flag: 0,
581 };
582 l2 += 1;
583 }
584 }
585 }
586 }
587 }
588 candidate[l].flag = -1;
589 candidate2[l2].flag = -1;
590
591 Ok(())
592}
593
594pub fn extract_visible_features_homography(
595 xsize: i32,
596 ysize: i32,
597 wtrans1: &[[[f32; 4]; 3]],
598 surface_set: &AR2SurfaceSet,
599 candidate: &mut [AR2TemplateCandidate],
600 candidate2: &mut [AR2TemplateCandidate],
601) -> Result<(), &'static str> {
602 let mut l = 0;
603 let mut l2 = 0;
604
605 for i in 0..surface_set.surface.len() {
606 let surface = &surface_set.surface[i];
607 let feature_set = match &surface.feature_set {
608 Some(fs) => fs,
609 None => continue,
610 };
611
612 let trans2 = &wtrans1[i];
613
614 for j in 0..feature_set.list.len() {
615 let feature_points = &feature_set.list[j];
616 for k in 0..feature_points.coord.len() {
617 let coord = &feature_points.coord[k];
618
619 let (sx, sy) = match marker_coord_to_screen_coord2(
620 None,
621 trans2,
622 coord.mx,
623 coord.my,
624 ) {
625 Ok(res) => res,
626 Err(_) => continue,
627 };
628
629 if sx < 0.0 || sx >= xsize as f32 || sy < 0.0 || sy >= ysize as f32 {
630 continue;
631 }
632
633 let w = get_resolution(None, trans2, [coord.mx, coord.my])?;
634
635 if w[1] <= feature_points.maxdpi && w[1] >= feature_points.mindpi {
636 if l >= AR2_TRACKING_CANDIDATE_MAX {
637 candidate[l].flag = -1;
638 return Err("Feature candidates overflow");
639 }
640 candidate[l] = AR2TemplateCandidate {
641 snum: i as i32,
642 level: j as i32,
643 num: k as i32,
644 sx,
645 sy,
646 flag: 0,
647 };
648 l += 1;
649 } else if w[1] <= feature_points.maxdpi * 2.0 && w[1] >= feature_points.mindpi / 2.0 {
650 if l2 < AR2_TRACKING_CANDIDATE_MAX {
651 candidate2[l2] = AR2TemplateCandidate {
652 snum: i as i32,
653 level: j as i32,
654 num: k as i32,
655 sx,
656 sy,
657 flag: 0,
658 };
659 l2 += 1;
660 }
661 }
662 }
663 }
664 }
665 candidate[l].flag = -1;
666 candidate2[l2].flag = -1;
667
668 Ok(())
669}
670
671pub fn ar2_select_template(
672 candidate: &mut [AR2TemplateCandidate],
673 prev_feature: &mut [AR2TemplateCandidate],
674 num: i32,
675 pos: &mut [[f32; 2]; 4],
676 xsize: i32,
677 ysize: i32,
678) -> i32 {
679 if num < 0 {
680 return -1;
681 }
682
683 if num == 0 {
684 let mut dmax = 0.0;
685 let mut j = -1;
686 for (i, cand) in candidate.iter().enumerate() {
687 if cand.flag == -1 { break; }
688 if cand.flag != 0 { continue; }
689 if cand.sx < (xsize / 8) as f32 || cand.sx > (xsize * 7 / 8) as f32
690 || cand.sy < (ysize / 8) as f32 || cand.sy > (ysize * 7 / 8) as f32 {
691 continue;
692 }
693
694 let d = (cand.sx - (xsize / 2) as f32).powi(2) + (cand.sy - (ysize / 2) as f32).powi(2);
695 if d > dmax {
696 dmax = d;
697 j = i as i32;
698 }
699 }
700
701 if j != -1 {
702 candidate[j as usize].flag = 1;
703 }
704 return j;
705 } else if num == 1 {
706 let mut dmax = 0.0;
707 let mut j = -1;
708 for (i, cand) in candidate.iter().enumerate() {
709 if cand.flag == -1 { break; }
710 if cand.flag != 0 { continue; }
711 if cand.sx < (xsize / 8) as f32 || cand.sx > (xsize * 7 / 8) as f32
712 || cand.sy < (ysize / 8) as f32 || cand.sy > (ysize * 7 / 8) as f32 {
713 continue;
714 }
715
716 let d = (cand.sx - pos[0][0]).powi(2) + (cand.sy - pos[0][1]).powi(2);
717 if d > dmax {
718 dmax = d;
719 j = i as i32;
720 }
721 }
722
723 if j != -1 {
724 candidate[j as usize].flag = 1;
725 }
726 return j;
727 } else if num == 2 {
728 let mut dmax = 0.0;
729 let mut j = -1;
730 for (i, cand) in candidate.iter().enumerate() {
731 if cand.flag == -1 { break; }
732 if cand.flag != 0 { continue; }
733 if cand.sx < (xsize / 8) as f32 || cand.sx > (xsize * 7 / 8) as f32
734 || cand.sy < (ysize / 8) as f32 || cand.sy > (ysize * 7 / 8) as f32 {
735 continue;
736 }
737
738 let d = (cand.sx - pos[0][0]) * (pos[1][1] - pos[0][1])
739 - (cand.sy - pos[0][1]) * (pos[1][0] - pos[0][0]);
740 let d_sq = d * d;
741 if d_sq > dmax {
742 dmax = d_sq;
743 j = i as i32;
744 }
745 }
746
747 if j != -1 {
748 candidate[j as usize].flag = 1;
749 }
750 return j;
751 } else if num == 3 {
752 let (mut p2sinf, mut p2cosf) = (0.0, 0.0);
753 let (mut p3sinf, mut p3cosf) = (0.0, 0.0);
754 let (mut p4sinf, mut p4cosf) = (0.0, 0.0);
755
756 if get_vector_angle(pos[0], pos[1], &mut p2sinf, &mut p2cosf).is_err() { return -1; }
757 if get_vector_angle(pos[0], pos[2], &mut p3sinf, &mut p3cosf).is_err() { return -1; }
758
759 let mut j = -1;
760 let mut smax = 0.0;
761 for (i, cand) in candidate.iter().enumerate() {
762 if cand.flag == -1 { break; }
763 if cand.flag != 0 { continue; }
764 if cand.sx < (xsize / 8) as f32 || cand.sx > (xsize * 7 / 8) as f32
765 || cand.sy < (ysize / 8) as f32 || cand.sy > (ysize * 7 / 8) as f32 {
766 continue;
767 }
768
769 pos[3][0] = cand.sx;
770 pos[3][1] = cand.sy;
771 if get_vector_angle(pos[0], pos[3], &mut p4sinf, &mut p4cosf).is_err() { continue; }
772
773 let q1: usize;
774 let r1: usize;
775 let r2: usize;
776
777 if (p3sinf * p2cosf - p3cosf * p2sinf >= 0.0) && (p4sinf * p2cosf - p4cosf * p2sinf >= 0.0) {
778 if p4sinf * p3cosf - p4cosf * p3sinf >= 0.0 {
779 q1 = 1; r1 = 2; r2 = 3;
780 } else {
781 q1 = 1; r1 = 3; r2 = 2;
782 }
783 } else if (p4sinf * p3cosf - p4cosf * p3sinf >= 0.0) && (p2sinf * p3cosf - p2cosf * p3sinf >= 0.0) {
784 if p4sinf * p2cosf - p4cosf * p2sinf >= 0.0 {
785 q1 = 2; r1 = 1; r2 = 3;
786 } else {
787 q1 = 2; r1 = 3; r2 = 1;
788 }
789 } else if (p2sinf * p4cosf - p2cosf * p4sinf >= 0.0) && (p3sinf * p4cosf - p3cosf * p4sinf >= 0.0) {
790 if p3sinf * p2cosf - p3cosf * p2sinf >= 0.0 {
791 q1 = 3; r1 = 1; r2 = 2;
792 } else {
793 q1 = 3; r1 = 2; r2 = 1;
794 }
795 } else {
796 continue;
797 }
798
799 let s = get_region_area(pos, q1, r1, r2);
800 if s > smax {
801 smax = s;
802 j = i as i32;
803 }
804 }
805
806 if j != -1 {
807 candidate[j as usize].flag = 1;
808 }
809 return j;
810 } else {
811 for p_cand in prev_feature.iter_mut() {
813 if p_cand.flag == -1 { break; }
814 if p_cand.flag != 0 { continue; }
815 p_cand.flag = 1;
816
817 for (i, cand) in candidate.iter_mut().enumerate() {
818 if cand.flag == -1 { break; }
819 if cand.flag == 0 && p_cand.snum == cand.snum && p_cand.level == cand.level && p_cand.num == cand.num {
820 cand.flag = 1;
821 return i as i32;
822 }
823 }
824 }
825
826 let mut available = Vec::new();
828 for (i, cand) in candidate.iter().enumerate() {
829 if cand.flag == -1 { break; }
830 if cand.flag == 0 {
831 available.push(i);
832 }
833 }
834
835 if available.is_empty() { return -1; }
836
837 use rand::Rng;
838 let mut rng = rand::thread_rng();
839 let idx = available[rng.gen_range(0..available.len())];
840 candidate[idx].flag = 1;
841 idx as i32
842 }
843}
844
845pub fn get_vector_angle(p1: [f32; 2], p2: [f32; 2], psinf: &mut f32, pcosf: &mut f32) -> Result<(), &'static str> {
846 let l = ((p2[0] - p1[0]).powi(2) + (p2[1] - p1[1]).powi(2)).sqrt();
847 if l == 0.0 { return Err("Zero length vector"); }
848 *psinf = (p2[1] - p1[1]) / l;
849 *pcosf = (p2[0] - p1[0]) / l;
850 Ok(())
851}
852
853pub fn get_region_area(pos: &[[f32; 2]; 4], q1: usize, r1: usize, r2: usize) -> f32 {
854 get_triangle_area(pos[0], pos[q1], pos[r1]) + get_triangle_area(pos[0], pos[r1], pos[r2])
855}
856
857pub fn get_triangle_area(p1: [f32; 2], p2: [f32; 2], p3: [f32; 2]) -> f32 {
858 let x1 = p2[0] - p1[0];
859 let y1 = p2[1] - p1[1];
860 let x2 = p3[0] - p1[0];
861 let y2 = p3[1] - p1[1];
862 ((x1 * y2 - x2 * y1) / 2.0).abs()
863}
864
865pub fn ar2_get_search_point(
866 cparam_lt: Option<&ARParamLT>,
867 trans1: Option<&[[f32; 4]; 3]>,
868 trans2: Option<&[[f32; 4]; 3]>,
869 trans3: Option<&[[f32; 4]; 3]>,
870 feature: &AR2FeatureCoord,
871 search: &mut [[i32; 2]; 3],
872) {
873 let mx = feature.mx;
874 let my = feature.my;
875
876 let ox1 = if let Some(t1) = trans1 {
877 match marker_coord_to_screen_coord(cparam_lt, t1, mx, my) {
878 Ok((x, y)) => {
879 search[0][0] = x as i32;
880 search[0][1] = y as i32;
881 Some((x, y))
882 }
883 Err(_) => None,
884 }
885 } else {
886 None
887 };
888
889 if ox1.is_none() {
890 search[0][0] = -1; search[0][1] = -1;
891 search[1][0] = -1; search[1][1] = -1;
892 search[2][0] = -1; search[2][1] = -1;
893 return;
894 }
895 let (ox1x, ox1y) = ox1.unwrap();
896
897 let ox2 = if let Some(t2) = trans2 {
898 match marker_coord_to_screen_coord(cparam_lt, t2, mx, my) {
899 Ok((x, y)) => {
900 search[1][0] = (2.0 * ox1x - x) as i32;
901 search[1][1] = (2.0 * ox1y - y) as i32;
902 Some((x, y))
903 }
904 Err(_) => None,
905 }
906 } else {
907 None
908 };
909
910 if ox2.is_none() {
911 search[1][0] = -1; search[1][1] = -1;
912 search[2][0] = -1; search[2][1] = -1;
913 return;
914 }
915 let (ox2x, ox2y) = ox2.unwrap();
916
917 if let Some(t3) = trans3 {
918 match marker_coord_to_screen_coord(cparam_lt, t3, mx, my) {
919 Ok((x, y)) => {
920 search[2][0] = (3.0 * ox1x - 3.0 * ox2x + x) as i32;
921 search[2][1] = (3.0 * ox1y - 3.0 * ox2y + y) as i32;
922 }
923 Err(_) => {
924 search[2][0] = -1;
925 search[2][1] = -1;
926 }
927 }
928 } else {
929 search[2][0] = -1;
930 search[2][1] = -1;
931 }
932}
933
934pub struct AR2Tracking2DResult {
935 pub sim: f32,
936 pub pos2d: [f32; 2],
937 pub pos3d: [f32; 3],
938}
939
940pub fn ar2_tracking_2d_sub(
941 cparam_lt: Option<&ARParamLT>,
942 pix_format: ARPixelFormat,
943 xsize: i32,
944 ysize: i32,
945 blur_level: i32,
946 search_size: i32,
947 wtrans1: &[[f32; 4]; 3],
948 wtrans2: Option<&[[f32; 4]; 3]>,
949 wtrans3: Option<&[[f32; 4]; 3]>,
950 surface_set: &AR2SurfaceSet,
951 candidate: &AR2TemplateCandidate,
952 data_ptr: &[u8],
953 mf_image: &mut [u8],
954 templ: &mut AR2Template,
955) -> Result<AR2Tracking2DResult, &'static str> {
956 let snum = candidate.snum as usize;
957 let level = candidate.level as usize;
958 let fnum = candidate.num as usize;
959
960 let surface = &surface_set.surface[snum];
961 let feature_set = surface.feature_set.as_ref().ok_or("No feature set")?;
962 let feature_points = &feature_set.list[level];
963
964 ar2_set_template_sub(
965 cparam_lt,
966 wtrans1,
967 &surface.image_set.as_ref().ok_or("No image set")?.clone(),
968 feature_points,
969 fnum,
970 blur_level,
971 templ,
972 )?;
973
974 if ((templ.vlen * templ.vlen) as f32)
975 < ((templ.xsize * templ.ysize) as f32 * 2.0 * 2.0) { return Err("Low variance template");
977 }
978
979 let mut search = [[0i32; 2]; 3];
980 let feature_coord = &feature_points.coord[fnum];
981
982 if surface_set.cont_num == 1 {
983 ar2_get_search_point(cparam_lt, Some(wtrans1), None, None, feature_coord, &mut search);
984 } else if surface_set.cont_num == 2 {
985 ar2_get_search_point(cparam_lt, Some(wtrans1), wtrans2, None, feature_coord, &mut search);
986 } else {
987 ar2_get_search_point(cparam_lt, Some(wtrans1), wtrans2, wtrans3, feature_coord, &mut search);
988 }
989
990 let mut bx = 0;
991 let mut by = 0;
992 let mut sim = 0.0;
993
994 ar2_get_best_matching(
995 data_ptr,
996 mf_image,
997 xsize,
998 ysize,
999 pix_format,
1000 templ,
1001 search_size,
1002 search_size,
1003 search,
1004 &mut bx,
1005 &mut by,
1006 &mut sim,
1007 )?;
1008
1009 let mut result = AR2Tracking2DResult {
1010 sim,
1011 pos2d: [bx as f32, by as f32],
1012 pos3d: [0.0; 3],
1013 };
1014
1015 result.pos3d[0] = surface.trans[0][0] * feature_coord.mx + surface.trans[0][1] * feature_coord.my + surface.trans[0][3];
1016 result.pos3d[1] = surface.trans[1][0] * feature_coord.mx + surface.trans[1][1] * feature_coord.my + surface.trans[1][3];
1017 result.pos3d[2] = surface.trans[2][0] * feature_coord.mx + surface.trans[2][1] * feature_coord.my + surface.trans[2][3];
1018
1019 Ok(result)
1020}
1021
1022pub fn ar2_tracking(
1023 handle: &mut AR2Handle,
1024 surface_set: &mut AR2SurfaceSet,
1025 data_ptr: &[u8],
1026 trans: &mut [[f32; 4]; 3],
1027 err: &mut f32,
1028) -> Result<(), i32> {
1029 if surface_set.cont_num <= 0 {
1030 return Err(-2);
1031 }
1032
1033 *err = 0.0;
1034
1035 for i in 0..surface_set.surface.len() {
1036 crate::math::mat_mul_fff(&surface_set.trans1, &surface_set.surface[i].trans, &mut handle.wtrans1[i]);
1037 if surface_set.cont_num > 1 {
1038 crate::math::mat_mul_fff(&surface_set.trans2, &surface_set.surface[i].trans, &mut handle.wtrans2[i]);
1039 }
1040 if surface_set.cont_num > 2 {
1041 crate::math::mat_mul_fff(&surface_set.trans3, &surface_set.surface[i].trans, &mut handle.wtrans3[i]);
1042 }
1043 }
1044
1045 let cparam_lt = unsafe { handle.cparam_lt.as_ref() }.ok_or(-1)?;
1046
1047 if handle.tracking_mode == AR2_TRACKING_6DOF {
1048 extract_visible_features(cparam_lt, &handle.wtrans1, surface_set, &mut handle.candidate, &mut handle.candidate2).map_err(|_| -1)?;
1049 } else {
1050 extract_visible_features_homography(handle.xsize, handle.ysize, &handle.wtrans1, surface_set, &mut handle.candidate, &mut handle.candidate2).map_err(|_| -1)?;
1051 }
1052
1053 let mut candidate_ptr_idx = 0; let mut i = 0;
1055 let mut num = 0;
1056
1057 while i < handle.search_feature_num {
1059 let mut pos = [[0.0f32; 2]; 4];
1060 let mut k = ar2_select_template(
1061 if candidate_ptr_idx == 0 { &mut handle.candidate } else { &mut handle.candidate2 },
1062 &mut surface_set.prev_feature,
1063 num,
1064 &mut pos,
1065 handle.xsize,
1066 handle.ysize,
1067 );
1068
1069 if k < 0 {
1070 if candidate_ptr_idx == 0 {
1071 candidate_ptr_idx = 1;
1072 k = ar2_select_template(&mut handle.candidate2, &mut surface_set.prev_feature, num, &mut pos, handle.xsize, handle.ysize);
1073 if k < 0 { break; }
1074 } else {
1075 break;
1076 }
1077 }
1078
1079 let cand = if candidate_ptr_idx == 0 { &handle.candidate[k as usize] } else { &handle.candidate2[k as usize] };
1080
1081 let cparam_lt = unsafe { handle.cparam_lt.as_ref() };
1082 let snum = cand.snum as usize;
1083
1084 match ar2_tracking_2d_sub(
1085 cparam_lt,
1086 handle.pix_format,
1087 handle.xsize,
1088 handle.ysize,
1089 handle.blur_level,
1090 handle.search_size,
1091 &handle.wtrans1[snum],
1092 Some(&handle.wtrans2[snum]),
1093 Some(&handle.wtrans3[snum]),
1094 surface_set,
1095 cand,
1096 data_ptr,
1097 &mut handle.mf_image,
1098 &mut handle.templ[0], ) {
1100 Ok(res) => {
1101 if res.sim > handle.sim_thresh {
1102 if handle.tracking_mode == AR2_TRACKING_6DOF {
1103 let (ix, iy) = cparam_lt.unwrap().param_ltf.observ2ideal(res.pos2d[0], res.pos2d[1]).map_err(|_| -1)?;
1104 handle.pos2d[num as usize][0] = ix;
1105 handle.pos2d[num as usize][1] = iy;
1106 } else {
1107 handle.pos2d[num as usize][0] = res.pos2d[0];
1108 handle.pos2d[num as usize][1] = res.pos2d[1];
1109 }
1110 handle.pos3d[num as usize][0] = res.pos3d[0];
1111 handle.pos3d[num as usize][1] = res.pos3d[1];
1112 handle.pos3d[num as usize][2] = res.pos3d[2];
1113
1114 handle.used_feature[num as usize].snum = cand.snum;
1115 handle.used_feature[num as usize].level = cand.level;
1116 handle.used_feature[num as usize].num = cand.num;
1117 handle.used_feature[num as usize].flag = 0;
1118
1119 num += 1;
1120 }
1121 }
1122 Err(_) => {}
1123 }
1124 i += 1;
1125 }
1126
1127 for idx in 0..num {
1128 surface_set.prev_feature[idx as usize] = handle.used_feature[idx as usize];
1129 }
1130 surface_set.prev_feature[num as usize].flag = -1;
1131
1132 if num < 3 {
1133 surface_set.cont_num = 0;
1134 return Err(-3);
1135 }
1136
1137 if handle.tracking_mode == AR2_TRACKING_6DOF {
1138 unsafe {
1139 let icp_handle = handle.icp_handle.as_mut().ok_or(-1)?;
1140 *err = ar2_get_trans_mat(icp_handle, surface_set.trans1, &handle.pos2d, &handle.pos3d, num as usize, trans, false);
1141 if *err > handle.tracking_thresh {
1142 crate::icp::icp_set_inlier_probability(icp_handle, 0.8);
1143 *err = ar2_get_trans_mat(icp_handle, *trans, &handle.pos2d, &handle.pos3d, num as usize, trans, true);
1144 if *err > handle.tracking_thresh {
1145 crate::icp::icp_set_inlier_probability(icp_handle, 0.0);
1146 *err = ar2_get_trans_mat(icp_handle, *trans, &handle.pos2d, &handle.pos3d, num as usize, trans, true);
1147 if *err > handle.tracking_thresh {
1148 surface_set.cont_num = 0;
1149 return Err(-4);
1150 }
1151 }
1152 }
1153 }
1154 } else {
1155 return Err(-5); }
1159
1160 surface_set.cont_num += 1;
1161 surface_set.trans3 = surface_set.trans2;
1162 surface_set.trans2 = surface_set.trans1;
1163 surface_set.trans1 = *trans;
1164
1165 Ok(())
1166}
1167
1168pub fn ar2_get_trans_mat(
1169 icp_handle: &mut ICPHandleT,
1170 init_conv: [[f32; 4]; 3],
1171 pos2d: &[[f32; 2]],
1172 pos3d: &[[f32; 3]],
1173 num: usize,
1174 conv: &mut [[f32; 4]; 3],
1175 robust_mode: bool,
1176) -> f32 {
1177 use crate::icp::{ICPDataT, ICP2DCoordT, ICP3DCoordT};
1178
1179 let mut dx = 0.0;
1180 let mut dy = 0.0;
1181 let mut dz = 0.0;
1182 for i in 0..num {
1183 dx += pos3d[i][0];
1184 dy += pos3d[i][1];
1185 dz += pos3d[i][2];
1186 }
1187 dx /= num as f32;
1188 dy /= num as f32;
1189 dz /= num as f32;
1190
1191 let mut data_2d = vec![ICP2DCoordT::default(); num];
1192 let mut data_3d = vec![ICP3DCoordT::default(); num];
1193
1194 for i in 0..num {
1195 data_2d[i].x = pos2d[i][0] as ARdouble;
1196 data_2d[i].y = pos2d[i][1] as ARdouble;
1197 data_3d[i].x = (pos3d[i][0] - dx) as ARdouble;
1198 data_3d[i].y = (pos3d[i][1] - dy) as ARdouble;
1199 data_3d[i].z = (pos3d[i][2] - dz) as ARdouble;
1200 }
1201
1202 let data = ICPDataT {
1203 screen_coord: data_2d,
1204 world_coord: data_3d,
1205 };
1206
1207 let mut init_mat = [[0.0 as ARdouble; 4]; 3];
1208 for j in 0..3 {
1209 for i in 0..3 { init_mat[j][i] = init_conv[j][i] as ARdouble; }
1210 }
1211 init_mat[0][3] = (init_conv[0][0] * dx + init_conv[0][1] * dy + init_conv[0][2] * dz + init_conv[0][3]) as ARdouble;
1212 init_mat[1][3] = (init_conv[1][0] * dx + init_conv[1][1] * dy + init_conv[1][2] * dz + init_conv[1][3]) as ARdouble;
1213 init_mat[2][3] = (init_conv[2][0] * dx + init_conv[2][1] * dy + init_conv[2][2] * dz + init_conv[2][3]) as ARdouble;
1214
1215 let mut mat = [[0.0 as ARdouble; 4]; 3];
1216 let mut err = 0.0;
1217
1218 if !robust_mode {
1219 crate::icp::icp_point(icp_handle, &data, &init_mat, &mut mat).map(|e| err = e as f32).ok();
1220 } else {
1221 crate::icp::icp_point_robust(icp_handle, &data, &init_mat, &mut mat).map(|e| err = e as f32).ok();
1222 }
1223
1224 for j in 0..3 {
1225 for i in 0..3 { conv[j][i] = mat[j][i] as f32; }
1226 }
1227 conv[0][3] = (mat[0][3] - mat[0][0] * dx as ARdouble - mat[0][1] * dy as ARdouble - mat[0][2] * dz as ARdouble) as f32;
1228 conv[1][3] = (mat[1][3] - mat[1][0] * dx as ARdouble - mat[1][1] * dy as ARdouble - mat[1][2] * dz as ARdouble) as f32;
1229 conv[2][3] = (mat[2][3] - mat[2][0] * dx as ARdouble - mat[2][1] * dy as ARdouble - mat[2][2] * dz as ARdouble) as f32;
1230
1231 err as f32
1232}
1233
1234pub const KEEP_NUM: usize = 3;
1235pub const SKIP_INTERVAL: i32 = 3;
1236
1237pub fn ar2_get_best_matching(
1238 img: &[u8],
1239 mf_image: &mut [u8],
1240 xsize: i32,
1241 ysize: i32,
1242 pix_format: ARPixelFormat,
1243 mtemp: &AR2Template,
1244 rx: i32,
1245 ry: i32,
1246 search: [[i32; 2]; 3],
1247 bx: &mut i32,
1248 by: &mut i32,
1249 val: &mut f32,
1250) -> Result<(), &'static str> {
1251 for ii in 0..3 {
1253 if search[ii][0] < 0 { break; }
1254
1255 let px = (search[ii][0] / (SKIP_INTERVAL + 1)) * (SKIP_INTERVAL + 1) + (SKIP_INTERVAL + 1) / 2;
1256 let py = (search[ii][1] / (SKIP_INTERVAL + 1)) * (SKIP_INTERVAL + 1) + (SKIP_INTERVAL + 1) / 2;
1257
1258 let sx = (px - rx).max(0);
1259 let ex = (px + rx).min(xsize - 1);
1260 let sy = (py - ry).max(0);
1261 let ey = (py + ry).min(ysize - 1);
1262
1263 for j in sy..=ey {
1264 for i in sx..=ex {
1265 mf_image[(j * xsize + i) as usize] = 0;
1266 }
1267 }
1268 }
1269
1270 let mut keep_num = 0;
1271 let mut cx = [0; KEEP_NUM];
1272 let mut cy = [0; KEEP_NUM];
1273 let mut cval = [0; KEEP_NUM];
1274 let mut ret = true;
1275
1276 for ii in 0..3 {
1277 if search[ii][0] < 0 {
1278 if ret { return Err("No valid search point"); }
1279 break;
1280 }
1281
1282 let px = (search[ii][0] / (SKIP_INTERVAL + 1)) * (SKIP_INTERVAL + 1) + (SKIP_INTERVAL + 1) / 2;
1283 let py = (search[ii][1] / (SKIP_INTERVAL + 1)) * (SKIP_INTERVAL + 1) + (SKIP_INTERVAL + 1) / 2;
1284
1285 for j in (py - ry..=py + ry).step_by((SKIP_INTERVAL + 1) as usize) {
1286 if j - mtemp.yts1 * AR2_TEMP_SCALE < 0 { continue; }
1287 if j + mtemp.yts2 * AR2_TEMP_SCALE >= ysize { break; }
1288
1289 for i in (px - rx..=px + rx).step_by((SKIP_INTERVAL + 1) as usize) {
1290 if i - mtemp.xts1 * AR2_TEMP_SCALE < 0 { continue; }
1291 if i + mtemp.xts2 * AR2_TEMP_SCALE >= xsize { break; }
1292
1293 if mf_image[(j * xsize + i) as usize] != 0 { continue; }
1294 mf_image[(j * xsize + i) as usize] = 1;
1295
1296 let mut wval = 0;
1297 if ar2_get_best_matching_sub_fine(img, xsize, ysize, pix_format, mtemp, i, j, &mut wval).is_ok() {
1298 ret = false;
1299 update_candidate(i, j, wval, &mut keep_num, &mut cx, &mut cy, &mut cval);
1300 }
1301 }
1302 }
1303 }
1304
1305 let mut wval2 = 0;
1306 let mut final_ret = Err("No match found");
1307
1308 for l in 0..keep_num {
1310 for j in cy[l] - SKIP_INTERVAL..=cy[l] + SKIP_INTERVAL {
1311 if j - mtemp.yts1 * AR2_TEMP_SCALE < 0 { continue; }
1312 if j + mtemp.yts2 * AR2_TEMP_SCALE >= ysize { break; }
1313
1314 for i in cx[l] - SKIP_INTERVAL..=cx[l] + SKIP_INTERVAL {
1315 if i - mtemp.xts1 * AR2_TEMP_SCALE < 0 { continue; }
1316 if i + mtemp.xts2 * AR2_TEMP_SCALE >= xsize { break; }
1317
1318 let mut wval = 0;
1319 if ar2_get_best_matching_sub_fine(img, xsize, ysize, pix_format, mtemp, i, j, &mut wval).is_ok() {
1320 if wval > wval2 {
1321 *bx = i;
1322 *by = j;
1323 wval2 = wval;
1324 *val = wval as f32 / 10000.0;
1325 final_ret = Ok(());
1326 }
1327 }
1328 }
1329 }
1330 }
1331
1332 final_ret
1333}
1334
1335pub fn ar2_get_best_matching_sub_fine(
1336 img: &[u8],
1337 xsize: i32,
1338 _ysize: i32,
1339 pix_format: ARPixelFormat,
1340 mtemp: &AR2Template,
1341 sx: i32,
1342 sy: i32,
1343 val: &mut i32,
1344) -> Result<(), &'static str> {
1345 let mut sum1 = 0;
1346 let mut sum2 = 0;
1347 let mut sum3 = 0;
1348
1349 let mut p1_idx = 0;
1350
1351 match pix_format {
1352 ARPixelFormat::MONO | ARPixelFormat::NV21 | ARPixelFormat::FourTwoZeroV | ARPixelFormat::FourTwoZeroF => {
1353 let ssx = -mtemp.xts1;
1354 let eex = mtemp.xts2;
1355 let ssy = -mtemp.yts1;
1356 let eey = mtemp.yts2;
1357
1358 for j in ssy..=eey {
1359 let row_start = (sy + j * AR2_TEMP_SCALE) * xsize + sx + ssx * AR2_TEMP_SCALE;
1360 for _i in ssx..=eex {
1361 let pixel_val = img[row_start as usize + (_i - ssx) as usize * AR2_TEMP_SCALE as usize] as i32;
1362 let template_val = mtemp.img1[p1_idx];
1363 if template_val != AR2_TEMPLATE_NULL_PIXEL {
1364 sum1 += pixel_val;
1365 sum2 += pixel_val * pixel_val;
1366 sum3 += pixel_val * template_val as i32;
1367 }
1368 p1_idx += 1;
1369 }
1370 }
1371 }
1372 _ => {
1373 return Err("Unsupported pixel format for matching");
1376 }
1377 }
1378
1379 sum3 -= sum1 * mtemp.sum / (mtemp.valid_num as i32);
1380 let vlen = sum2 - sum1 * sum1 / (mtemp.valid_num as i32);
1381 if vlen == 0 {
1382 *val = 0;
1383 } else {
1384 *val = (sum3 * 100 / mtemp.vlen) * 100 / (vlen as f32).sqrt() as i32;
1385 }
1386
1387 Ok(())
1388}
1389
1390fn update_candidate(
1391 x: i32,
1392 y: i32,
1393 wval: i32,
1394 keep_num: &mut usize,
1395 cx: &mut [i32; KEEP_NUM],
1396 cy: &mut [i32; KEEP_NUM],
1397 cval: &mut [i32; KEEP_NUM],
1398) {
1399 if *keep_num == 0 {
1400 cx[0] = x;
1401 cy[0] = y;
1402 cval[0] = wval;
1403 *keep_num = 1;
1404 return;
1405 }
1406
1407 let mut insert_idx = *keep_num;
1408 for l in 0..*keep_num {
1409 if cval[l] < wval {
1410 insert_idx = l;
1411 break;
1412 }
1413 }
1414
1415 if insert_idx == *keep_num {
1416 if insert_idx < KEEP_NUM {
1417 cx[insert_idx] = x;
1418 cy[insert_idx] = y;
1419 cval[insert_idx] = wval;
1420 *keep_num += 1;
1421 }
1422 return;
1423 }
1424
1425 let m = if *keep_num == KEEP_NUM { KEEP_NUM - 1 } else { *keep_num };
1426 if *keep_num < KEEP_NUM { *keep_num += 1; }
1427
1428 for n in (insert_idx + 1..=m).rev() {
1429 cx[n] = cx[n - 1];
1430 cy[n] = cy[n - 1];
1431 cval[n] = cval[n - 1];
1432 }
1433 cx[insert_idx] = x;
1434 cy[insert_idx] = y;
1435 cval[insert_idx] = wval;
1436}