import streamlit as st import cv2 import numpy as np from PIL import Image import math from mediapipe.tasks import python from mediapipe.tasks.python import vision # ----------------------------- # CONFIG # ----------------------------- st.set_page_config( page_title="Classroom Dimension Estimator", page_icon="📏", layout="wide" ) POSE_MODEL_PATH = "pose_landmarker_lite.task" # ----------------------------- # UI STYLE # ----------------------------- st.markdown(""" """, unsafe_allow_html=True) # ----------------------------- # UTIL FUNCTIONS # ----------------------------- def calculate_distance(p1, p2): return math.sqrt((p2[0]-p1[0])**2 + (p2[1]-p1[1])**2) # ----------------------------- # ROOM DETECTION (unchanged) # ----------------------------- def estimate_room_dimensions(image): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, 50, 150) lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=100, minLineLength=100, maxLineGap=10) if lines is None: return None, None, image max_w, max_h = 0, 0 out = image.copy() for l in lines: x1, y1, x2, y2 = l[0] cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 2) length = calculate_distance((x1,y1), (x2,y2)) angle = abs(math.degrees(math.atan2(y2-y1, x2-x1))) if angle < 45 or angle > 135: max_w = max(max_w, length) else: max_h = max(max_h, length) return max_w * 0.01, max_h * 0.01, out # ----------------------------- # MEDIA PIPE TASKS (NEW) # ----------------------------- def estimate_with_person_reference(image): base_options = python.BaseOptions(model_asset_path=POSE_MODEL_PATH) options = vision.PoseLandmarkerOptions( base_options=base_options, running_mode=vision.RunningMode.IMAGE, num_poses=1 ) with vision.PoseLandmarker.create_from_options(options) as landmarker: rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) mp_image = vision.Image(image_format=vision.ImageFormat.SRGB, data=rgb) result = landmarker.detect(mp_image) if not result.pose_landmarks: return None, image lm = result.pose_landmarks[0] h, w = image.shape[:2] # TASK API = index based landmarks nose = lm[0] ankle = lm[27] head = (int(nose.x * w), int(nose.y * h)) foot = (int(ankle.x * w), int(ankle.y * h)) pixel_dist = calculate_distance(head, foot) if pixel_dist == 0: return None, image ratio = 1.7 / pixel_dist annotated = image.copy() cv2.circle(annotated, head, 6, (0,0,255), -1) cv2.circle(annotated, foot, 6, (255,0,0), -1) return ratio, annotated # ----------------------------- # STREAMLIT APP # ----------------------------- def main(): st.title("📏 Classroom Dimension Estimator") uploaded_file = st.file_uploader( "Upload classroom image", type=["jpg","jpeg","png"] ) if uploaded_file: image = Image.open(uploaded_file) image_np = np.array(image) tab1, tab2 = st.tabs(["Image", "Results"]) with tab1: st.image(image, use_column_width=True) with st.spinner("Processing..."): ratio, pose_img = estimate_with_person_reference(image_np) if ratio: st.success("Person detected → using scale reference") w, h, processed = estimate_room_dimensions(image_np) if w and h: w *= ratio h *= ratio with tab1: st.image(pose_img, caption="Pose detection") with tab2: st.metric("Width", f"{w:.2f} m") st.metric("Height", f"{h:.2f} m") st.metric("Area", f"{w*h:.2f} m²") else: st.warning("No person detected → fallback method") w, h, processed = estimate_room_dimensions(image_np) with tab2: if w and h: st.metric("Width", f"{w:.2f} m") st.metric("Height", f"{h:.2f} m") st.metric("Area", f"{w*h:.2f} m²") with tab1: st.image(processed, caption="Room detection") if __name__ == "__main__": main()