VanNguyen1214 commited on
Commit
75e661f
·
verified ·
1 Parent(s): fda97ae

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +266 -3
app.py CHANGED
@@ -566,8 +566,177 @@ if __name__ == '__main__':
566
  args.cfg = 'src/config/zind.yaml'
567
  zind_model = get_model(args)
568
 
569
- with gr.Blocks(title="Layout Estimate Room", theme=gr.themes.Soft()) as demo:
570
- gr.Markdown("# Layout Estimate Room - Multi-Room Edition")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
 
572
  with gr.Row():
573
  with gr.Column(scale=1):
@@ -693,6 +862,18 @@ if __name__ == '__main__':
693
  height=400
694
  )
695
 
 
 
 
 
 
 
 
 
 
 
 
 
696
 
697
  with gr.Row():
698
  mesh_file = gr.File(label='💾 Tải xuống file 3D')
@@ -720,6 +901,7 @@ if __name__ == '__main__':
720
  if mode == "🏠 Phòng đơn":
721
  return (
722
  gr.update(visible=True), # single_image
 
723
  gr.update(visible=False), # multi_images
724
  gr.update(visible=True), # single_guide
725
  gr.update(visible=False), # multi_guide
@@ -728,6 +910,7 @@ if __name__ == '__main__':
728
  elif mode == "🏢 Phòng rộng":
729
  return (
730
  gr.update(visible=False), # single_image
 
731
  gr.update(visible=True), # multi_images
732
  gr.update(visible=False), # single_guide
733
  gr.update(visible=True), # multi_guide
@@ -736,6 +919,7 @@ if __name__ == '__main__':
736
  else: # "🚪 Ghép phòng thông minh"
737
  return (
738
  gr.update(visible=False), # single_image
 
739
  gr.update(visible=True), # multi_images
740
  gr.update(visible=False), # single_guide
741
  gr.update(visible=False), # multi_guide
@@ -746,7 +930,7 @@ if __name__ == '__main__':
746
  processing_mode.change(
747
  fn=switch_mode,
748
  inputs=[processing_mode],
749
- outputs=[single_image, multi_images, single_guide, multi_guide, smart_guide]
750
  )
751
 
752
  # Function to handle processing based on selected mode
@@ -769,6 +953,85 @@ if __name__ == '__main__':
769
  else:
770
  return [None, None, None, None, None]
771
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
772
 
773
  # Event handlers
774
  process_btn.click(
 
566
  args.cfg = 'src/config/zind.yaml'
567
  zind_model = get_model(args)
568
 
569
+ description = """
570
+ # 🏠 Layout Estimate Room - Multi-Room Edition
571
+
572
+ **Ước lượng layout phòng 3D từ ảnh panorama với khả năng ghép nhiều phòng thông qua cửa**
573
+
574
+ Ứng dụng này sử dụng công nghệ AI tiên tiến để phân tích ảnh toàn cảnh 360° và tạo ra mô hình 3D chi tiết của phòng.
575
+ **🆕 Tính năng mới**: Tự động phát hiện cửa và ghép nhiều phòng thành bản đồ hoàn chỉnh!
576
+
577
+ ### ✨ Tính năng nổi bật:
578
+ - 🎯 Phân tích layout phòng tự động từ ảnh panorama
579
+ - 🚪 **Phát hiện cửa thông minh** và ghép các phòng liền kề
580
+ - 🏠 **Tạo bản đồ toàn bộ ngôi nhà** từ nhiều ảnh panorama
581
+ - 🎨 Tạo mô hình 3D chất lượng cao cho từng phòng và toàn bộ không gian
582
+ - 📊 Hiển thị kết quả trực quan với thông tin chi tiết về cửa và kết nối
583
+ - 💾 Xuất file 3D và JSON với dữ liệu layout hoàn chỉnh
584
+
585
+ ---
586
+ """
587
+
588
+ # Enhanced CSS without Light/Dark mode
589
+ custom_css = """
590
+ .gradio-container {
591
+ max-width: 1800px !important;
592
+ margin: auto !important;
593
+ transition: all 0.3s ease;
594
+ }
595
+
596
+ /* Enhanced Components */
597
+ .panorama-viewer {
598
+ width: 100% !important;
599
+ height: 450px !important;
600
+ border-radius: 15px;
601
+ margin: 20px 0;
602
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
603
+ overflow: hidden;
604
+ transition: all 0.3s ease;
605
+ }
606
+
607
+ .panorama-viewer:hover {
608
+ transform: translateY(-2px);
609
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
610
+ }
611
+
612
+ /* Improved Cards */
613
+ .info-card {
614
+ backdrop-filter: blur(10px);
615
+ border-radius: 15px;
616
+ padding: 20px;
617
+ margin: 15px 0;
618
+ transition: all 0.3s ease;
619
+ }
620
+
621
+ .info-card:hover {
622
+ transform: translateY(-2px);
623
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
624
+ }
625
+
626
+ /* Button Enhancements */
627
+ .gr-button {
628
+ border: none !important;
629
+ border-radius: 25px !important;
630
+ padding: 12px 24px !important;
631
+ font-weight: 600 !important;
632
+ transition: all 0.3s ease !important;
633
+ }
634
+
635
+ .gr-button:hover {
636
+ transform: translateY(-2px) !important;
637
+ }
638
+
639
+ /* Responsive Design */
640
+ @media (max-width: 768px) {
641
+ .gradio-container {
642
+ max-width: 100% !important;
643
+ padding: 10px !important;
644
+ }
645
+
646
+ .panorama-viewer {
647
+ height: 300px !important;
648
+ }
649
+ }
650
+
651
+ /* Animation Classes */
652
+ .fade-in {
653
+ animation: fadeIn 0.5s ease-in;
654
+ }
655
+
656
+ @keyframes fadeIn {
657
+ from { opacity: 0; transform: translateY(20px); }
658
+ to { opacity: 1; transform: translateY(0); }
659
+ }
660
+
661
+ .slide-in {
662
+ animation: slideIn 0.3s ease-out;
663
+ }
664
+
665
+ @keyframes slideIn {
666
+ from { transform: translateX(-20px); opacity: 0; }
667
+ to { transform: translateX(0); opacity: 1; }
668
+ }
669
+ """
670
+
671
+ # Pannellum HTML template
672
+ pannellum_html = """
673
+ <!DOCTYPE HTML>
674
+ <html>
675
+ <head>
676
+ <meta charset="utf-8">
677
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
678
+ <title>Panorama Viewer</title>
679
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pannellum@2.5.6/build/pannellum.css"/>
680
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/pannellum@2.5.6/build/pannellum.js"></script>
681
+ <style>
682
+ #panorama {
683
+ width: 100%;
684
+ height: 400px;
685
+ border-radius: 10px;
686
+ }
687
+ body {
688
+ margin: 0;
689
+ padding: 10px;
690
+ font-family: Arial, sans-serif;
691
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
692
+ }
693
+ .controls {
694
+ text-align: center;
695
+ margin: 10px 0;
696
+ color: white;
697
+ }
698
+ .info {
699
+ background: rgba(255,255,255,0.9);
700
+ padding: 10px;
701
+ border-radius: 5px;
702
+ margin: 10px 0;
703
+ font-size: 14px;
704
+ }
705
+ </style>
706
+ </head>
707
+ <body>
708
+ <div class="info">
709
+ <strong>🌐 Panorama 360° Viewer</strong><br>
710
+ Sử dụng chuột để xoay, scroll để zoom. Ảnh này sẽ được phân tích để tạo layout 3D.
711
+ </div>
712
+ <div id="panorama"></div>
713
+ <div class="controls">
714
+ <p>📱 Di chuyển chuột để khám phá không gian 360°</p>
715
+ </div>
716
+ <script>
717
+ pannellum.viewer('panorama', {
718
+ "type": "equirectangular",
719
+ "panorama": "{image_path}",
720
+ "autoLoad": true,
721
+ "autoRotate": -2,
722
+ "compass": true,
723
+ "northOffset": 0,
724
+ "showZoomCtrl": true,
725
+ "showFullscreenCtrl": true,
726
+ "showControls": true,
727
+ "hotSpotDebug": false,
728
+ "backgroundColor": [0, 0, 0],
729
+ "minHfov": 50,
730
+ "maxHfov": 120,
731
+ "hfov": 100
732
+ });
733
+ </script>
734
+ </body>
735
+ </html>
736
+ """
737
+
738
+ with gr.Blocks(css=custom_css, title="Layout Estimate Room", theme=gr.themes.Soft()) as demo:
739
+ gr.Markdown(description)
740
 
741
  with gr.Row():
742
  with gr.Column(scale=1):
 
862
  height=400
863
  )
864
 
865
+ # Panorama 360° viewer positioned below 3D model
866
+ panorama_viewer = gr.HTML(
867
+ label="🌐 Xem Panorama 360°",
868
+ value="""
869
+ <div style="text-align: center; padding: 50px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 10px; color: white;">
870
+ <h3>🌐 Panorama 360° Viewer</h3>
871
+ <p>Tải lên ảnh panorama để xem trước 360°</p>
872
+ <p><small>Hỗ trợ định dạng: JPG, PNG, JPEG</small></p>
873
+ </div>
874
+ """,
875
+ visible=True
876
+ )
877
 
878
  with gr.Row():
879
  mesh_file = gr.File(label='💾 Tải xuống file 3D')
 
901
  if mode == "🏠 Phòng đơn":
902
  return (
903
  gr.update(visible=True), # single_image
904
+ gr.update(visible=True), # panorama_viewer
905
  gr.update(visible=False), # multi_images
906
  gr.update(visible=True), # single_guide
907
  gr.update(visible=False), # multi_guide
 
910
  elif mode == "🏢 Phòng rộng":
911
  return (
912
  gr.update(visible=False), # single_image
913
+ gr.update(visible=False), # panorama_viewer
914
  gr.update(visible=True), # multi_images
915
  gr.update(visible=False), # single_guide
916
  gr.update(visible=True), # multi_guide
 
919
  else: # "🚪 Ghép phòng thông minh"
920
  return (
921
  gr.update(visible=False), # single_image
922
+ gr.update(visible=False), # panorama_viewer
923
  gr.update(visible=True), # multi_images
924
  gr.update(visible=False), # single_guide
925
  gr.update(visible=False), # multi_guide
 
930
  processing_mode.change(
931
  fn=switch_mode,
932
  inputs=[processing_mode],
933
+ outputs=[single_image, panorama_viewer, multi_images, single_guide, multi_guide, smart_guide]
934
  )
935
 
936
  # Function to handle processing based on selected mode
 
953
  else:
954
  return [None, None, None, None, None]
955
 
956
+ # Function to update panorama viewer with iframe
957
+ def update_panorama_viewer(image_path):
958
+ if image_path is None:
959
+ return """
960
+ <div style="text-align: center; padding: 50px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 10px; color: white;">
961
+ <h3>🌐 Panorama 360° Viewer</h3>
962
+ <p>Tải lên ảnh panorama để xem trước 360°</p>
963
+ <p><small>Hỗ trợ định dạng: JPG, PNG, JPEG</small></p>
964
+ </div>
965
+ """
966
+
967
+ try:
968
+ import base64
969
+ import os
970
+
971
+ # Create base64 data URL for the image
972
+ with open(image_path, "rb") as img_file:
973
+ img_data = base64.b64encode(img_file.read()).decode()
974
+
975
+ # Determine MIME type
976
+ file_ext = os.path.splitext(image_path)[1].lower()
977
+ if file_ext in ['.jpg', '.jpeg']:
978
+ mime_type = 'image/jpeg'
979
+ elif file_ext == '.png':
980
+ mime_type = 'image/png'
981
+ else:
982
+ mime_type = 'image/jpeg'
983
+
984
+ data_url = f"data:{mime_type};base64,{img_data}"
985
+
986
+ # Create iframe with Pannellum CDN (fixed parameters)
987
+ iframe_html = f"""
988
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 15px; margin: 10px 0;">
989
+ <div style="background: rgba(255,255,255,0.95); color: #333; padding: 15px; border-radius: 8px; margin-bottom: 15px; font-size: 14px;">
990
+ <strong>🌐 Panorama 360° của bạn</strong><br>
991
+ Khám phá không gian trước khi phân tích layout. Sử dụng chuột để xoay, scroll để zoom.
992
+ </div>
993
+
994
+ <iframe
995
+ width="100%"
996
+ height="400"
997
+ allowfullscreen
998
+ style="border: none; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.3);"
999
+ src="https://cdn.pannellum.org/2.5/pannellum.htm#panorama={data_url}&autoLoad=true&autoRotate=-2">
1000
+ </iframe>
1001
+
1002
+ <div style="text-align: center; margin-top: 15px; color: white;">
1003
+ <p style="margin: 5px 0;">💡 <strong>Mẹo sử dụng:</strong></p>
1004
+ <p style="margin: 5px 0; font-size: 13px;">• Di chuyển chuột để xoay 360° • Scroll để zoom • Nhấn fullscreen để xem toàn màn hình</p>
1005
+ </div>
1006
+ </div>
1007
+ """
1008
+
1009
+ return iframe_html
1010
+
1011
+ except Exception as e:
1012
+ logger.warning(f"Could not create panorama viewer: {e}")
1013
+ return f"""
1014
+ <div style="text-align: center; padding: 50px; background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%); border-radius: 10px; color: white;">
1015
+ <h3>⚠️ Lỗi Panorama Viewer</h3>
1016
+ <p>Không thể tải ảnh panorama. Vui lòng kiểm tra định dạng ảnh.</p>
1017
+ <p><small>Lỗi: {str(e)}</small></p>
1018
+ <p><small>Hỗ trợ: JPG, PNG, JPEG</small></p>
1019
+ </div>
1020
+ """
1021
+
1022
+ # Event handler for updating panorama viewer when image changes
1023
+ single_image.change(
1024
+ fn=update_panorama_viewer,
1025
+ inputs=[single_image],
1026
+ outputs=[panorama_viewer]
1027
+ )
1028
+
1029
+ # Initialize panorama viewer with default image on app load
1030
+ demo.load(
1031
+ fn=update_panorama_viewer,
1032
+ inputs=[single_image],
1033
+ outputs=[panorama_viewer]
1034
+ )
1035
 
1036
  # Event handlers
1037
  process_btn.click(