Shreyansh Khaitan commited on
Commit
47526b2
·
unverified ·
1 Parent(s): 7eaf7f9
Files changed (6) hide show
  1. .DS_Store +0 -0
  2. Dockerfile +17 -0
  3. app.py +99 -0
  4. requirements.txt +3 -0
  5. static/style.css +31 -0
  6. 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>