LiangLabUMB commited on
Commit
b1d43dd
·
verified ·
1 Parent(s): a885eb4

Upload grid_seeded.py

Browse files

tilt angle tolerance increased to 30 degree

Files changed (1) hide show
  1. grid_seeded.py +59 -2
grid_seeded.py CHANGED
@@ -108,7 +108,19 @@ WIN_PERIODS = 6.2 # window width in ruling periods: 4 for the block,
108
  # the rest for phase search and the angle crop
109
  PER_WORK = WORK / WIN_PERIODS # a period is ALWAYS this many work px
110
  HP_W = int(0.25 * PER_WORK) | 1
111
- ANG_RANGE = 14.0 # deg, rotation half-range
 
 
 
 
 
 
 
 
 
 
 
 
112
  BOOT_FRAC = 0.55 # v3c's fixed window -- used only to seed the fixed point
113
  MAX_ITER = 4
114
  REPEAT_TOL = 0.03 # period change below this ends the fixed point
@@ -686,10 +698,31 @@ def _finish(g, s1, verify):
686
  }
687
 
688
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
689
  def detect_from_seed(image, seed_xy, verify=True, period_hint=None,
690
- lock=False, want_debug=False):
 
691
  """One tap -> the four corners of the surrounding 4x4 counting block.
692
 
 
 
 
 
693
  Parameters
694
  ----------
695
  image : ndarray, HxW grey or HxWx3 RGB. Use the FULL-resolution image;
@@ -705,6 +738,30 @@ def detect_from_seed(image, seed_xy, verify=True, period_hint=None,
705
 
706
  Returns a JSON-safe dict. Always check ``ok`` before using ``corners``.
707
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
708
  g = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if image.ndim == 3 else image
709
  g = np.ascontiguousarray(g)
710
  H, W = g.shape[:2]
 
108
  # the rest for phase search and the angle crop
109
  PER_WORK = WORK / WIN_PERIODS # a period is ALWAYS this many work px
110
  HP_W = int(0.25 * PER_WORK) | 1
111
+ ANG_RANGE = 30.0 # deg, rotation half-range. Widened from 14: phone-through-
112
+ # eyepiece photos are routinely tilted 15-17 deg (measured on
113
+ # the 20260901 cos7 set), which sat AT/OUTSIDE the old +/-14 box.
114
+ # The coarse tilt search then pinned at the boundary or locked
115
+ # onto a spurious negative-angle autocorrelation peak, and every
116
+ # downstream period and line offset came out wrong -- the fit was
117
+ # then (correctly) rejected by QC, so the tap "failed". Set to 30
118
+ # for headroom against steeper future tilts. Low-tilt photos are
119
+ # unaffected: their autocorrelation peak is in the same place, and
120
+ # widening only scans extra angles that score lower.
121
+ # HARD CEILING: keep this < 45. A square grid repeats every 90 deg,
122
+ # so a tilt past 45 aliases into the perpendicular axis (the two
123
+ # ruling directions swap) and the reported angle becomes ambiguous.
124
  BOOT_FRAC = 0.55 # v3c's fixed window -- used only to seed the fixed point
125
  MAX_ITER = 4
126
  REPEAT_TOL = 0.03 # period change below this ends the fixed point
 
698
  }
699
 
700
 
701
+ # ---- multi-start retry --------------------------------------------------
702
+ # One tap fits ONE analysis window. On a faint, cluttered or tilted grid that
703
+ # window can land on a patch where the period fixed point wanders and the fit
704
+ # is (correctly) rejected by QC -- while the SAME block, seeded a little to one
705
+ # side, fits cleanly. Measured on the 20260901 cos7 set: a single centre tap
706
+ # failed on 2 of 4 quadrants, yet every quadrant fit at some nearby tap. A user
707
+ # re-tapping is doing exactly this by hand. So on failure we retry from a small
708
+ # ring of nearby seeds and keep the first that PASSES THE SAME QC gate -- this
709
+ # never loosens acceptance, it only gives the fitter more starting points.
710
+ RETRY_RING = 8 # seeds tried on failure, evenly spaced on a ring
711
+ RETRY_RADIUS_FRAC = 0.08 # ring radius as a fraction of the short image side.
712
+ # ~0.5-0.8 of a ruling period on these photos, so the
713
+ # retries stay well inside the tapped block and cannot
714
+ # jump to a neighbouring one (block ~4 periods across).
715
+
716
+
717
  def detect_from_seed(image, seed_xy, verify=True, period_hint=None,
718
+ lock=False, want_debug=False,
719
+ retries=RETRY_RING, retry_radius_frac=RETRY_RADIUS_FRAC):
720
  """One tap -> the four corners of the surrounding 4x4 counting block.
721
 
722
+ Fits at the tap; if that is rejected, retries from a ring of nearby seeds
723
+ (see RETRY_RING above) and returns the first fit that passes QC, otherwise
724
+ the original rejection. Set retries=0 for the old single-shot behaviour.
725
+
726
  Parameters
727
  ----------
728
  image : ndarray, HxW grey or HxWx3 RGB. Use the FULL-resolution image;
 
738
 
739
  Returns a JSON-safe dict. Always check ``ok`` before using ``corners``.
740
  """
741
+ import math
742
+ out = _detect_from_seed_once(image, seed_xy, verify, period_hint,
743
+ lock, want_debug)
744
+ if out.get("ok") or retries <= 0:
745
+ return out
746
+ H, W = image.shape[:2]
747
+ r = retry_radius_frac * min(H, W)
748
+ sx0, sy0 = float(seed_xy[0]), float(seed_xy[1])
749
+ for k in range(int(retries)):
750
+ a = 2.0 * math.pi * k / int(retries)
751
+ s2 = (sx0 + r * math.cos(a), sy0 + r * math.sin(a))
752
+ if not (0 <= s2[0] < W and 0 <= s2[1] < H):
753
+ continue
754
+ alt = _detect_from_seed_once(image, s2, verify, period_hint,
755
+ lock, want_debug)
756
+ if alt.get("ok"):
757
+ alt["retry_seed"] = [int(s2[0]), int(s2[1])]
758
+ return alt
759
+ return out
760
+
761
+
762
+ def _detect_from_seed_once(image, seed_xy, verify=True, period_hint=None,
763
+ lock=False, want_debug=False):
764
+ """Single-window fit at exactly `seed_xy`. See detect_from_seed."""
765
  g = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) if image.ndim == 3 else image
766
  g = np.ascontiguousarray(g)
767
  H, W = g.shape[:2]