ragebhanukiran commited on
Commit
b338c44
·
verified ·
1 Parent(s): 4e549b3

initial commit

Browse files
Files changed (27) hide show
  1. README.md +0 -0
  2. deployment/app.py +131 -0
  3. deployment/outputs/seq3-drone_0000010_jpg.rf.1d1c9cb09ed588cbe7fa1eecc0947021.jpg +0 -0
  4. deployment/outputs/seq3-drone_0000018_jpg.rf.bd265e7b0f05b9d031e42f912e788da1.jpg +0 -0
  5. deployment/outputs/seq3-drone_0000155_jpg.rf.a34f65f74dcd9fe48304ac8cb3cf677d.jpg +0 -0
  6. deployment/outputs/seq3-drone_0002496_jpg.rf.af29baeec76b255e74d1497d516ff654.jpg +0 -0
  7. deployment/static/style.css +44 -0
  8. deployment/static/uploads/1_png.rf.2543efb6c056bc6a60b2946ecc4ce008.jpg +0 -0
  9. deployment/static/uploads/2_jpeg_jpg.rf.e89231a86b8a496a721d7dbe9a958206.jpg +0 -0
  10. deployment/static/uploads/Figure_11.png +0 -0
  11. deployment/static/uploads/_-_-41-_png_jpg.rf.c9eb095ec6cae86d10d90e7d2c2f920c.jpg +0 -0
  12. deployment/static/uploads/result.jpg +0 -0
  13. deployment/static/uploads/seq3-drone_0000010_jpg.rf.1d1c9cb09ed588cbe7fa1eecc0947021.jpg +0 -0
  14. deployment/static/uploads/seq3-drone_0000018_jpg.rf.bd265e7b0f05b9d031e42f912e788da1.jpg +0 -0
  15. deployment/static/uploads/seq3-drone_0000155_jpg.rf.a34f65f74dcd9fe48304ac8cb3cf677d.jpg +0 -0
  16. deployment/static/uploads/seq3-drone_0000606_jpg.rf.f13a5ae4dac612b023ff93fb3256139a.jpg +0 -0
  17. deployment/static/uploads/seq3-drone_0002496_jpg.rf.af29baeec76b255e74d1497d516ff654.jpg +0 -0
  18. deployment/templates/index.html +76 -0
  19. models/fasterrcnn_model.pth +3 -0
  20. requirements.txt +9 -0
  21. scripts/__pycache__/dataset.cpython-311.pyc +0 -0
  22. scripts/dataset.py +57 -0
  23. scripts/inference.py +143 -0
  24. scripts/train.py +127 -0
  25. static/uploads/result.jpg +0 -0
  26. static/uploads/seq3-drone_0000018_jpg.rf.bd265e7b0f05b9d031e42f912e788da1.jpg +0 -0
  27. static/uploads/seq3-drone_0000812_jpg.rf.8deaa8bc13cb2daa0535fea033dd1482.jpg +0 -0
README.md ADDED
File without changes
deployment/app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import torchvision.transforms as transforms
4
+ import torchvision.models.detection as detection
5
+ from flask import Flask, request, render_template, send_from_directory, url_for, Response
6
+ from PIL import Image
7
+ import cv2
8
+ import numpy as np
9
+
10
+ # Initialize Flask app
11
+ app = Flask(__name__)
12
+ UPLOAD_FOLDER = os.path.abspath(os.path.join("deployment", "static", "uploads"))
13
+ OUTPUT_FOLDER = os.path.abspath(os.path.join("deployment", "outputs"))
14
+
15
+ # Ensure directories exist
16
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
17
+ os.makedirs(OUTPUT_FOLDER, exist_ok=True)
18
+
19
+ # Define class names
20
+ CLASS_NAMES = {
21
+ 0: "vehicle", 1: "bicycle", 2: "bus", 3: "car", 4: "lorry"
22
+ }
23
+ NUM_CLASSES = len(CLASS_NAMES) + 1 # Include background class
24
+
25
+ # Load Faster R-CNN model
26
+ def load_model(model_path, num_classes):
27
+ model = detection.fasterrcnn_resnet50_fpn(weights=None, num_classes=num_classes)
28
+ model.load_state_dict(torch.load(model_path, map_location='cpu'))
29
+ model.eval()
30
+ return model
31
+
32
+ model_path = os.path.join("models", "fasterrcnn_model.pth")
33
+ model = load_model(model_path, NUM_CLASSES)
34
+
35
+ # Image preprocessing
36
+ def preprocess_image(image):
37
+ transform = transforms.Compose([transforms.ToTensor()])
38
+ return transform(image).unsqueeze(0)
39
+
40
+ # Draw predictions
41
+ def draw_predictions(image, prediction):
42
+ boxes, scores, labels = prediction['boxes'], prediction['scores'], prediction['labels']
43
+ for i in range(len(boxes)):
44
+ if scores[i] > 0.5: # Confidence threshold
45
+ x1, y1, x2, y2 = map(int, boxes[i].tolist())
46
+ class_name = CLASS_NAMES.get(labels[i].item(), f"Class {labels[i].item()}")
47
+ cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
48
+ cv2.putText(image, f"{class_name}: {scores[i]:.2f}", (x1, y1 - 10),
49
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
50
+ return image
51
+
52
+ # Home route (upload and detect)
53
+ @app.route('/', methods=['GET', 'POST'])
54
+ def upload_and_predict():
55
+ if request.method == 'POST':
56
+ file = request.files['file']
57
+ if file:
58
+ filename = file.filename
59
+ upload_path = os.path.join(UPLOAD_FOLDER, filename)
60
+ result_path = os.path.join(OUTPUT_FOLDER, filename)
61
+ file.save(upload_path)
62
+
63
+ print(f"✅ Uploaded file saved at: {upload_path}")
64
+
65
+ # Run inference
66
+ img = Image.open(upload_path).convert("RGB")
67
+ img_tensor = preprocess_image(img)
68
+
69
+ with torch.no_grad():
70
+ prediction = model(img_tensor)[0]
71
+
72
+ # Draw results
73
+ image_cv = cv2.imread(upload_path)
74
+ if image_cv is None:
75
+ print(f"❌ ERROR: OpenCV could not read {upload_path}")
76
+ else:
77
+ result_image = draw_predictions(image_cv, prediction)
78
+ cv2.imwrite(result_path, result_image)
79
+ print(f"✅ Result image saved at: {result_path}")
80
+
81
+ return render_template('index.html',
82
+ uploaded_image=url_for('uploaded_file', filename=filename),
83
+ result_image=url_for('output_file', filename=filename))
84
+
85
+ return render_template('index.html')
86
+
87
+ # Serve uploaded images correctly
88
+ @app.route('/uploads/<filename>')
89
+ def uploaded_file(filename):
90
+ return send_from_directory(os.path.abspath(UPLOAD_FOLDER), filename)
91
+
92
+ # Serve output images correctly
93
+ @app.route('/outputs/<filename>')
94
+ def output_file(filename):
95
+ return send_from_directory(os.path.abspath(OUTPUT_FOLDER), filename)
96
+
97
+
98
+ # Real-time webcam detection
99
+ def generate_frames():
100
+ cap = cv2.VideoCapture(0)
101
+ while cap.isOpened():
102
+ success, frame = cap.read()
103
+ if not success:
104
+ break
105
+
106
+ # Convert frame and preprocess
107
+ img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
108
+ img_tensor = preprocess_image(img)
109
+
110
+ # Run inference
111
+ with torch.no_grad():
112
+ prediction = model(img_tensor)[0]
113
+
114
+ # Draw results
115
+ frame = draw_predictions(frame, prediction)
116
+
117
+ # Convert to JPEG
118
+ _, buffer = cv2.imencode('.jpg', frame)
119
+ frame_bytes = buffer.tobytes()
120
+
121
+ yield (b'--frame\r\n'
122
+ b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
123
+
124
+ cap.release()
125
+
126
+ @app.route('/video_feed')
127
+ def video_feed():
128
+ return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
129
+
130
+ if __name__ == '__main__':
131
+ app.run(debug=True)
deployment/outputs/seq3-drone_0000010_jpg.rf.1d1c9cb09ed588cbe7fa1eecc0947021.jpg ADDED
deployment/outputs/seq3-drone_0000018_jpg.rf.bd265e7b0f05b9d031e42f912e788da1.jpg ADDED
deployment/outputs/seq3-drone_0000155_jpg.rf.a34f65f74dcd9fe48304ac8cb3cf677d.jpg ADDED
deployment/outputs/seq3-drone_0002496_jpg.rf.af29baeec76b255e74d1497d516ff654.jpg ADDED
deployment/static/style.css ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ font-family: Arial, sans-serif;
3
+ background-color: #f4f4f4;
4
+ text-align: center;
5
+ padding: 20px;
6
+ }
7
+
8
+ h2 {
9
+ color: #333;
10
+ }
11
+
12
+ form {
13
+ background: white;
14
+ padding: 20px;
15
+ border-radius: 8px;
16
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
17
+ display: inline-block;
18
+ margin: 20px;
19
+ }
20
+
21
+ input[type="file"] {
22
+ margin: 10px 0;
23
+ }
24
+
25
+ button {
26
+ background-color: #28a745;
27
+ color: white;
28
+ border: none;
29
+ padding: 10px 15px;
30
+ border-radius: 5px;
31
+ cursor: pointer;
32
+ font-size: 16px;
33
+ }
34
+
35
+ button:hover {
36
+ background-color: #218838;
37
+ }
38
+
39
+ img {
40
+ margin-top: 15px;
41
+ max-width: 80%;
42
+ border-radius: 8px;
43
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
44
+ }
deployment/static/uploads/1_png.rf.2543efb6c056bc6a60b2946ecc4ce008.jpg ADDED
deployment/static/uploads/2_jpeg_jpg.rf.e89231a86b8a496a721d7dbe9a958206.jpg ADDED
deployment/static/uploads/Figure_11.png ADDED
deployment/static/uploads/_-_-41-_png_jpg.rf.c9eb095ec6cae86d10d90e7d2c2f920c.jpg ADDED
deployment/static/uploads/result.jpg ADDED
deployment/static/uploads/seq3-drone_0000010_jpg.rf.1d1c9cb09ed588cbe7fa1eecc0947021.jpg ADDED
deployment/static/uploads/seq3-drone_0000018_jpg.rf.bd265e7b0f05b9d031e42f912e788da1.jpg ADDED
deployment/static/uploads/seq3-drone_0000155_jpg.rf.a34f65f74dcd9fe48304ac8cb3cf677d.jpg ADDED
deployment/static/uploads/seq3-drone_0000606_jpg.rf.f13a5ae4dac612b023ff93fb3256139a.jpg ADDED
deployment/static/uploads/seq3-drone_0002496_jpg.rf.af29baeec76b255e74d1497d516ff654.jpg ADDED
deployment/templates/index.html ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Faster R-CNN Object Detection</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ text-align: center;
11
+ background-color: #f4f4f4;
12
+ padding: 20px;
13
+ }
14
+ h1 {
15
+ color: #333;
16
+ }
17
+ .container {
18
+ background: white;
19
+ padding: 20px;
20
+ border-radius: 10px;
21
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
22
+ max-width: 600px;
23
+ margin: auto;
24
+ }
25
+ input[type="file"] {
26
+ margin: 20px 0;
27
+ }
28
+ .image-container {
29
+ margin-top: 20px;
30
+ }
31
+ img {
32
+ max-width: 100%;
33
+ border: 2px solid #ddd;
34
+ border-radius: 5px;
35
+ }
36
+ .btn {
37
+ display: inline-block;
38
+ padding: 10px 20px;
39
+ font-size: 16px;
40
+ background-color: #007bff;
41
+ color: white;
42
+ border: none;
43
+ cursor: pointer;
44
+ border-radius: 5px;
45
+ margin-top: 10px;
46
+ }
47
+ .btn:hover {
48
+ background-color: #0056b3;
49
+ }
50
+ </style>
51
+ </head>
52
+ <body>
53
+ <div class="container">
54
+ <h1>Faster R-CNN Object Detection</h1>
55
+
56
+ <form action="/" method="post" enctype="multipart/form-data">
57
+ <input type="file" name="file" required>
58
+ <button type="submit" class="btn">Upload & Detect</button>
59
+ </form>
60
+
61
+ {% if uploaded_image %}
62
+ <div class="image-container">
63
+ <h2>Uploaded Image</h2>
64
+ <img src="{{ uploaded_image }}" alt="Uploaded Image">
65
+ </div>
66
+ {% endif %}
67
+
68
+ {% if result_image %}
69
+ <div class="image-container">
70
+ <h2>Detection Results</h2>
71
+ <img src="{{ result_image }}" alt="Detected Image">
72
+ </div>
73
+ {% endif %}
74
+ </div>
75
+ </body>
76
+ </html>
models/fasterrcnn_model.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:115326c8ea7e52e62ed0d14c5fa5d9ee67bdeac5324f8a0a559cd1b29d95bba6
3
+ size 165811943
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ torchaudio
4
+ pycocotools
5
+ matplotlib
6
+ numpy
7
+ pandas
8
+ opencv-python
9
+ tqdm
scripts/__pycache__/dataset.cpython-311.pyc ADDED
Binary file (3.52 kB). View file
 
scripts/dataset.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import torchvision.transforms as transforms
4
+ from torch.utils.data import Dataset
5
+ from pycocotools.coco import COCO
6
+ from PIL import Image
7
+
8
+ class COCODataset(Dataset):
9
+ def __init__(self, root, annotation_file, transforms=None):
10
+ self.root = root
11
+ self.coco = COCO(annotation_file)
12
+ self.transforms = transforms
13
+
14
+ self.image_ids = list(self.coco.imgs.keys())
15
+
16
+ def __getitem__(self, idx):
17
+ image_id = self.image_ids[idx]
18
+ image_info = self.coco.imgs[image_id]
19
+ image_path = os.path.join(self.root, image_info["file_name"])
20
+
21
+ image = Image.open(image_path).convert("RGB")
22
+
23
+ annotations = self.coco.loadAnns(self.coco.getAnnIds(imgIds=image_id))
24
+
25
+ boxes = []
26
+ labels = []
27
+
28
+ for ann in annotations:
29
+ xmin = ann["bbox"][0]
30
+ ymin = ann["bbox"][1]
31
+ width = ann["bbox"][2]
32
+ height = ann["bbox"][3]
33
+
34
+ boxes.append([xmin, ymin, xmin + width, ymin + height])
35
+ labels.append(ann["category_id"]) # Ensure category_id starts from 1
36
+
37
+ if len(boxes) == 0:
38
+ boxes = torch.zeros((0, 4), dtype=torch.float32)
39
+ labels = torch.zeros((0,), dtype=torch.int64)
40
+ else:
41
+ boxes = torch.tensor(boxes, dtype=torch.float32)
42
+ labels = torch.tensor(labels, dtype=torch.int64)
43
+
44
+ target = {"boxes": boxes, "labels": labels, "image_id": torch.tensor([image_id])}
45
+
46
+ if self.transforms:
47
+ image = self.transforms(image)
48
+
49
+ return image, target
50
+
51
+ def __len__(self):
52
+ return len(self.image_ids)
53
+
54
+ def get_transforms():
55
+ return transforms.Compose([
56
+ transforms.ToTensor()
57
+ ])
scripts/inference.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision.transforms as transforms
3
+ import torchvision.models.detection as detection
4
+ from PIL import Image
5
+ import cv2
6
+ import numpy as np
7
+
8
+ # Define class names
9
+ CLASS_NAMES = {
10
+ 0: "vehicle", 1: "bicycle", 2: "bus", 3: "car", 4: "lorry"
11
+ }
12
+ NUM_CLASSES = len(CLASS_NAMES) + 1 # Include background class
13
+
14
+ # Global flag to stop detection when clicking the window
15
+ stop_detection = False
16
+
17
+ # Load Faster R-CNN model
18
+ def load_model(model_path, num_classes):
19
+ model = detection.fasterrcnn_resnet50_fpn(weights=None, num_classes=num_classes)
20
+
21
+ # Load the trained model
22
+ checkpoint = torch.load(model_path, map_location="cpu")
23
+ model.load_state_dict(checkpoint)
24
+
25
+ model.eval()
26
+ return model
27
+
28
+ # Transform input image
29
+ def preprocess_image(image):
30
+ transform = transforms.Compose([transforms.ToTensor()])
31
+ return transform(image).unsqueeze(0)
32
+
33
+ # Run inference on an image
34
+ def run_inference_on_image(image_path, model):
35
+ img = Image.open(image_path).convert("RGB")
36
+ img_tensor = preprocess_image(img)
37
+
38
+ with torch.no_grad():
39
+ prediction = model(img_tensor)[0]
40
+
41
+ draw_predictions(image_path, prediction)
42
+
43
+ # Draw predictions on an image
44
+ def draw_predictions(image_path, prediction):
45
+ image = cv2.imread(image_path)
46
+ boxes, scores, labels = prediction['boxes'], prediction['scores'], prediction['labels']
47
+
48
+ for i in range(len(boxes)):
49
+ if scores[i] > 0.5: # Confidence threshold
50
+ x1, y1, x2, y2 = map(int, boxes[i].tolist())
51
+ class_id = labels[i].item()
52
+ class_name = CLASS_NAMES.get(class_id, f"Class {class_id}")
53
+ cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
54
+ cv2.putText(image, f"{class_name}: {scores[i]:.2f}", (x1, y1 - 10),
55
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
56
+
57
+ cv2.imshow("Detection Result", image)
58
+ cv2.waitKey(0)
59
+ cv2.destroyAllWindows()
60
+
61
+ # Mouse click event function to stop real-time detection
62
+ def stop_real_time_detection(event, x, y, flags, param):
63
+ global stop_detection
64
+ if event == cv2.EVENT_LBUTTONDOWN: # Detect left mouse button click
65
+ stop_detection = True
66
+
67
+ # Real-time detection with webcam
68
+ def real_time_detection(model):
69
+ global stop_detection
70
+ stop_detection = False # Reset flag before starting detection
71
+
72
+ cap = cv2.VideoCapture(0)
73
+ if not cap.isOpened():
74
+ print("❌ Error: Could not open webcam.")
75
+ return
76
+
77
+ print("🎥 Starting real-time object detection. Click the window to close.")
78
+
79
+ cv2.namedWindow("Real-time Detection") # Name the OpenCV window
80
+ cv2.setMouseCallback("Real-time Detection", stop_real_time_detection) # Set mouse click callback
81
+
82
+ while True:
83
+ ret, frame = cap.read()
84
+ if not ret:
85
+ print("❌ Error: Failed to capture frame.")
86
+ break
87
+
88
+ img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
89
+ img_tensor = preprocess_image(img)
90
+
91
+ with torch.no_grad():
92
+ prediction = model(img_tensor)[0]
93
+
94
+ draw_predictions_live(frame, prediction)
95
+
96
+ cv2.imshow("Real-time Detection", frame)
97
+
98
+ # FIX: Process window events so OpenCV does not freeze
99
+ if cv2.waitKey(1) & 0xFF == ord('q'): # Press 'q' to exit (optional)
100
+ break
101
+
102
+ if stop_detection: # If window is clicked, stop detection
103
+ print("🛑 Stopping real-time detection...")
104
+ break
105
+
106
+ cap.release()
107
+ cv2.destroyAllWindows() # FIX: Close OpenCV windows properly
108
+ cv2.waitKey(1) # FIX: Ensure window is destroyed
109
+
110
+ # Draw predictions on live video feed
111
+ def draw_predictions_live(frame, prediction):
112
+ boxes, scores, labels = prediction['boxes'], prediction['scores'], prediction['labels']
113
+
114
+ for i in range(len(boxes)):
115
+ if scores[i] > 0.5:
116
+ x1, y1, x2, y2 = map(int, boxes[i].tolist())
117
+ class_id = labels[i].item()
118
+ class_name = CLASS_NAMES.get(class_id, f"Class {class_id}")
119
+ cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
120
+ cv2.putText(frame, f"{class_name}: {scores[i]:.2f}", (x1, y1 - 10),
121
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
122
+
123
+ if __name__ == "__main__":
124
+ model = load_model("models/fasterrcnn_model.pth", NUM_CLASSES)
125
+
126
+ while True:
127
+ print("\nOptions:")
128
+ print("1 - Run object detection on an image")
129
+ print("2 - Run real-time object detection (Click to exit)")
130
+ print("q - Quit")
131
+
132
+ choice = input("Enter your choice: ").strip().lower()
133
+
134
+ if choice == "1":
135
+ image_path = input("Enter the path of the test image: ").strip()
136
+ run_inference_on_image(image_path, model)
137
+ elif choice == "2":
138
+ real_time_detection(model)
139
+ elif choice == "q":
140
+ print("👋 Exiting program.")
141
+ break
142
+ else:
143
+ print("⚠️ Invalid choice! Please enter '1', '2', or 'q'.")
scripts/train.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision
3
+ import matplotlib.pyplot as plt
4
+ from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
5
+ from torchvision.models.detection import fasterrcnn_resnet50_fpn, FasterRCNN_ResNet50_FPN_Weights
6
+ from torch.utils.data import DataLoader
7
+ from torchmetrics.detection.mean_ap import MeanAveragePrecision
8
+ from torchvision import transforms as T
9
+ from scripts.dataset import COCODataset, get_transforms
10
+
11
+ # Paths to dataset
12
+ DATASET_ROOT = "dataset/train"
13
+ ANNOTATION_FILE = "dataset/annotations/instances_train.json"
14
+
15
+ # Function to get the model with fixed NMS
16
+ def get_model(num_classes):
17
+ model = fasterrcnn_resnet50_fpn(weights=FasterRCNN_ResNet50_FPN_Weights.COCO_V1)
18
+
19
+ # Replace the classifier with a new one (custom num_classes)
20
+ in_features = model.roi_heads.box_predictor.cls_score.in_features
21
+ model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
22
+
23
+ # Fix excessive bounding boxes by lowering NMS
24
+ model.rpn.nms_thresh = 0.3 # Default ~0.7
25
+ model.roi_heads.nms_thresh = 0.3
26
+
27
+ return model
28
+
29
+ # Define dataset and data loader
30
+ dataset = COCODataset(root=DATASET_ROOT, annotation_file=ANNOTATION_FILE, transforms=get_transforms())
31
+ dataloader = DataLoader(dataset, batch_size=4, shuffle=True, collate_fn=lambda batch: tuple(zip(*batch)))
32
+
33
+ # Device configuration
34
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
35
+
36
+ # Define the number of classes (5 classes + 1 background)
37
+ num_classes = 6
38
+ model = get_model(num_classes).to(device)
39
+
40
+ # Optimizer and learning rate scheduler
41
+ params = [p for p in model.parameters() if p.requires_grad]
42
+ optimizer = torch.optim.AdamW(params, lr=0.002, weight_decay=0.0001)
43
+ lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)
44
+
45
+ # Initialize Mean Average Precision (mAP) metric
46
+ metric = MeanAveragePrecision()
47
+
48
+ # Function to evaluate the model
49
+ def evaluate_model(model, dataloader, device):
50
+ model.eval()
51
+ metric.reset()
52
+
53
+ with torch.no_grad():
54
+ for images, targets in dataloader:
55
+ images = [img.to(device) for img in images]
56
+ targets = [{k: v.to(device) for k, v in t.items()} for t in targets]
57
+
58
+ outputs = model(images)
59
+ preds = [{"boxes": o["boxes"].cpu(), "scores": o["scores"].cpu(), "labels": o["labels"].cpu()} for o in outputs]
60
+ gts = [{"boxes": t["boxes"].cpu(), "labels": t["labels"].cpu()} for t in targets]
61
+
62
+ metric.update(preds, gts)
63
+
64
+ result = metric.compute()
65
+ return result["map"].item(), result["map_50"].item(), result["map_75"].item()
66
+
67
+ # Lists to store training loss and accuracy
68
+ losses_list = []
69
+ mAP_list = []
70
+ mAP50_list = []
71
+ mAP75_list = []
72
+
73
+ # Training loop
74
+ num_epochs = 15
75
+ for epoch in range(num_epochs):
76
+ model.train()
77
+ epoch_loss = 0.0
78
+
79
+ for images, targets in dataloader:
80
+ images = [image.to(device) for image in images]
81
+ targets = [{k: v.to(device) for k, v in target.items()} for target in targets]
82
+
83
+ optimizer.zero_grad()
84
+ loss_dict = model(images, targets)
85
+ losses = sum(loss for loss in loss_dict.values())
86
+ epoch_loss += losses.item()
87
+
88
+ losses.backward()
89
+ torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=2.0)
90
+ optimizer.step()
91
+
92
+ lr_scheduler.step()
93
+ losses_list.append(epoch_loss)
94
+
95
+ # Compute mAP
96
+ mAP, mAP50, mAP75 = evaluate_model(model, dataloader, device)
97
+ mAP_list.append(mAP)
98
+ mAP50_list.append(mAP50)
99
+ mAP75_list.append(mAP75)
100
+
101
+ print(f"Epoch {epoch+1}/{num_epochs}, Loss: {epoch_loss:.4f}")
102
+ print(f"Epoch {epoch+1}: mAP: {mAP:.4f}, mAP@50: {mAP50:.4f}, mAP@75: {mAP75:.4f}")
103
+
104
+ # Save model
105
+ torch.save(model.state_dict(), "models/fasterrcnn_model.pth")
106
+ print("Training complete! Model saved as 'fasterrcnn_model.pth'.")
107
+
108
+ # Plot Loss Graph
109
+ plt.figure(figsize=(10, 5))
110
+ plt.plot(range(1, num_epochs + 1), losses_list, marker='o', linestyle='-')
111
+ plt.xlabel("Epochs")
112
+ plt.ylabel("Loss")
113
+ plt.title("Training Loss over Epochs")
114
+ plt.grid()
115
+ plt.show()
116
+
117
+ # Plot mAP Graphs
118
+ plt.figure(figsize=(10, 5))
119
+ plt.plot(range(1, num_epochs + 1), mAP_list, marker='o', linestyle='-', label="mAP")
120
+ plt.plot(range(1, num_epochs + 1), mAP50_list, marker='s', linestyle='-', label="mAP@50")
121
+ plt.plot(range(1, num_epochs + 1), mAP75_list, marker='d', linestyle='-', label="mAP@75")
122
+ plt.xlabel("Epochs")
123
+ plt.ylabel("Accuracy")
124
+ plt.title("mAP over Epochs")
125
+ plt.legend()
126
+ plt.grid()
127
+ plt.show()
static/uploads/result.jpg ADDED
static/uploads/seq3-drone_0000018_jpg.rf.bd265e7b0f05b9d031e42f912e788da1.jpg ADDED
static/uploads/seq3-drone_0000812_jpg.rf.8deaa8bc13cb2daa0535fea033dd1482.jpg ADDED