pyresearch commited on
Commit
4aadcb7
·
verified ·
1 Parent(s): 83349a6

Upload 6 files

Browse files
Files changed (7) hide show
  1. .gitattributes +1 -0
  2. Dockerfile +32 -0
  3. app.py +97 -0
  4. demo.mp4 +3 -0
  5. requirements.txt +9 -0
  6. templates/index.html +99 -0
  7. yolov8l.pt +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ demo.mp4 filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+
5
+
6
+
7
+ # Base image with Python 3.9
8
+ FROM python:3.9
9
+
10
+ # For fixing ImportError: libGL.so.1: cannot open shared object file: No such file or directory
11
+ RUN apt-get update
12
+ RUN apt install -y libgl1-mesa-glx
13
+
14
+
15
+ # Create a non-root user
16
+ RUN useradd -m -u 1000 user
17
+
18
+ # Set the working directory
19
+ WORKDIR /app
20
+
21
+ # Copy requirements.txt and install Python dependencies
22
+ COPY --chown=user ./requirements.txt requirements.txt
23
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
24
+
25
+ # Copy the rest of the application code
26
+ COPY --chown=user . /app
27
+
28
+ # Switch to the non-root user
29
+ USER user
30
+
31
+ # Command to run the FastAPI application
32
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ from fastapi import FastAPI, Request, UploadFile, File
4
+ from fastapi.responses import StreamingResponse, HTMLResponse
5
+ from fastapi.templating import Jinja2Templates
6
+ from typing import Generator
7
+ from ultralytics import YOLO
8
+ import numpy as np
9
+
10
+ app = FastAPI()
11
+ templates = Jinja2Templates(directory="templates")
12
+
13
+ # Load the YOLOv8 model
14
+ model = YOLO("yolov8l.pt")
15
+
16
+ video_path = None
17
+ cap = None
18
+ bird_count = 0
19
+ tracker_initialized = False
20
+ trackers = None
21
+
22
+ @app.post("/upload_video/")
23
+ async def upload_video(file: UploadFile = File(...)):
24
+ global cap, tracker_initialized, trackers
25
+
26
+ # Save uploaded video file
27
+ file_location = f"uploads/{file.filename}"
28
+ with open(file_location, "wb") as f:
29
+ f.write(file.file.read())
30
+
31
+ # Open the uploaded video file
32
+ cap = cv2.VideoCapture(file_location)
33
+
34
+ # Reset tracker and counter
35
+ tracker_initialized = False
36
+ trackers = None
37
+
38
+ return {"info": f"file '{file.filename}' saved at '{file_location}'"}
39
+
40
+ def process_video() -> Generator[bytes, None, None]:
41
+ global bird_count, tracker_initialized, trackers, cap
42
+ while cap.isOpened():
43
+ success, frame = cap.read()
44
+
45
+ if success:
46
+ frame_height, frame_width = frame.shape[:2]
47
+ if not tracker_initialized:
48
+ results = model(frame)
49
+ detections = results[0].boxes.data.cpu().numpy()
50
+ bird_results = [detection for detection in detections if int(detection[5]) == 14]
51
+
52
+ try:
53
+ trackers = cv2.legacy.MultiTracker_create()
54
+ except AttributeError:
55
+ trackers = cv2.MultiTracker_create()
56
+
57
+ for res in bird_results:
58
+ x1, y1, x2, y2, confidence, class_id = res
59
+ x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
60
+ if 0 <= x1 < frame_width and 0 <= y1 < frame_height and x2 <= frame_width and y2 <= frame_height:
61
+ bbox = (x1, y1, x2 - x1, y2 - y1)
62
+ tracker = cv2.legacy.TrackerCSRT_create() if hasattr(cv2, 'legacy') else cv2.TrackerCSRT_create()
63
+ trackers.add(tracker, frame, bbox)
64
+
65
+ bird_count = len(bird_results)
66
+ tracker_initialized = True
67
+ else:
68
+ success, boxes = trackers.update(frame)
69
+
70
+ if success:
71
+ bird_count = len(boxes)
72
+ for box in boxes:
73
+ x, y, w, h = [int(v) for v in box]
74
+ cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
75
+ cv2.putText(frame, 'bird', (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
76
+ else:
77
+ tracker_initialized = False
78
+
79
+ ret, buffer = cv2.imencode('.jpg', frame)
80
+ frame = buffer.tobytes()
81
+ yield (b'--frame\r\n'
82
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
83
+ else:
84
+ break
85
+ cap.release()
86
+
87
+ @app.get("/", response_class=HTMLResponse)
88
+ async def index(request: Request):
89
+ return templates.TemplateResponse("index.html", {"request": request, "bird_count": bird_count})
90
+
91
+ @app.get("/video_feed")
92
+ async def video_feed():
93
+ return StreamingResponse(process_video(), media_type='multipart/x-mixed-replace; boundary=frame')
94
+
95
+ if __name__ == "__main__":
96
+ import uvicorn
97
+ uvicorn.run(app, host="0.0.0.0", port=7860)
demo.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1f13ec6b61585746d6db66f057bb5aab8106a1f37b581adab03b7a14d4c98a0d
3
+ size 1399765
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ uvicorn
2
+ jinja2
3
+ opencv-python-headless
4
+ ultralytics
5
+ fastapi
6
+ uvicorn
7
+ opencv-python-headless
8
+ ultralytics
9
+ jinja2
templates/index.html ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Birds Count</title>
6
+ <style>
7
+ body, html {
8
+ margin: 0;
9
+ padding: 0;
10
+ width: 100%;
11
+ height: 100%;
12
+ display: flex;
13
+ flex-direction: column;
14
+ justify-content: space-between;
15
+ }
16
+ .header, .footer {
17
+ background-color: #216d7c;
18
+ width: 100%;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: 20px;
23
+ box-sizing: border-box;
24
+ }
25
+ .header-content {
26
+ display: flex;
27
+ align-items: center;
28
+ }
29
+ .content {
30
+ flex: 1;
31
+ display: flex;
32
+ flex-direction: column;
33
+ align-items: center;
34
+ justify-content: center;
35
+ }
36
+ img {
37
+ max-width: 100%;
38
+ height: auto;
39
+ }
40
+ .logo {
41
+ height: 40px;
42
+ margin-right: 10px;
43
+ }
44
+ .header-text {
45
+ font-size: 24px;
46
+ font-weight: bold;
47
+ color: white;
48
+ }
49
+ .footer-content {
50
+ display: flex;
51
+ flex-direction: column;
52
+ align-items: center;
53
+ }
54
+ .footer-text {
55
+ color: white;
56
+ margin-bottom: 10px;
57
+ }
58
+ .social-links img {
59
+ height: 24px;
60
+ margin: 0 5px;
61
+ }
62
+ </style>
63
+ </head>
64
+ <body>
65
+ <div class="header">
66
+ <div class="header-content">
67
+ <!-- <img src="pyresearch.png" alt="Logo" class="logo"> -->
68
+ <div class="header-text"> Bird Count Dashboard</div>
69
+ </div>
70
+ </div>
71
+
72
+ <div class="content">
73
+ <h2>Current Bird Count: {{ bird_count }}</h2>
74
+ <img src="{{ url_for('video_feed') }}" width="720" height="480">
75
+ </div>
76
+
77
+ <div class="footer">
78
+ <div class="footer-content">
79
+ <div class="footer-text"> 2024 | All rights reserved</div>
80
+ <div class="social-links">
81
+ <a href="https://www.facebook.com/Pyresearch" target="_blank">
82
+ <img src="" alt="Facebook">
83
+ </a>
84
+ <a href="https://www.youtube.com/Pyresearch" target="_blank">
85
+ <img src="" alt="YouTube">
86
+ </a>
87
+ <a href="https://www.instagram.com/pyresearch/" target="_blank">
88
+ <img src="" alt="Instagram">
89
+ </a>
90
+ <a href="https://www.tiktok.com/@pyresearch2" target="_blank">
91
+ <img src="" alt="TikTok">
92
+ </a>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </body>
97
+ </html>
98
+
99
+
yolov8l.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:18218ea4798da042d9862e6029ca9531adbd40ace19b6c9a75e2e28f1adf30cc
3
+ size 87769683