constructelligence commited on
Commit
17d2de1
·
verified ·
1 Parent(s): 495ab9b

Upload robot_planner.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. robot_planner.py +37 -3
robot_planner.py CHANGED
@@ -30,6 +30,7 @@ Example::
30
  from __future__ import annotations
31
 
32
  import argparse
 
33
  import json
34
  from pathlib import Path
35
 
@@ -303,14 +304,16 @@ def count_passes(segments, orientation):
303
 
304
 
305
  def build_plan(paintable, keepout, stroke_width, overlap, margin, orientation, corners, mm_per_unit,
306
- boundary_tolerance, trim_width=None, trim_overlap=None, already_painted=None):
 
 
307
  height, width = paintable.shape
308
- plane_size, to_plane, to_image = (width, height), None, None
309
  if corners is not None:
310
  corners = np.asarray(corners, float)
311
  edge_w = max(np.linalg.norm(corners[1] - corners[0]), np.linalg.norm(corners[2] - corners[3]))
312
  edge_h = max(np.linalg.norm(corners[3] - corners[0]), np.linalg.norm(corners[2] - corners[1]))
313
- plane_size = (max(1, int(round(edge_w))), max(1, int(round(edge_h))))
314
  to_plane = homography(corners, [(0, 0), (plane_size[0], 0), (plane_size[0], plane_size[1]), (0, plane_size[1])])
315
  to_image = np.linalg.inv(to_plane)
316
  paintable = warp_mask(paintable, to_plane, plane_size)
@@ -484,6 +487,11 @@ def main():
484
  source.add_argument("--paintable", type=Path, help="binary paintable-wall mask PNG from predict.py")
485
  source.add_argument("--mask", type=Path, help="semantic mask PNG; paintable/keep-out are derived from it")
486
  parser.add_argument("--keepout", type=Path, help="binary keep-out mask PNG (used with --paintable)")
 
 
 
 
 
487
  parser.add_argument("--corners", type=corners_arg,
488
  help='four wall corners "TL TR BR BL" as "x,y x,y x,y x,y"')
489
  parser.add_argument("--stroke-width", type=float, default=230.0, help="roller/pass width in plane units")
@@ -522,6 +530,31 @@ def main():
522
  paintable = np.isin(semantic, WALL_CLASSES)
523
  keepout = np.isin(semantic, KEEPOUT_CLASSES)
524
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  already = None
526
  if args.state:
527
  loaded = load_state(args.state)
@@ -539,6 +572,7 @@ def main():
539
 
540
  plan, debug = build_plan(paintable, keepout, args.stroke_width, args.overlap, args.margin,
541
  args.orientation, args.corners, args.mm_per_unit, args.boundary_tolerance,
 
542
  trim_width=args.trim_width, trim_overlap=args.trim_overlap, already_painted=already)
543
  rendered = json.dumps(plan, indent=2)
544
  print(rendered)
 
30
  from __future__ import annotations
31
 
32
  import argparse
33
+ import sys
34
  import json
35
  from pathlib import Path
36
 
 
304
 
305
 
306
  def build_plan(paintable, keepout, stroke_width, overlap, margin, orientation, corners, mm_per_unit,
307
+ boundary_tolerance, trim_width=None, trim_overlap=None, already_painted=None, plane_size=None):
308
+ """``plane_size`` (units wide, units high) sets the true wall-plane aspect; without it the
309
+ longest image edges are used, which is only right for a near-frontal view."""
310
  height, width = paintable.shape
311
+ given_size, plane_size, to_plane, to_image = plane_size, (width, height), None, None
312
  if corners is not None:
313
  corners = np.asarray(corners, float)
314
  edge_w = max(np.linalg.norm(corners[1] - corners[0]), np.linalg.norm(corners[2] - corners[3]))
315
  edge_h = max(np.linalg.norm(corners[3] - corners[0]), np.linalg.norm(corners[2] - corners[1]))
316
+ plane_size = given_size or (max(1, int(round(edge_w))), max(1, int(round(edge_h))))
317
  to_plane = homography(corners, [(0, 0), (plane_size[0], 0), (plane_size[0], plane_size[1]), (0, plane_size[1])])
318
  to_image = np.linalg.inv(to_plane)
319
  paintable = warp_mask(paintable, to_plane, plane_size)
 
487
  source.add_argument("--paintable", type=Path, help="binary paintable-wall mask PNG from predict.py")
488
  source.add_argument("--mask", type=Path, help="semantic mask PNG; paintable/keep-out are derived from it")
489
  parser.add_argument("--keepout", type=Path, help="binary keep-out mask PNG (used with --paintable)")
490
+ parser.add_argument("--measurements", type=Path,
491
+ help="predict.py --json output: plan inside a measured face's paint region at true size; "
492
+ "plane units are then --unit-mm millimetres and widths/margins are in mm")
493
+ parser.add_argument("--face", type=int, default=0, help="which measured face to plan (with --measurements)")
494
+ parser.add_argument("--unit-mm", type=float, default=10.0, help="plane resolution with --measurements")
495
  parser.add_argument("--corners", type=corners_arg,
496
  help='four wall corners "TL TR BR BL" as "x,y x,y x,y x,y"')
497
  parser.add_argument("--stroke-width", type=float, default=230.0, help="roller/pass width in plane units")
 
530
  paintable = np.isin(semantic, WALL_CLASSES)
531
  keepout = np.isin(semantic, KEEPOUT_CLASSES)
532
 
533
+ plane_size = None
534
+ if args.measurements:
535
+ data = json.loads(args.measurements.read_text(encoding="utf-8"))
536
+ faces = (data.get("measurements") or data).get("faces") or []
537
+ if not 0 <= args.face < len(faces):
538
+ parser.error(f"{args.measurements} has {len(faces)} measured face(s); --face {args.face} is not one")
539
+ face = faces[args.face]
540
+ open_ends = [side for side, kind in face["ends"].items() if kind == "frame"]
541
+ if open_ends:
542
+ print(f"warning: the wall continues past the image on the {' and '.join(open_ends)}; "
543
+ f"this plan covers only the visible part and has no stop there", file=sys.stderr)
544
+ doubtful = [k for k, v in face.get("stop_line_trust", {}).items() if v == "conflict"]
545
+ if doubtful:
546
+ print(f"warning: {', '.join(doubtful)} stop line(s) disagree with the segmentation; verify before painting",
547
+ file=sys.stderr)
548
+ # Plan in true wall-plane millimetres: ceiling line to top of skirting, end to end.
549
+ args.corners = [tuple(p) for p in face["paint_region_corners_px"]]
550
+ args.mm_per_unit = args.unit_mm
551
+ plane_size = (max(1, round(face["width_ft"] * 304.8 / args.unit_mm)),
552
+ max(1, round(face["paint_height_ft"] * 304.8 / args.unit_mm)))
553
+ args.stroke_width /= args.unit_mm
554
+ args.margin /= args.unit_mm
555
+ if args.trim_width:
556
+ args.trim_width /= args.unit_mm
557
+
558
  already = None
559
  if args.state:
560
  loaded = load_state(args.state)
 
572
 
573
  plan, debug = build_plan(paintable, keepout, args.stroke_width, args.overlap, args.margin,
574
  args.orientation, args.corners, args.mm_per_unit, args.boundary_tolerance,
575
+ plane_size=plane_size,
576
  trim_width=args.trim_width, trim_overlap=args.trim_overlap, already_painted=already)
577
  rendered = json.dumps(plan, indent=2)
578
  print(rendered)