Update src/pages/2_ArealAI

#13
by juliajo - opened
Files changed (1) hide show
  1. src/pages/2_ArealAI +176 -0
src/pages/2_ArealAI CHANGED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import cv2
3
+ import numpy as np
4
+ import tempfile
5
+ import os
6
+ from PIL import Image
7
+ import matplotlib.pyplot as plt
8
+ from ultralytics import YOLO
9
+ import io
10
+ import pymupdf
11
+ import hashlib
12
+ from utils.object_detection import detect_resize_walls, remove_interior_walls
13
+ from utils.segmentation import predict_segments, fill_segments, segmentation_to_binary
14
+ from utils.plotting import plot_results_streamlit
15
+
16
+
17
+
18
+ MODEL_SEG_PATH = os.path.join(os.path.dirname(__file__), "../models/segment/bra_bta/best.pt")
19
+ MODEL_OBJ_PATH = os.path.join(os.path.dirname(__file__), "../models/detect/walls/best.pt")
20
+
21
+ model_seg = YOLO(MODEL_SEG_PATH)
22
+ model_obj = YOLO(MODEL_OBJ_PATH)
23
+
24
+
25
+ def file_hash(file_obj):
26
+ file_obj.seek(0)
27
+ content = file_obj.read()
28
+ file_obj.seek(0)
29
+ return hashlib.md5(content).hexdigest()
30
+
31
+ def draw_bbox(img, bbox, wall_id, color=(0, 0, 255), thickness=2):
32
+ x1, y1, x2, y2 = bbox
33
+ cv2.rectangle(img, (x1, y1), (x2, y2), color, thickness)
34
+ center_x = int((x1 + x2) / 2)
35
+ text_y = y1 - 10
36
+ text_y = max(text_y, 30)
37
+
38
+
39
+ cv2.putText(
40
+ img, str(wall_id), (center_x - 20, text_y),
41
+ fontFace=cv2.FONT_HERSHEY_SIMPLEX,
42
+ fontScale=2.5,
43
+ color=(0, 0, 0),
44
+ thickness=4,
45
+ lineType=cv2.LINE_AA
46
+ )
47
+
48
+ return img
49
+
50
+
51
+ def calculate_BRA(pixels_per_meter, filled_masks):
52
+ """Calculate the total area of the building and display the steps"""
53
+ results = []
54
+
55
+ for i, mask in enumerate(filled_masks):
56
+ pixel_area = np.sum(mask > 0)
57
+ sqm_area = pixel_area / (pixels_per_meter ** 2)
58
+
59
+ results.append({
60
+ "Plan": f"Plan {i+1}",
61
+ "Pixel Area": pixel_area,
62
+ "Pixels per meter": pixels_per_meter,
63
+ "Area (m²)": sqm_area
64
+ })
65
+
66
+ st.markdown(f"""
67
+ ### Calculation for Plan {i+1}
68
+ - **Pixel area**: `{pixel_area}` pixels
69
+ - **Pixels per meter**: `{pixels_per_meter:.2f}` px/m
70
+ - **BRA** = pixel_area / (pixels_per_meter²)
71
+ - **Result**: **{sqm_area:.2f} m²**
72
+ """)
73
+
74
+ return results
75
+
76
+
77
+
78
+
79
+ st.title("Usable Floorplan (BRA) Area Calculation")
80
+ st.write(
81
+ """
82
+ This module analyzes floorplan drawings and calculates the building's usable floor area (BRA) using AI-based segmentation.
83
+
84
+ Upload a simple floorplan drawing, then select a **reference wall** for which the **real-world length is known**. This reference is used to scale the drawing and estimate the area in square meters.
85
+
86
+ **Note**: This tool is best suited for clean, top-down floorplan images with visible walls. Complex or cluttered drawings may produce inaccurate results.
87
+ """
88
+ )
89
+
90
+ st.subheader("Upload a floorplan drawing")
91
+
92
+ uploaded_files = st.file_uploader(
93
+ "Upload",
94
+ type=["jpg", "png", "jpeg", "pdf"],
95
+ accept_multiple_files=True
96
+ )
97
+
98
+ if uploaded_files:
99
+
100
+ for idx, uploaded_file in enumerate(uploaded_files):
101
+
102
+ file_type = uploaded_file.type
103
+
104
+ if file_type == "application/pdf":
105
+ pdf_bytes = uploaded_file.read()
106
+ doc = pymupdf.open(stream=pdf_bytes, filetype="pdf")
107
+
108
+ page = doc.load_page(0)
109
+ pix = page.get_pixmap(dpi=300)
110
+ image = Image.open(io.BytesIO(pix.tobytes("png")))
111
+ else:
112
+ image = Image.open(uploaded_file)
113
+
114
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as tmp_file:
115
+ image.save(tmp_file.name, format="JPEG")
116
+ image_path = tmp_file.name
117
+
118
+ with st.sidebar:
119
+ st.image(image, caption=f"Uploaded Image", use_container_width=True)
120
+
121
+
122
+ results = predict_segments(model_seg, image_path)
123
+ masks_resized = segmentation_to_binary(results)
124
+ original_image = cv2.imread(image_path)
125
+
126
+ # Generate a unique cache key per image
127
+ wall_cache_key = f"walls_{file_hash(uploaded_file)}"
128
+
129
+ if wall_cache_key not in st.session_state:
130
+ detected_boxes = detect_resize_walls(image_path, model_obj)
131
+ filtered_bboxes = remove_interior_walls(masks_resized, detected_boxes)
132
+ st.session_state[wall_cache_key] = filtered_bboxes
133
+ else:
134
+ filtered_bboxes = st.session_state[wall_cache_key]
135
+
136
+
137
+ img_with_ids = cv2.imread(image_path)
138
+ wall_data = []
139
+
140
+ for idx, bbox in enumerate(filtered_bboxes):
141
+ x1, y1, x2, y2 = bbox
142
+ length_x = x2 - x1
143
+ length_y = y2 - y1
144
+ wall_data.append({"id": idx, "bbox": bbox, "length_x": length_x, "length_y": length_y})
145
+ img_with_ids = draw_bbox(img_with_ids, bbox, wall_id=idx)
146
+
147
+ st.image(img_with_ids, caption="Click on the ID below to select your reference wall")
148
+
149
+ filled_masks = [fill_segments(mask, filtered_bboxes) for mask in masks_resized]
150
+
151
+
152
+ wall_options = [f"Wall {w['id']}: {w['length_x']}px x {w['length_y']}px" for w in wall_data]
153
+ selected_wall_label = st.selectbox("Select a reference wall by ID", wall_options)
154
+ selected_wall = wall_data[wall_options.index(selected_wall_label)]
155
+
156
+ longest_side_px = max(selected_wall["length_x"], selected_wall["length_y"])
157
+
158
+ line_length_meters = st.number_input("Enter the known length of the wall (in meters):", min_value=0.1, step=0.1)
159
+
160
+ run_detection = st.button("Calculate usable floor area BRA")
161
+
162
+ if run_detection:
163
+ if line_length_meters > 0:
164
+ pixels_per_meter = longest_side_px / line_length_meters
165
+
166
+ calculate_BRA(pixels_per_meter, filled_masks)
167
+
168
+
169
+ st.subheader("Segmented Area")
170
+
171
+ fig = plot_results_streamlit(image_path, filled_masks)
172
+ st.pyplot(fig)
173
+
174
+
175
+
176
+