diff --git a/.gitignore b/.gitignore
index b661a1e..a28cacc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
*.pt
*.avi
*.mp4
+*.jpg
# Byte-compiled / optimized / DLL files
__pycache__/
diff --git a/README.md b/README.md
index 5608df9..1d696f7 100644
--- a/README.md
+++ b/README.md
@@ -20,11 +20,11 @@ In addition to the detections, **it has been possible to track these objects and
### Information flow
-
+
### Count algorithm
-
+
## Results
@@ -105,7 +105,7 @@ Do this following steps *in order.*
nvtop # To run the nvtop
```
- 
+ 
**Pull nvidia-gpu image**
@@ -117,26 +117,14 @@ Follow this **[installation guide.](https://docs.nvidia.com/datacenter/cloud-na
git pull https://github.com/aagustinconti/yolov7_counting
```
-**Change permissions of ./start.sh**
-
-```bash
-sudo chmod +x ./start.sh
-```
**Download YOLOv7x pretrained weights**
1. Download the pretrained weights of YOLOv7x [here.](https://github.com/WongKinYiu/yolov7/blob/main/README.md#performance)
2. Save them in **./pretrained_weights** directory.
-**RUN ./start.sh**
-
-To build the docker image if is not available in your PC and run the container with the propp
-
-```bash
-./start.sh
-```
-### Configuring the test
+**Configuring the test**
- Into the **test_oop.py** file you can modify some characteristics of the instance of the class *YoloSortCount()* before to execute the *run()* method.
- By default:
@@ -145,15 +133,18 @@ To build the docker image if is not available in your PC and run the container w
- Classes: person (ID: 0)
- Save: False
-**RUN the test**
-On the docker terminal run
+**RUN docker_control.py**
+
+To build the docker image if it's not available in your PC and run the container with the propp
```bash
- python test_oop.py
+python3 docker_control.py
```
+
+
## Thanks to
[YOLOv7](https://github.com/WongKinYiu/yolov7/)
diff --git a/dependencies/Dockerfile b/dependencies/Dockerfile
index 88f24d1..dc636ef 100644
--- a/dependencies/Dockerfile
+++ b/dependencies/Dockerfile
@@ -1,5 +1,5 @@
# Specify the parent image from which we build
-FROM pytorch/pytorch:latest
+FROM pytorch/pytorch:1.13.1-cuda11.6-cudnn8-runtime
# Copy the dependencies directory
COPY . /dependencies_files_docker
@@ -11,7 +11,8 @@ WORKDIR /dependencies_files_docker
RUN pip install -r requirements.txt
RUN chmod +x dependencies.sh
RUN bash dependencies.sh
-RUN cp -f ./upsampling.py /opt/conda/lib/python3.7/site-packages/torch/nn/modules/upsampling.py
+RUN mv /opt/conda/lib/python3.10/site-packages/torch/nn/modules/upsampling.py /opt/conda/lib/python3.10/site-packages/torch/nn/modules/upsampling_wrong.py
+RUN cp -f ./upsampling.py /opt/conda/lib/python3.10/site-packages/torch/nn/modules/upsampling.py
# To go to the working directory
WORKDIR /workspace
diff --git a/dependencies/requirements.txt b/dependencies/requirements.txt
index 89dbc03..f2cd1d1 100644
--- a/dependencies/requirements.txt
+++ b/dependencies/requirements.txt
@@ -1,17 +1,25 @@
+opencv-python==4.6.0.66
+scipy==1.7.3
+gdown==4.5.3
+tensorboard==2.10.1
+tensorboard-data-server==0.6.1
+tensorboard-plugin-wit==1.8.1
+pafy==0.5.5
+youtube-dl==2020.12.2
+pandas==1.3.5
+
+
absl-py==1.3.0
brotlipy==0.7.0
cachetools==5.2.0
-conda==4.13.0
-conda-build==3.21.9
cycler==0.11.0
Cython==0.29.32
deep-sort-realtime==1.3.1
dnspython==2.2.1
-easydict==1.10
flake8==5.0.4
fonttools==4.37.4
future==0.18.2
-gdown==4.5.3
+
google-auth==2.13.0
google-auth-oauthlib==0.4.6
grpcio==1.50.0
@@ -32,16 +40,15 @@ nvidia-cuda-nvrtc-cu11==11.7.99
nvidia-cuda-runtime-cu11==11.7.99
nvidia-cudnn-cu11==8.5.0.96
oauthlib==3.2.2
-opencv-python==4.6.0.66
+
packaging==21.3
-pafy==0.5.5
-pandas==1.3.5
+
+
Pillow==9.0.1
protobuf==3.19.6
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycodestyle==2.9.1
-pycosat==0.6.3
pyflakes==2.5.0
pyparsing==3.0.9
python-dateutil==2.8.2
@@ -49,19 +56,12 @@ python-etcd==0.4.5
PyYAML==6.0
requests-oauthlib==1.3.1
rsa==4.9
-scipy==1.7.3
+
seaborn==0.12.0
tb-nightly==2.11.0a20221105
-tensorboard==2.10.1
-tensorboard-data-server==0.6.1
-tensorboard-plugin-wit==1.8.1
-thop==0.1.1.post2209072238
-torch==1.13.0
-torchelastic==0.2.0
-torchtext==0.13.0
-torchvision==0.14.0
+
Werkzeug==2.2.2
yacs==0.1.8
yapf==0.32.0
-youtube-dl==2020.12.2
+
zipp==3.10.0
diff --git a/dependencies/upsampling.py b/dependencies/upsampling.py
index 184f474..ee91ff4 100644
--- a/dependencies/upsampling.py
+++ b/dependencies/upsampling.py
@@ -153,8 +153,9 @@ def __init__(self, size: Optional[_size_any_t] = None, scale_factor: Optional[_r
self.recompute_scale_factor = recompute_scale_factor
def forward(self, input: Tensor) -> Tensor:
- return F.interpolate(input, self.size, self.scale_factor, self.mode, self.align_corners)
- #recompute_scale_factor=self.recompute_scale_factor)
+ return F.interpolate(input, self.size, self.scale_factor, self.mode, self.align_corners,
+ #recompute_scale_factor=self.recompute_scale_factor
+ )
def extra_repr(self) -> str:
if self.scale_factor is not None:
diff --git a/docker_control.py b/docker_control.py
index f3434f6..34dfda4 100644
--- a/docker_control.py
+++ b/docker_control.py
@@ -23,13 +23,20 @@
logging.info("Checking if the Image already exists...")
-if not os.system('[ "$(docker image inspect yolov7_detect_track_count:latest 2> /dev/null)" == [] ]'):
+if str(os.popen("docker image inspect yolov7_detect_track_count:latest 2> /dev/null").read())[:2] == "[]":
logging.info("The image doesn't exist. Building the Docker Image...")
- os.system("cd ./dependencies")
+ os.chdir("./dependencies")
+
+ cwd = os.getcwd()
+ logging.info(f"The current directory is --> {cwd}")
+
os.system("docker build -t yolov7_detect_track_count .")
- os.system("cd ..")
+ os.chdir("..")
+
+ cwd = os.getcwd()
+ logging.info(f"The current directory is --> {cwd}")
else:
logging.info("The image has already exists.")
@@ -41,9 +48,15 @@
logging.info("Running a container...")
+
+
container = client.containers.run(
image='yolov7_detect_track_count:latest',
+ stdin_open=True,
+ tty=True,
auto_remove=True,
+ network_mode='host',
+ name="test",
device_requests=[docker.types.DeviceRequest(
device_ids=["0"], capabilities=[['gpu']])],
devices=["/dev/video0:/dev/video0"],
@@ -52,6 +65,5 @@
cwd: {'bind': '/workspace', 'mode': 'rw'}
},
environment=[f"DISPLAY={display}"],
- tty=True,
command='python test_oop.py'
)
diff --git a/flask-app.py b/flask-app.py
deleted file mode 100644
index 3fd1cbc..0000000
--- a/flask-app.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Import necessary libraries
-from flask import Flask, render_template, Response
-import cv2
-# Initialize the Flask app
-app = Flask(__name__)
-
-#https://towardsdatascience.com/video-streaming-in-web-browsers-with-opencv-flask-93a38846fe00
-camera = cv2.VideoCapture("http://192.168.102.3:4747/video")
-'''
-for ip camera use - rtsp://username:password@ip_address:554/user=username_password='password'_channel=channel_number_stream=0.sdp'
-for local webcam use cv2.VideoCapture(0)
-'''
-
-
-def gen_frames():
- while True:
- success, frame = camera.read() # read the camera frame
- if not success:
- break
- else:
- ret, buffer = cv2.imencode('.jpg', frame)
- frame = buffer.tobytes()
- yield (b'--frame\r\n'
- b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # concat
-
-
-@app.route('/')
-def index():
- return render_template('index.html')
-
-
-@app.route('/video_feed')
-def video_feed():
- return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
-
-
-if __name__ == "__main__":
- app.run(debug=True)
diff --git a/readme-img/Untitled.png b/readme-img/graph_1.png
similarity index 100%
rename from readme-img/Untitled.png
rename to readme-img/graph_1.png
diff --git a/readme-img/Untitled 1.png b/readme-img/graph_2.png
similarity index 100%
rename from readme-img/Untitled 1.png
rename to readme-img/graph_2.png
diff --git a/readme-img/Untitled 2.png b/readme-img/nvidiasmi.png
similarity index 100%
rename from readme-img/Untitled 2.png
rename to readme-img/nvidiasmi.png
diff --git a/start.sh b/start.sh
deleted file mode 100755
index f39d846..0000000
--- a/start.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-# Create the image of torch
-
-echo "Checking if the Image already exists..."
-
-if [[ "$(docker image inspect yolov7_detect_track_count:latest 2> /dev/null)" == [] ]];
-
-then
- echo "The image doesn't exist. Building the Docker Image..."
-
- cd ./dependencies
- docker build -t yolov7_detect_track_count .
- cd ..
-
-else
- echo "The image has already exists."
-fi
-
-
-# And then run
-# 1. To allow the use of screen
-echo "Setting up X Server to accept connections. Turning Access control off..."
-xhost +
-
-# 2. To run the image
-echo "Runing the Docker Image in the current location -> Display: ON ; Web camera access: ON"
-docker run --gpus all --rm -it -e DISPLAY=$DISPLAY -v $PWD:/workspace -v /tmp/.X11-unix:/tmp/.X11-unix:rw --device="/dev/video0:/dev/video0" yolov7_detect_track_count:latest
diff --git a/templates/index.html b/templates/index.html
deleted file mode 100644
index 44d4d83..0000000
--- a/templates/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
Live Streaming
-
 }})
-
-
-
-
\ No newline at end of file
diff --git a/test_oop.py b/test_oop.py
index 48c9c61..66ae002 100644
--- a/test_oop.py
+++ b/test_oop.py
@@ -12,11 +12,11 @@
WebCamera: 0 ---> DEFAULT
Youtube Video or stream: "https://www.youtube.com/watch?v=qP1y7Tdab7Y"
Stream URL: "http://IP/hls/stream_src.m3u8"
-RSTP Stream: "http://192.168.102.3:4747/video"
+RSTP Stream: "http://192.168.1.3:4747/video"
Local video: "img_bank/cows_for_sale.mp4"
Local image: "img_bank/img.jpg" | "img_bank/img.png"
"""
-test.video_path = 0 #"http://192.168.102.3:4747/video"
+test.video_path = 0#"https://www.youtube.com/watch?v=2wqpy036z24"
"""
@@ -28,7 +28,7 @@
"""
test.max_width = 720
test.max_fps = 25 # Max 1000
-test.inv_h_frame = False
+test.inv_h_frame = True
"""
@@ -51,7 +51,7 @@
- Load the ROI color.
"""
#test.roi = [0,0,0,0]
-test.auto_load_roi = False
+test.auto_load_roi = True
test.roi_color = (255, 255, 255)
@@ -68,7 +68,7 @@
"""
test.model_path = 'pretrained_weights/yolov7.pt'
test.graphic_card = 0
-test.class_ids = []
+test.class_ids = [0]
test.img_sz = 640
test.color = (0, 255, 0)
test.conf_thres = 0.5
diff --git a/test_oop_2.py b/test_oop_2.py
deleted file mode 100644
index 295df7c..0000000
--- a/test_oop_2.py
+++ /dev/null
@@ -1,137 +0,0 @@
-from yolov7_sort_count_oop import YoloSortCount
-
-#################### TEST ####################
-
-# INSTANCIATE
-
-test = YoloSortCount()
-
-
-"""
-###### AVAILABLE SOURCES ######
-WebCamera: 0 ---> DEFAULT
-Youtube Video or stream: "https://www.youtube.com/watch?v=qP1y7Tdab7Y"
-Stream URL: "http://IP/hls/stream_src.m3u8"
-RSTP Stream: "http://192.168.102.3:4747/video"
-Local video: "img_bank/cows_for_sale.mp4"
-Local image: "img_bank/img.jpg" | "img_bank/img.png"
-"""
-test.video_path = "http://192.168.102.3:4747/video"
-
-
-"""
-###### FRAME PROPERTIES ######
-
-- Set the max size of the frame (width)
-- Set the max fps of the video
-- Invert the image (In case of your WebCamera is mirrored, IE)
-"""
-test.max_width = 720
-test.max_fps = 25 # Max 1000
-test.inv_h_frame = False
-
-
-"""
-###### SHOWING RESULTS ######
-
-- Show the results in your display (Interactive ROI, imshow of the out frame)
-- In case of you are not showing the results, set the timer to stop the execution.
-- Stop the frame with hold_image method in case you are using image as a source.
-"""
-test.show_img = True
-test.ends_in_sec = 10
-test.hold_img = False
-
-
-"""
-###### ROI ######
-
-- Load the ROI manually.
--
-- Load the ROI color.
-"""
-#test.roi = [0,0,0,0]
-test.auto_load_roi = True
-test.roi_color = (255, 255, 255)
-
-
-"""
-###### DETECTION MODEL ######
-
-- Specify the path of the model.
-- Select the ID of your Graphic Card (nvidia-smi)
-- Select the classes to detect
-- Set the image size (Check if the YOLO model allows that --> IE: yolov7.pt 640, yolov7-w6.pt 1280 or 640)
-- Set the bounding box color
-- Set the minimum confidence to detect.
-- Set the minimum overlap of a predicted versus actual bounding box for an object.
-"""
-test.model_path = 'pretrained_weights/yolov7.pt'
-test.graphic_card = 0
-test.class_ids = []
-test.img_sz = 640
-test.color = (0, 255, 0)
-test.conf_thres = 0.5
-test.iou_thres = 0.65
-
-"""
-###### TRACKING MODEL ######
-
-- Specify the path of the model.
-- Set the max distance between two points to consider a tracking object.
-- Set the max overlap of a predicted versus actual bounding box for an object.
-- Set the image size (Check if the YOLO model allows that --> IE: yolov7.pt 640, yolov7-w6.pt 1280 or 640)
-- Set max_age to consider a lost of a tracking object that get out of the seen area.
-- Set the minimum frames to start to track objects.
-- Set the value that indicates how many previous frames of feature vectors should be retained for distance calculation for each track.
-- Set the color of the centroid and label of a tracking object.
-"""
-test.deep_sort_model = "osnet_x1_0"
-test.ds_max_dist = 0.1
-test.ds_max_iou_distance = 0.7
-test.ds_max_age = 30
-test.ds_n_init = 3
-test.ds_nn_budget = 100
-test.ds_color = (0, 0, 255)
-
-"""
-###### PLOT RESULTS ######
-
-- Specify the min x (left to right) to plot the draws
-- Specify the min y (top to bottom) to plot the draws
-- Specify padding between rectangles and text
-- Specify the text color.
-- Specify the rectangles color.
-"""
-test.plot_xmin = 10
-test.plot_ymin = 10
-test.plot_padding = 2
-test.plot_text_color = (255, 255, 255)
-test.plot_bgr_color = (0, 0, 0)
-
-
-"""
-###### DEBUG TEXT ######
-
-- Show the configs
-- Show the detection output variables
-- Show the tracking output variables
-- Show counting output variables
-"""
-test.show_configs = False
-test.show_detection = False
-test.show_tracking = False
-test.show_count = False
-
-"""
-###### SAVING RESULTS ######
-
-- Select if you want to save the results
-- Select a location to save the results
-"""
-test.save_vid = False
-test.save_loc = "results/result"
-
-
-# Run
-test.run()
diff --git a/yolov7_sort_count_oop.py b/yolov7_sort_count_oop.py
index 74ef4cd..bf2f11a 100644
--- a/yolov7_sort_count_oop.py
+++ b/yolov7_sort_count_oop.py
@@ -26,10 +26,6 @@
from count_oop import Count
-"""
-
-
-"""
class YoloSortCount():
@@ -67,7 +63,6 @@ def __init__(self):
self.ds_nn_budget = 100
self.ds_color = (0, 0, 255)
- self.max_fps = 25
self.max_width = 720
# Pre defined
@@ -75,6 +70,7 @@ def __init__(self):
self.orig_w = None
self.orig_h = None
+ self.orig_ratio = None
self.orig_fps = None
self.stopped = False
@@ -93,7 +89,7 @@ def __init__(self):
# Debug
logging.basicConfig(
- format='%(asctime)s | %(levelname)s: %(message)s', level=logging.NOTSET)
+ format='%(asctime)s | %(levelname)s: %(message)s', level=logging.INFO)
self.show_configs = False
self.show_detection = False
@@ -154,28 +150,18 @@ def load_video_capture(self, video_path):
logging.info(f'Source of the video: {video_path}')
cap = cv2.VideoCapture(video_path)
+
+ # To discard delayed frames
+ cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
+
logging.info('The video capture has been loaded.')
orig_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
orig_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
-
-
- if orig_w > self.max_width and orig_w != 0 :
- logging.info(
- 'Capture has more width than max. width allowed. Rezising...')
-
- orig_ratio = orig_h / orig_w
-
- cap = self.change_res(cap, self.max_width, orig_ratio)
-
- orig_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
- orig_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
-
- logging.info(f'Capture has been resized to {(orig_w,orig_h)}')
-
+ orig_ratio = orig_w / orig_h
orig_fps = cap.get(cv2.CAP_PROP_FPS) % 100
- return cap, orig_w, orig_h, orig_fps
+ return cap, orig_w, orig_h, orig_ratio, orig_fps
except Exception as err:
raise ImportError(
@@ -233,6 +219,7 @@ def load_tracking_model(self, deep_sort_model, max_dist, max_iou_distance, max_a
"""
try:
+ logging.info('This step may take a while...')
deepsort = DeepSort(deep_sort_model,
max_dist=max_dist,
max_iou_distance=max_iou_distance,
@@ -250,10 +237,15 @@ def load_roi(self):
- To select the ROI, interactive way.
"""
-
- cap_roi, _, _, _ = self.load_video_capture(self.video_path)
+ cap_roi, _, _,_,_= self.load_video_capture(self.video_path)
+
+ orig_w_roi = int(cap_roi.get(cv2.CAP_PROP_FRAME_WIDTH))
+ orig_h_roi = int(cap_roi.get(cv2.CAP_PROP_FRAME_HEIGHT))
+ orig_ratio_roi = orig_w_roi / orig_h_roi
+
ret, select_roi_frame = cap_roi.read()
-
+
+ # To avoid the camera delay
if not self.hold_img:
frame_count_roi = 0
while frame_count_roi <= 3 and ret:
@@ -261,6 +253,12 @@ def load_roi(self):
ret, select_roi_frame = cap_roi.read()
frame_count_roi += 1
+
+ # To adjust to the max width
+ if (self.max_width !=None) and (orig_w_roi != 0) and (orig_w_roi > self.max_width):
+ select_roi_frame = cv2.resize(select_roi_frame,(int(self.max_width), int(self.max_width/orig_ratio_roi)))
+
+
# To show image correctly (IE: web camera)
if self.inv_h_frame:
select_roi_frame = cv2.flip(select_roi_frame, 1)
@@ -327,17 +325,6 @@ def plot_text(self, frame, frame_w, fps, plot_xmin, plot_ymin, padding, counter_
return frame
- def change_res(self, cap, max_width, orig_ratio):
- """
- WHAT IT DOES:
- - Change te resolution of the frame.
-
- """
-
- cap.set(3, max_width)
- cap.set(4, int(max_width * orig_ratio))
-
- return cap
def run(self):
"""
@@ -370,7 +357,7 @@ def run(self):
self.roi = self.load_roi()
logging.info('ROI has been loaded.')
- cap, self.orig_w, self.orig_h, self.orig_fps = self.load_video_capture(
+ cap, self.orig_w, self.orig_h, self.orig_ratio, self.orig_fps = self.load_video_capture(
self.video_path)
if not self.roi:
@@ -389,16 +376,25 @@ def run(self):
start_ends_in_sec = time.time()
+
# Run detection
while (cap.isOpened()):
-
- # Get frame
+
+ # Get frame (The slow streaming video capture
+ # can be resolved by:
+ # https://stackoverflow.com/questions/58293187/opencv-real-time-streaming-video-capture-is-slow-how-to-drop-frames-or-get-sync )
+
ret, self.frame = cap.read()
+ # To resize frames
+ if (self.max_width !=None) and (self.orig_w != 0) and (self.orig_w > self.max_width):
+ self.frame = cv2.resize(self.frame,(int(self.max_width), int(self.max_width/self.orig_ratio)))
+
# To show image correctly (IE: web camera)
if self.inv_h_frame:
self.frame = cv2.flip(self.frame, 1)
+
# If the video has not finished yet
if ret:
@@ -463,7 +459,7 @@ def run(self):
self.stopped = True
break
else:
- if cv2.waitKey(int(1000/self.max_fps)) & 0xFF == ord('q'):
+ if cv2.waitKey(1) & 0xFF == ord('q'):
logging.info('Exiting by keyboard...')
self.stopped = True
break