Pream912 commited on
Commit
3c0d7ed
Β·
verified Β·
1 Parent(s): 25757b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -46
app.py CHANGED
@@ -605,9 +605,26 @@ def init_state() -> Dict:
605
  def cb_load_image(upload, state):
606
  if upload is None:
607
  return None, state, "Upload a floor-plan image to begin."
608
- img_bgr = cv2.imdecode(
609
- np.frombuffer(upload, dtype=np.uint8), cv2.IMREAD_COLOR
610
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
  if img_bgr is None:
612
  return None, state, "❌ Could not decode image."
613
  state = init_state()
@@ -699,25 +716,25 @@ def cb_undo_door_line(state):
699
  return vis, state, f"↩ Last line removed. Remaining: {len(state['user_lines'])}"
700
 
701
 
702
- def cb_run_sam(state, progress=gr.Progress()):
703
  walls = state.get("walls")
704
  img = state.get("img_cropped")
705
  if walls is None or img is None:
706
  return None, None, state, "Run preprocessing first."
707
 
708
- progress(0.1, desc="Downloading SAM checkpoint…")
709
  ckpt = download_sam_if_needed()
710
  if ckpt is None:
711
  return None, None, state, "❌ SAM checkpoint download failed."
712
 
713
- progress(0.3, desc="Segmenting rooms…")
714
  img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
715
  raw = segment_with_sam(img_rgb, walls.copy(), ckpt)
716
 
717
- progress(0.6, desc="Filtering rooms…")
718
  filtered = filter_room_masks(raw, img.shape)
719
 
720
- progress(0.75, desc="Running OCR…")
721
  rooms = []
722
  for idx, entry in enumerate(filtered, 1):
723
  cnt = entry["contour"]
@@ -748,7 +765,7 @@ def cb_run_sam(state, progress=gr.Progress()):
748
  state["rooms"] = rooms
749
  state["selected_ids"] = []
750
 
751
- progress(0.9, desc="Rendering…")
752
  annotated = build_annotated_image(img, rooms)
753
  state["annotated"] = annotated
754
 
@@ -854,29 +871,37 @@ CSS = """
854
  #title { text-align: center; font-size: 1.8em; font-weight: 700; color: #1F4E79; }
855
  #subtitle { text-align: center; color: #555; margin-top: -8px; margin-bottom: 16px; }
856
  .step-card { border-left: 4px solid #1F4E79 !important; padding-left: 10px !important; }
857
- #status-box textarea { font-size: 0.95em !important; color: #1a6b2e !important; font-weight: 600 !important; }
858
  """
859
 
860
- with gr.Blocks(css=CSS, title="FloorPlan Analyser") as app:
 
 
 
 
 
 
 
 
 
861
  state = gr.State(init_state())
862
 
863
  gr.Markdown("# 🏒 Floor Plan Room Analyser", elem_id="title")
864
  gr.Markdown(
865
  "Upload a floor-plan β†’ auto-extract walls β†’ close doors β†’ SAM segmentation β†’ OCR labels β†’ export Excel",
866
- elem_id="subtitle"
867
  )
868
 
869
- status_box = gr.Textbox(label="Status", interactive=False,
870
- value="Idle β€” upload a floor plan to begin.",
871
- elem_id="status-box")
 
 
872
 
873
  # ── Row 1: Upload + Preprocessing ───────────────────────────────────────
874
  with gr.Row():
875
  with gr.Column(scale=1, elem_classes="step-card"):
876
  gr.Markdown("### 1️⃣ Upload Floor Plan")
877
- upload_btn = gr.UploadButton(
878
- "πŸ“‚ Upload Image", file_types=["image"], size="sm"
879
- )
880
  raw_preview = gr.Image(label="Loaded Image", height=320)
881
 
882
  with gr.Column(scale=1, elem_classes="step-card"):
@@ -893,14 +918,15 @@ with gr.Blocks(css=CSS, title="FloorPlan Analyser") as app:
893
  with gr.Column(elem_classes="step-card"):
894
  gr.Markdown("### 3️⃣ Draw Door-Closing Lines *(click start β†’ click end)*")
895
  gr.Markdown(
896
- "Click on the **Walls** image below to define start/end of a door-closing line. "
897
- "Drawn lines are applied to the wall mask before SAM runs, preventing segment leakage."
 
898
  )
899
- with gr.Row():
900
- undo_line_btn = gr.Button("↩ Undo Last Line", size="sm")
901
  wall_draw_img = gr.Image(
902
- label="Wall mask β€” click to draw door lines",
903
- height=380, interactive=False
 
904
  )
905
 
906
  # ── Row 3: SAM + Annotation ──────────────────────────────────────────────
@@ -909,8 +935,9 @@ with gr.Blocks(css=CSS, title="FloorPlan Analyser") as app:
909
  gr.Markdown("### 4️⃣ SAM Segmentation + OCR")
910
  sam_btn = gr.Button("πŸ€– Run SAM + OCR", variant="primary")
911
  ann_img = gr.Image(
912
- label="Annotated rooms β€” click to select/deselect",
913
- height=480, interactive=False
 
914
  )
915
 
916
  with gr.Column(scale=1, elem_classes="step-card"):
@@ -918,81 +945,80 @@ with gr.Blocks(css=CSS, title="FloorPlan Analyser") as app:
918
  room_table = gr.Dataframe(
919
  headers=["ID", "Label", "Area", "SAM Score"],
920
  datatype=["number", "str", "str", "str"],
921
- interactive=False, label="Detected Rooms"
 
922
  )
923
  with gr.Group():
924
  gr.Markdown("**Edit selected room(s)**")
925
- rename_txt = gr.Textbox(
926
- placeholder="New label…", label="Rename Label"
927
- )
928
  with gr.Row():
929
  rename_btn = gr.Button("✏ Rename", size="sm")
930
  remove_btn = gr.Button("πŸ—‘ Remove Selected", size="sm", variant="stop")
931
 
932
  gr.Markdown("---")
933
- export_btn = gr.Button("πŸ“Š Export to Excel", variant="secondary")
934
- excel_file = gr.File(label="Download Excel", visible=True)
935
 
936
- # ── Wiring ───────────────────────────────────────────────────────────────
937
 
938
  upload_btn.upload(
939
  cb_load_image,
940
  inputs=[upload_btn, state],
941
- outputs=[raw_preview, state, status_box]
942
  )
943
 
944
  preprocess_btn.click(
945
  cb_preprocess,
946
  inputs=[state],
947
- outputs=[clean_img, walls_img, state, status_box]
948
  ).then(
949
- lambda s: cv2.cvtColor(s["walls"], cv2.COLOR_GRAY2RGB)
950
- if s.get("walls") is not None else None,
951
  inputs=[state],
952
- outputs=[wall_draw_img]
953
  )
954
 
955
  wall_draw_img.select(
956
  cb_add_door_line,
957
  inputs=[state],
958
- outputs=[wall_draw_img, state, status_box]
959
  )
960
 
961
  undo_line_btn.click(
962
  cb_undo_door_line,
963
  inputs=[state],
964
- outputs=[wall_draw_img, state, status_box]
965
  )
966
 
967
  sam_btn.click(
968
  cb_run_sam,
969
  inputs=[state],
970
- outputs=[ann_img, room_table, state, status_box]
971
  )
972
 
973
  ann_img.select(
974
  cb_click_room,
975
  inputs=[state],
976
- outputs=[ann_img, state, status_box]
977
  )
978
 
979
  remove_btn.click(
980
  cb_remove_selected,
981
  inputs=[state],
982
- outputs=[ann_img, room_table, state, status_box]
983
  )
984
 
985
  rename_btn.click(
986
  cb_rename_selected,
987
  inputs=[rename_txt, state],
988
- outputs=[ann_img, room_table, state, status_box]
989
  )
990
 
991
  export_btn.click(
992
  cb_export_excel,
993
  inputs=[state],
994
- outputs=[excel_file, status_box]
995
  )
996
 
 
997
  if __name__ == "__main__":
998
- app.launch(share=False, debug=True)
 
605
  def cb_load_image(upload, state):
606
  if upload is None:
607
  return None, state, "Upload a floor-plan image to begin."
608
+ # Gradio 6: UploadButton returns a NamedString (file path) or a dict
609
+ try:
610
+ if hasattr(upload, "name"):
611
+ file_path = upload.name # NamedString / tempfile path
612
+ elif isinstance(upload, dict) and "name" in upload:
613
+ file_path = upload["name"]
614
+ elif isinstance(upload, str):
615
+ file_path = upload
616
+ else:
617
+ # bytes fallback
618
+ img_bgr = cv2.imdecode(
619
+ np.frombuffer(bytes(upload), dtype=np.uint8), cv2.IMREAD_COLOR
620
+ )
621
+ file_path = None
622
+
623
+ if file_path is not None:
624
+ img_bgr = cv2.imread(file_path)
625
+ except Exception as e:
626
+ return None, state, f"❌ Error reading upload: {e}"
627
+
628
  if img_bgr is None:
629
  return None, state, "❌ Could not decode image."
630
  state = init_state()
 
716
  return vis, state, f"↩ Last line removed. Remaining: {len(state['user_lines'])}"
717
 
718
 
719
+ def cb_run_sam(state):
720
  walls = state.get("walls")
721
  img = state.get("img_cropped")
722
  if walls is None or img is None:
723
  return None, None, state, "Run preprocessing first."
724
 
725
+ print("[SAM] Downloading checkpoint if needed…")
726
  ckpt = download_sam_if_needed()
727
  if ckpt is None:
728
  return None, None, state, "❌ SAM checkpoint download failed."
729
 
730
+ print("[SAM] Segmenting rooms…")
731
  img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
732
  raw = segment_with_sam(img_rgb, walls.copy(), ckpt)
733
 
734
+ print("[SAM] Filtering rooms…")
735
  filtered = filter_room_masks(raw, img.shape)
736
 
737
+ print("[SAM] Running OCR…")
738
  rooms = []
739
  for idx, entry in enumerate(filtered, 1):
740
  cnt = entry["contour"]
 
765
  state["rooms"] = rooms
766
  state["selected_ids"] = []
767
 
768
+ print("[SAM] Rendering…")
769
  annotated = build_annotated_image(img, rooms)
770
  state["annotated"] = annotated
771
 
 
871
  #title { text-align: center; font-size: 1.8em; font-weight: 700; color: #1F4E79; }
872
  #subtitle { text-align: center; color: #555; margin-top: -8px; margin-bottom: 16px; }
873
  .step-card { border-left: 4px solid #1F4E79 !important; padding-left: 10px !important; }
 
874
  """
875
 
876
+
877
+ def _walls_to_rgb(s):
878
+ """Helper used in .then() β€” must be a named function for Gradio 6."""
879
+ w = s.get("walls")
880
+ if w is None:
881
+ return None
882
+ return cv2.cvtColor(w, cv2.COLOR_GRAY2RGB)
883
+
884
+
885
+ with gr.Blocks(title="FloorPlan Analyser") as app:
886
  state = gr.State(init_state())
887
 
888
  gr.Markdown("# 🏒 Floor Plan Room Analyser", elem_id="title")
889
  gr.Markdown(
890
  "Upload a floor-plan β†’ auto-extract walls β†’ close doors β†’ SAM segmentation β†’ OCR labels β†’ export Excel",
891
+ elem_id="subtitle",
892
  )
893
 
894
+ status_box = gr.Textbox(
895
+ label="Status",
896
+ interactive=False,
897
+ value="Idle β€” upload a floor plan to begin.",
898
+ )
899
 
900
  # ── Row 1: Upload + Preprocessing ───────────────────────────────────────
901
  with gr.Row():
902
  with gr.Column(scale=1, elem_classes="step-card"):
903
  gr.Markdown("### 1️⃣ Upload Floor Plan")
904
+ upload_btn = gr.UploadButton("πŸ“‚ Upload Image", file_types=["image"], size="sm")
 
 
905
  raw_preview = gr.Image(label="Loaded Image", height=320)
906
 
907
  with gr.Column(scale=1, elem_classes="step-card"):
 
918
  with gr.Column(elem_classes="step-card"):
919
  gr.Markdown("### 3️⃣ Draw Door-Closing Lines *(click start β†’ click end)*")
920
  gr.Markdown(
921
+ "Click the wall image below: **first click** = line start, "
922
+ "**second click** = line end. Lines are burned into the wall mask "
923
+ "before SAM runs to prevent room leakage through open doors."
924
  )
925
+ undo_line_btn = gr.Button("↩ Undo Last Line", size="sm")
 
926
  wall_draw_img = gr.Image(
927
+ label="Wall mask β€” click to draw door-closing lines",
928
+ height=380,
929
+ interactive=False,
930
  )
931
 
932
  # ── Row 3: SAM + Annotation ──────────────────────────────────────────────
 
935
  gr.Markdown("### 4️⃣ SAM Segmentation + OCR")
936
  sam_btn = gr.Button("πŸ€– Run SAM + OCR", variant="primary")
937
  ann_img = gr.Image(
938
+ label="Annotated rooms β€” click to select / deselect",
939
+ height=480,
940
+ interactive=False,
941
  )
942
 
943
  with gr.Column(scale=1, elem_classes="step-card"):
 
945
  room_table = gr.Dataframe(
946
  headers=["ID", "Label", "Area", "SAM Score"],
947
  datatype=["number", "str", "str", "str"],
948
+ interactive=False,
949
+ label="Detected Rooms",
950
  )
951
  with gr.Group():
952
  gr.Markdown("**Edit selected room(s)**")
953
+ rename_txt = gr.Textbox(placeholder="New label…", label="Rename Label")
 
 
954
  with gr.Row():
955
  rename_btn = gr.Button("✏ Rename", size="sm")
956
  remove_btn = gr.Button("πŸ—‘ Remove Selected", size="sm", variant="stop")
957
 
958
  gr.Markdown("---")
959
+ export_btn = gr.Button("πŸ“Š Export to Excel", variant="secondary")
960
+ excel_file = gr.File(label="Download Excel", visible=True)
961
 
962
+ # ── Event Wiring ─────────────────────────────────────────────────────────
963
 
964
  upload_btn.upload(
965
  cb_load_image,
966
  inputs=[upload_btn, state],
967
+ outputs=[raw_preview, state, status_box],
968
  )
969
 
970
  preprocess_btn.click(
971
  cb_preprocess,
972
  inputs=[state],
973
+ outputs=[clean_img, walls_img, state, status_box],
974
  ).then(
975
+ _walls_to_rgb,
 
976
  inputs=[state],
977
+ outputs=[wall_draw_img],
978
  )
979
 
980
  wall_draw_img.select(
981
  cb_add_door_line,
982
  inputs=[state],
983
+ outputs=[wall_draw_img, state, status_box],
984
  )
985
 
986
  undo_line_btn.click(
987
  cb_undo_door_line,
988
  inputs=[state],
989
+ outputs=[wall_draw_img, state, status_box],
990
  )
991
 
992
  sam_btn.click(
993
  cb_run_sam,
994
  inputs=[state],
995
+ outputs=[ann_img, room_table, state, status_box],
996
  )
997
 
998
  ann_img.select(
999
  cb_click_room,
1000
  inputs=[state],
1001
+ outputs=[ann_img, state, status_box],
1002
  )
1003
 
1004
  remove_btn.click(
1005
  cb_remove_selected,
1006
  inputs=[state],
1007
+ outputs=[ann_img, room_table, state, status_box],
1008
  )
1009
 
1010
  rename_btn.click(
1011
  cb_rename_selected,
1012
  inputs=[rename_txt, state],
1013
+ outputs=[ann_img, room_table, state, status_box],
1014
  )
1015
 
1016
  export_btn.click(
1017
  cb_export_excel,
1018
  inputs=[state],
1019
+ outputs=[excel_file, status_box],
1020
  )
1021
 
1022
+
1023
  if __name__ == "__main__":
1024
+ app.launch(share=False, debug=True, css=CSS)