Skip to content

Commit e258d38

Browse files
author
Koriukina, Valeriia
committed
added code for OpenCV GPU Support
1 parent 9569089 commit e258d38

File tree

4 files changed

+360
-0
lines changed

4 files changed

+360
-0
lines changed

OpenCV-GPU-Support/README.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# OpenCV GPU Support
2+
3+
This repository contains the code for [OpenCV GPU Support](https://www.learnopencv.com/opencv-gpu-support/)
4+
5+
## Getting Started
6+
7+
Our code is tested using Python 3.7.5, but it should also work with any other python3.x. If you'd like to check your
8+
version run:
9+
10+
```bash
11+
python3 -V
12+
```
13+
14+
### Virtual Environment
15+
16+
Let's create a new virtual environment. You'll need to install [virtualenv](https://pypi.org/project/virtualenv/)
17+
package if you don't have it:
18+
19+
```bash
20+
pip install virtualenv
21+
```
22+
23+
Now we can create a new virtualenv variable and call it `env`:
24+
25+
```bash
26+
python3 -m venv env
27+
```
28+
29+
The last thing we have to do is to activate it:
30+
31+
```bash
32+
source env/bin/activate
33+
```
34+
35+
### Numpy
36+
37+
Install numpy package by running:
38+
39+
```bash
40+
pip install numpy
41+
```
42+
43+
### Installing CUDA
44+
45+
The code was tested using CUDA Toolkit 10.2. Please follow the official instruction to download
46+
[CUDA Toolkit 10.2](https://developer.nvidia.com/cuda-10.2-download-archive) or higher.
47+
48+
### OpenCV with CUDA Support
49+
50+
In this blog post, we're using OpenCV with CUDA support to accelerate OpenCV algorithms. That is why we will need to
51+
customize the OpenCV library build and make it from scratch. To do so:
52+
53+
1. Install dependencies:
54+
55+
```bash
56+
sudo apt-get update
57+
sudo apt-get install build-essential cmake unzip pkg-config
58+
sudo apt-get install libjpeg-dev libpng-dev libtiff-dev
59+
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
60+
sudo apt-get install libxvidcore-dev libx264-dev
61+
sudo apt-get install libgtk-3-dev
62+
sudo apt-get install libatlas-base-dev gfortran
63+
sudo apt-get install python3-dev
64+
65+
```
66+
67+
2. Download the latest OpenCV version from the official repository:
68+
69+
```bash
70+
wget -O opencv.zip https://github.com/opencv/opencv/archive/4.3.0.zip
71+
wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.3.0.zip
72+
```
73+
74+
3. Unzip the downloaded archives:
75+
76+
```bash
77+
unzip opencv.zip
78+
unzip opencv_contrib.zip
79+
```
80+
81+
4. Rename the directories to match CMake paths:
82+
83+
```bash
84+
mv opencv-4.3.0 opencv
85+
mv opencv_contrib-4.3.0 opencv_contrib
86+
```
87+
88+
5. Compile OpenCV:
89+
90+
Create and enter a build directory:
91+
92+
```bash
93+
cd opencv
94+
mkdir build
95+
cd build
96+
```
97+
98+
Run CMake to configure the OpenCV build. Don't forget to set the right pass to the `PYTHON_EXECUTABLE`. If you are using
99+
the CUDA version different from `10.2`, please change the last 3 arguments accordingly.
100+
101+
```bash
102+
cmake -D CMAKE_BUILD_TYPE=RELEASE \
103+
-D CMAKE_INSTALL_PREFIX=/usr/local \
104+
-D INSTALL_PYTHON_EXAMPLES=OFF \
105+
-D INSTALL_C_EXAMPLES=OFF \
106+
-D OPENCV_ENABLE_NONFREE=ON \
107+
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
108+
-D PYTHON_EXECUTABLE=env/bin/python3 \
109+
-D BUILD_EXAMPLES=ON \
110+
-D WITH_CUDA=ON \
111+
-D CUDA_FAST_MATH=ON \
112+
-D WITH_CUBLAS=ON \
113+
-D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-10.2 \
114+
-D OpenCL_LIBRARY=/usr/local/cuda-10.2/lib64/libOpenCL.so \
115+
-DOpenCL_INCLUDE_DIR=/usr/local/cuda-10.2/include/ \
116+
..
117+
```
118+
119+
Check the output and make sure that everything is set correctly. After that we're ready to build it with:
120+
121+
```bash
122+
make -j4
123+
```
124+
125+
Make sure, you didn't get any errors. Then run the following command:
126+
127+
```bash
128+
sudo ldconfig
129+
```
130+
131+
which creates the necessary links and cache to our freshly built shared library.
132+
133+
Rename the created Python3 bindings for OpenCV to `cv2.so`:
134+
135+
```bash
136+
mv lib/python3/cv2.cpython-37m-x86_64-linux-gnu.so cv2.so
137+
```
138+
139+
The last step is to create a symlink of our OpenCV `cv2.so` into the virtual environment installed packages:
140+
141+
```bash
142+
cd env/lib/python3.7/site-packages/
143+
ln -s ~/opencv/build/cv2.so cv2.so
144+
```
145+
146+
## Running the Demo
147+
148+
To run the demo, you will need to pass:
149+
150+
- `--video` argument to set the path to the video file,
151+
- `--device` to choose between CPU and GPU inference. By default, the device is set to "cpu".
152+
153+
For example:
154+
155+
```bash
156+
python3 demo.py --video video/boat.mp4 --device "cpu"
157+
```
158+
159+
# AI Courses by OpenCV
160+
161+
Want to become an expert in AI? [AI Courses by OpenCV](https://opencv.org/courses/) is a great place to start.
162+
163+
<a href="https://opencv.org/courses/">
164+
<p align="center">
165+
<img src="https://www.learnopencv.com/wp-content/uploads/2020/04/AI-Courses-By-OpenCV-Github.png">
166+
</p>
167+
</a>

OpenCV-GPU-Support/demo.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import argparse
2+
import time
3+
4+
import cv2
5+
import numpy as np
6+
7+
8+
def main(video, device):
9+
10+
# init dict to track time for every stage at each iteration
11+
timers = {
12+
"full pipeline": [],
13+
"reading": [],
14+
"pre-process": [],
15+
"optical flow": [],
16+
"post-process": [],
17+
}
18+
19+
# init video capture with video
20+
cap = cv2.VideoCapture(video)
21+
# get default video FPS
22+
fps = cap.get(cv2.CAP_PROP_FPS)
23+
# get total number of video frames
24+
num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
25+
26+
# read the first frame
27+
ret, previous_frame = cap.read()
28+
29+
# proceed if frame reading was successful
30+
if ret:
31+
# resize frame
32+
frame = cv2.resize(previous_frame, (960, 540))
33+
# convert to gray
34+
previous_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
35+
36+
# create hsv output for optical flow
37+
hsv = np.zeros_like(frame)
38+
# set saturation to a maximum value
39+
hsv[..., 1] = 255
40+
41+
while True:
42+
# start full pipeline timer
43+
start_full_time = time.time()
44+
45+
# start reading timer
46+
start_read_time = time.time()
47+
48+
# capture frame-by-frame
49+
ret, current_frame = cap.read()
50+
51+
# end reading timer
52+
end_read_time = time.time()
53+
# add elapsed iteration time
54+
timers["reading"].append(end_read_time - start_read_time)
55+
56+
# if frame reading was not successful, break
57+
if not ret:
58+
break
59+
60+
# start pre-process timer
61+
start_pre_time = time.time()
62+
# resize frame
63+
frame = cv2.resize(current_frame, (960, 540))
64+
65+
# convert to gray
66+
current_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
67+
68+
if device == "cpu":
69+
# end pre-process timer
70+
end_pre_time = time.time()
71+
# add elapsed iteration time
72+
timers["pre-process"].append(end_pre_time - start_pre_time)
73+
74+
# start optical flow timer
75+
start_of = time.time()
76+
# calculate optical flow
77+
flow = cv2.calcOpticalFlowFarneback(
78+
previous_frame, current_frame, None, 0.5, 3, 15, 3, 5, 1.2, 0,
79+
)
80+
# end of timer
81+
end_of = time.time()
82+
# add elapsed iteration time
83+
timers["optical flow"].append(end_of - start_of)
84+
85+
else:
86+
# move both frames to GPU
87+
cu_previous = cv2.cuda_GpuMat()
88+
cu_current = cv2.cuda_GpuMat()
89+
90+
cu_previous.upload(previous_frame)
91+
cu_current.upload(current_frame)
92+
93+
# end pre-process timer
94+
end_pre_time = time.time()
95+
# add elapsed iteration time
96+
timers["pre-process"].append(end_pre_time - start_pre_time)
97+
98+
# start optical flow timer
99+
start_of = time.time()
100+
# create optical flow instance
101+
flow = cv2.cuda_FarnebackOpticalFlow.create(
102+
None, 0.5, 3, 15, 3, 5, 1.2, 0,
103+
)
104+
# calculate optical flow
105+
flow = cv2.cuda_FarnebackOpticalFlow.calc(
106+
flow, cu_previous, cu_current, None,
107+
)
108+
# sent result from GPU back to CPU
109+
flow = flow.download()
110+
111+
# end of timer
112+
end_of = time.time()
113+
# add elapsed iteration time
114+
timers["optical flow"].append(end_of - start_of)
115+
116+
# start post-process timer
117+
start_post_time = time.time()
118+
119+
# convert from cartesian to polar to get magnitude and angle
120+
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
121+
# set hue according to the angle of optical flow
122+
hsv[..., 0] = ang * 180 / np.pi / 2
123+
# set value according to the normalized magnitude of optical flow
124+
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
125+
# convert hsv to rgb
126+
rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
127+
# update previous_frame value
128+
previous_frame = current_frame
129+
130+
# end post-process timer
131+
end_post_time = time.time()
132+
# add elapsed iteration time
133+
timers["post-process"].append(end_post_time - start_post_time)
134+
135+
# end full pipeline timer
136+
end_full_time = time.time()
137+
# add elapsed iteration time
138+
timers["full pipeline"].append(end_full_time - start_full_time)
139+
140+
# visualization
141+
cv2.imshow("original", frame)
142+
cv2.imshow("result", rgb)
143+
k = cv2.waitKey(1)
144+
if k == 27:
145+
break
146+
147+
# release the capture
148+
cap.release()
149+
# destroy all windows
150+
cv2.destroyAllWindows()
151+
152+
# print results
153+
print("Number of frames: ", num_frames)
154+
155+
# elapsed time at each stage
156+
print("Elapsed time")
157+
for stage, seconds in timers.items():
158+
print("-", stage, ": {:0.2f} seconds".format(sum(seconds)))
159+
160+
# calculate frames per second
161+
print("Default video FPS: {:0.2f}".format(fps))
162+
163+
of_fps = (num_frames - 1) / sum(timers["optical flow"])
164+
print("Optical flow FPS: {:0.2f}".format(of_fps))
165+
166+
full_fps = (num_frames - 1) / sum(timers["full pipeline"])
167+
print("Full pipeline FPS: {:0.2f}".format(full_fps))
168+
169+
170+
if __name__ == "__main__":
171+
172+
# init argument parser
173+
parser = argparse.ArgumentParser(description="OpenCV CPU/GPU Comparison")
174+
175+
parser.add_argument(
176+
"--video", help="path to .mp4 video file", required=True, type=str,
177+
)
178+
179+
parser.add_argument(
180+
"--device",
181+
default="cpu",
182+
choices=["cpu", "gpu"],
183+
help="device to inference on",
184+
)
185+
186+
# parsing script arguments
187+
args = parser.parse_args()
188+
video = args.video
189+
device = args.device
190+
191+
# run pipeline
192+
main(video, device)

OpenCV-GPU-Support/video/boat.mp4

28.1 MB
Binary file not shown.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Want to become an expert in AI? [AI Courses by OpenCV](https://opencv.org/course
1313

1414
| Blog Post | |
1515
| ------------- |:-------------|
16+
|[OpenCV GPU Support](https://www.learnopencv.com/opencv-gpu-support/)|[Code](https://github.com/spmallick/learnopencv/tree/master/opencv-gpu-support)|
1617
|[Training a Custom Object Detector with DLIB & Making Gesture Controlled Applications](https://www.learnopencv.com/training-a-custom-object-detector-with-dlib-making-gesture-controlled-applications/)|[Code](https://github.com/spmallick/learnopencv/tree/master/Training_a_custom_hand_detector_with_dlib) |
1718
|[How To Run Inference Using TensorRT C++ API](https://www.learnopencv.com/how-to-run-inference-using-tensorrt-c-api/) | [Code](https://github.com/spmallick/learnopencv/tree/master/PyTorch-ONNX-TensorRT-CPP) |
1819
|[Using Facial Landmarks for Overlaying Faces with Medical Masks](https://www.learnopencv.com/using-facial-landmarks-for-overlaying-faces-with-masks/)|[Code](https://github.com/spmallick/learnopencv/tree/master/FaceMaskOverlay) |

0 commit comments

Comments
 (0)