Spaces:
Sleeping
Sleeping
import streamlit as st | |
st.set_page_config(page_title="Object Volume Estimator", layout="wide") | |
import cv2 | |
import torch | |
import numpy as np | |
from PIL import Image | |
import pandas as pd | |
from ultralytics import YOLO | |
from torchvision.transforms import Compose, Resize, ToTensor, Normalize | |
# Load models | |
def load_models(): | |
yolo = YOLO("yolov8n.pt") | |
midas = torch.hub.load("intel-isl/MiDaS", "DPT_Large") | |
midas.eval() | |
transform = Compose([ | |
Resize(384), | |
ToTensor(), | |
Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) | |
]) | |
return yolo, midas, transform | |
yolo_model, midas_model, midas_transform = load_models() | |
# --- Streamlit App --- | |
st.title("Object Dimension & Volume Estimator") | |
# πΈ Image Source Selection | |
option = st.radio("Choose Image Source:", ("π€ Upload Image", "πΈ Use Camera")) | |
# Mode Selection | |
mode = st.selectbox("Select Image Type:", ["2D RGB Image", "RGB + Depth Image"]) | |
image_pil = None | |
if option == "π€ Upload Image": | |
uploaded_file = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"]) | |
if uploaded_file: | |
image_pil = Image.open(uploaded_file).convert("RGB") | |
elif option == "πΈ Use Camera": | |
camera_input = st.camera_input("Take a picture") | |
if camera_input: | |
image_pil = Image.open(camera_input).convert("RGB") | |
# Upload depth image if RGB + Depth selected | |
depth_map = None | |
if mode == "RGB + Depth Image" and image_pil is not None: | |
depth_file = st.file_uploader("Upload corresponding Depth Map (grayscale image)", type=["png", "jpg", "jpeg", "tiff"]) | |
if depth_file: | |
depth_map = np.array(Image.open(depth_file).convert("L")) | |
# Proceed if we have an image | |
if image_pil is not None: | |
# Convert to OpenCV format | |
image_cv = np.array(image_pil) | |
image_cv = cv2.cvtColor(image_cv, cv2.COLOR_RGB2BGR) | |
img_h, img_w = image_cv.shape[:2] | |
st.image(image_pil, caption="Input Image", use_container_width=True) | |
# Store detected object data | |
object_data = [] | |
# π YOLO Object Detection | |
results = yolo_model(image_cv) | |
# π Depth Estimation | |
if mode == "2D RGB Image": | |
input_tensor = midas_transform(image_pil).unsqueeze(0) | |
with torch.no_grad(): | |
estimated_depth = midas_model(input_tensor).squeeze().cpu().numpy() | |
depth_map_resized = cv2.resize(estimated_depth, (img_w, img_h)) | |
else: | |
if depth_map is not None: | |
depth_map_resized = cv2.resize(depth_map, (img_w, img_h)) | |
else: | |
st.error("Please upload a corresponding depth map for 3D images.") | |
st.stop() | |
# π― Process each detection | |
for r in results: | |
for box in r.boxes: | |
x1, y1, x2, y2 = map(int, box.xyxy[0]) | |
width = x2 - x1 | |
height = y2 - y1 | |
region = depth_map_resized[y1:y2, x1:x2] | |
if region.size == 0: | |
continue | |
depth = np.mean(region) | |
volume = round(depth * width * height, 2) | |
# Draw bounding box & label | |
cv2.rectangle(image_cv, (x1, y1), (x2, y2), (0, 255, 0), 2) | |
label = f"LΓBΓH: {depth:.2f}Γ{width}Γ{height} | V: {volume}" | |
cv2.putText(image_cv, label, (x1, y1 - 10), | |
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 2) | |
# Store data for CSV | |
object_data.append({ | |
"Length": round(depth, 2), | |
"Breadth": int(width), | |
"Height": int(height), | |
"Volume": volume | |
}) | |
# Show object details | |
st.markdown(f"**π§ Object Detected:**") | |
st.write(f"π Length Γ Breadth Γ Height: {depth:.2f} Γ {width} Γ {height}") | |
st.write(f"π¦ Estimated Volume: {volume} (relative unitsΒ³)") | |
# Show annotated image | |
result_img = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB) | |
st.image(result_img, caption="Detected Dimensions", use_container_width=True) | |
# Show table & CSV download if data exists | |
if object_data: | |
df = pd.DataFrame(object_data) | |
st.markdown("### π Detected Objects Table") | |
st.dataframe(df) | |
csv = df.to_csv(index=False).encode('utf-8') | |
st.download_button( | |
label="π₯ Download Results as CSV", | |
data=csv, | |
file_name='object_dimensions_volume.csv', | |
mime='text/csv', | |
) |