Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	
		Shreyansh Khaitan
		
	commited on
		
		
					upload
Browse files- .DS_Store +0 -0
- Dockerfile +17 -0
- app.py +99 -0
- requirements.txt +3 -0
- static/style.css +31 -0
- templates/index.html +29 -0
    	
        .DS_Store
    ADDED
    
    | Binary file (6.15 kB). View file | 
|  | 
    	
        Dockerfile
    ADDED
    
    | @@ -0,0 +1,17 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            # Use Python as the base image
         | 
| 2 | 
            +
            FROM python:3.8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # Set the working directory
         | 
| 5 | 
            +
            WORKDIR /app
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            # Copy the project files
         | 
| 8 | 
            +
            COPY . /app
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            # Install dependencies
         | 
| 11 | 
            +
            RUN pip install --no-cache-dir -r requirements.txt
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # Expose port 7860
         | 
| 14 | 
            +
            EXPOSE 7860
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            # Run the Flask app
         | 
| 17 | 
            +
            CMD ["python", "app.py"]
         | 
    	
        app.py
    ADDED
    
    | @@ -0,0 +1,99 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            from flask import Flask, request, render_template, send_file
         | 
| 2 | 
            +
            from inference_sdk import InferenceHTTPClient
         | 
| 3 | 
            +
            from PIL import Image, ImageDraw, ImageFont
         | 
| 4 | 
            +
            import os
         | 
| 5 | 
            +
            from collections import defaultdict
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            app = Flask(__name__)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # Securely get API key from Hugging Face Secrets
         | 
| 10 | 
            +
            API_KEY = os.getenv("ROBOFLOW_API_KEY")  
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # Initialize the Roboflow client
         | 
| 13 | 
            +
            CLIENT = InferenceHTTPClient(
         | 
| 14 | 
            +
                api_url="https://detect.roboflow.com",
         | 
| 15 | 
            +
                api_key=API_KEY
         | 
| 16 | 
            +
            )
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            # Model settings
         | 
| 19 | 
            +
            MODEL_ID = "hvacsym/5"
         | 
| 20 | 
            +
            CONFIDENCE_THRESHOLD = 30  # Confidence threshold for filtering predictions
         | 
| 21 | 
            +
            GRID_SIZE = (4, 4)  # 4x4 segmentation
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            def process_image(image_path):
         | 
| 24 | 
            +
                """Processes an uploaded image and returns the final image with bounding boxes & symbol counts."""
         | 
| 25 | 
            +
                original_image = Image.open(image_path)
         | 
| 26 | 
            +
                width, height = original_image.size
         | 
| 27 | 
            +
                seg_w, seg_h = width // GRID_SIZE[1], height // GRID_SIZE[0]
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                # Create a copy of the image for bounding boxes
         | 
| 30 | 
            +
                final_image = original_image.copy()
         | 
| 31 | 
            +
                draw_final = ImageDraw.Draw(final_image)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                # Load font
         | 
| 34 | 
            +
                try:
         | 
| 35 | 
            +
                    font = ImageFont.truetype("arial.ttf", 15)
         | 
| 36 | 
            +
                except:
         | 
| 37 | 
            +
                    font = ImageFont.load_default()
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # Dictionary for total counts
         | 
| 40 | 
            +
                total_counts = defaultdict(int)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # Process each segment
         | 
| 43 | 
            +
                for row in range(GRID_SIZE[0]):
         | 
| 44 | 
            +
                    for col in range(GRID_SIZE[1]):
         | 
| 45 | 
            +
                        x1, y1 = col * seg_w, row * seg_h
         | 
| 46 | 
            +
                        x2, y2 = (col + 1) * seg_w, (row + 1) * seg_h
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                        segment = original_image.crop((x1, y1, x2, y2))
         | 
| 49 | 
            +
                        segment_path = f"segment_{row}_{col}.png"
         | 
| 50 | 
            +
                        segment.save(segment_path)
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                        # Run inference
         | 
| 53 | 
            +
                        result = CLIENT.infer(segment_path, model_id=MODEL_ID)
         | 
| 54 | 
            +
                        filtered_predictions = [
         | 
| 55 | 
            +
                            pred for pred in result["predictions"] if pred["confidence"] * 100 >= CONFIDENCE_THRESHOLD
         | 
| 56 | 
            +
                        ]
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                        # Draw bounding boxes and update counts
         | 
| 59 | 
            +
                        for obj in filtered_predictions:
         | 
| 60 | 
            +
                            sx, sy, sw, sh = obj["x"], obj["y"], obj["width"], obj["height"]
         | 
| 61 | 
            +
                            class_name = obj["class"]
         | 
| 62 | 
            +
                            confidence = obj["confidence"]
         | 
| 63 | 
            +
                            total_counts[class_name] += 1
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                            # Adjust coordinates for final image
         | 
| 66 | 
            +
                            x_min, y_min = x1 + (sx - sw // 2), y1 + (sy - sh // 2)
         | 
| 67 | 
            +
                            x_max, y_max = x1 + (sx + sw // 2), y1 + (sy + sh // 2)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                            # Draw bounding box
         | 
| 70 | 
            +
                            draw_final.rectangle([x_min, y_min, x_max, y_max], outline="green", width=2)
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                            # Draw label
         | 
| 73 | 
            +
                            text = f"{class_name} {confidence:.2f}"
         | 
| 74 | 
            +
                            draw_final.text((x_min + 2, y_min - 10), text, fill="white", font=font)
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                # Save final image with bounding boxes
         | 
| 77 | 
            +
                final_image_path = "static/final_detected_image.png"
         | 
| 78 | 
            +
                final_image.save(final_image_path)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                return final_image_path, total_counts
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            @app.route("/", methods=["GET", "POST"])
         | 
| 83 | 
            +
            def index():
         | 
| 84 | 
            +
                if request.method == "POST":
         | 
| 85 | 
            +
                    # Get uploaded image
         | 
| 86 | 
            +
                    image_file = request.files["image"]
         | 
| 87 | 
            +
                    if image_file:
         | 
| 88 | 
            +
                        image_path = "static/uploaded_image.png"
         | 
| 89 | 
            +
                        image_file.save(image_path)
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                        # Process image
         | 
| 92 | 
            +
                        final_image_path, total_counts = process_image(image_path)
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                        return render_template("index.html", final_image=final_image_path, counts=total_counts)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                return render_template("index.html", final_image=None, counts=None)
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            if __name__ == "__main__":
         | 
| 99 | 
            +
                app.run(host="0.0.0.0", port=7860)
         | 
    	
        requirements.txt
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            flask
         | 
| 2 | 
            +
            pillow
         | 
| 3 | 
            +
            inference-sdk
         | 
    	
        static/style.css
    ADDED
    
    | @@ -0,0 +1,31 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            body {
         | 
| 2 | 
            +
                font-family: Arial, sans-serif;
         | 
| 3 | 
            +
                text-align: center;
         | 
| 4 | 
            +
                background-color: #f8f8f8;
         | 
| 5 | 
            +
            }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            h1 {
         | 
| 8 | 
            +
                color: #333;
         | 
| 9 | 
            +
            }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            form {
         | 
| 12 | 
            +
                margin: 20px;
         | 
| 13 | 
            +
            }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            button {
         | 
| 16 | 
            +
                background-color: #4CAF50;
         | 
| 17 | 
            +
                color: white;
         | 
| 18 | 
            +
                padding: 10px 20px;
         | 
| 19 | 
            +
                border: none;
         | 
| 20 | 
            +
                cursor: pointer;
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            button:hover {
         | 
| 24 | 
            +
                background-color: #45a049;
         | 
| 25 | 
            +
            }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            img {
         | 
| 28 | 
            +
                width: 50%;
         | 
| 29 | 
            +
                margin-top: 20px;
         | 
| 30 | 
            +
                border-radius: 5px;
         | 
| 31 | 
            +
            }
         | 
    	
        templates/index.html
    ADDED
    
    | @@ -0,0 +1,29 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html lang="en">
         | 
| 3 | 
            +
            <head>
         | 
| 4 | 
            +
                <meta charset="UTF-8">
         | 
| 5 | 
            +
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
         | 
| 6 | 
            +
                <title>HVAC Symbol Detector</title>
         | 
| 7 | 
            +
                <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
         | 
| 8 | 
            +
            </head>
         | 
| 9 | 
            +
            <body>
         | 
| 10 | 
            +
                <h1>HVAC Symbol Detector</h1>
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                <form action="/" method="POST" enctype="multipart/form-data">
         | 
| 13 | 
            +
                    <input type="file" name="image" accept="image/*" required>
         | 
| 14 | 
            +
                    <button type="submit">Upload & Detect</button>
         | 
| 15 | 
            +
                </form>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                {% if final_image %}
         | 
| 18 | 
            +
                    <h2>Processed Image</h2>
         | 
| 19 | 
            +
                    <img src="{{ final_image }}" alt="Processed Image">
         | 
| 20 | 
            +
                    
         | 
| 21 | 
            +
                    <h2>Detected Symbols</h2>
         | 
| 22 | 
            +
                    <ul>
         | 
| 23 | 
            +
                        {% for label, count in counts.items() %}
         | 
| 24 | 
            +
                            <li>{{ label }}: {{ count }}</li>
         | 
| 25 | 
            +
                        {% endfor %}
         | 
| 26 | 
            +
                    </ul>
         | 
| 27 | 
            +
                {% endif %}
         | 
| 28 | 
            +
            </body>
         | 
| 29 | 
            +
            </html>
         |