- OpenCV
- Brief overview
- Basic structures
- Example functions and methods
- Let’s write an algorithm
- Testing module
- Accuracy test
- Performance test
- Let’s optimize
- Practice / Homework
- Open source project on GitHub with >3M downloads per year
- The most popular computer vision library with 20 years of development history
- 4 major releases:
1.0
,2.4.x
,3.4.x
,4.x
- Modular structure:
core
,imgproc
,ts
,dnn
,stitching
, ... - Written in C++ but has automatic wrappers in Python, Java, JavaScript, Matlab, GO, PHP, C#, etc.
- Cross-platform and well optimized for research and development
cv::Mat
- for images, masks, vector fields, complex values and custom data
cv::Mat mat(480, 640, CV_8UC3);
int rows = mat.rows; // 480
int cols = mat.cols; // 640
int channels = mat.channels(); // 3
uint8_t* data = mat.ptr<uint8_t>();
-
cv::Mat
types:[depth | (i.e. CV_8U, CV_16F, CV_32F, CV_64F)] + channels
-
std::cout << mat << std::endl
- To printcv::Mat
in console and watch values
cv::Rect rect; cv::Point point; cv::Size size;
int x = rect.x; int x = point.x; int w = size.width;
int y = rect.y; int y = point.y; int h = size.height;
int w = rect.width;
int h = rect.height;
Most of the methods work with basic OpenCV data structures as input and output
cv::Mat src, dst, mask;
cv::cvtColor(src, dst, COLOR_BGR2GRAY);
cv::resize(src, dst, cv::Size(1280, 960));
cv::Canny(src, dst, /*threshold1*/ 100, /*threshold2*/ 200);
cv::inpaint(src, mask, dst, /*inpaintRadius*/ 3, cv::INPAINT_TELEA);
std::vector<cv::Mat> images;
cv::Ptr<Stitcher> stitcher = cv::Stitcher::create(cv::Sticher::PANORAMA);
stitcher->stitch(images, dst);
---?code=src/bgr2gray.cpp&lang=cpp&title=BGR2Gray
@snap[south span-100 text-09] @[3-22](Reference implementation: 4.02ms @ 1920x1080) @[24-41](Fixed point: 2.39ms @ 1920x1080 (x1.68)) @[43-63](Parallel implementation: 1.83ms @ 1920x1080 (x2.19)) @snapend
Different backend depends on compilation options and target OS
- Intel Threading Building Blocks (TBB)
- C= Parallel C/C++ Programming Language Extension
- OpenMP
- APPLE GCD
- Windows RT concurrency
- Windows concurrency
- Pthreads
One of OpenCV modules is named ts
. It sonsists of
- Google Test based testing infrastructure
- OpenCV related extensions for regression and performance tests
- Python scripts for tests analysis
- Use
TEST
macro to define non-parametrized test - Use
EXPECT_*
checks for numerical and logical tests
#include <opencv2/ts.hpp>
TEST(bgr2gray, u8)
{
cv::Mat src(10, 11, CV_8UC3), ref, dst;
randu(src, 0, 255);
bgr2gray_reference(src, ref);
bgr2gray_u8(src, dst);
double maxV;
minMaxLoc(abs(ref - dst), 0, &maxV);
EXPECT_LE(maxV, 1);
}
$ ./bin/test_algo --gtest_filter=bgr2gray.u8
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from bgr2gray
[ RUN ] bgr2gray.u8
[ OK ] bgr2gray.u8 (15 ms)
[----------] 1 test from bgr2gray (18 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (21 ms total)
[ PASSED ] 1 test.
- Define a list of parameters and instantiate test with their combinations
typedef TestWithParam<tuple<int, int> > bgr2gray;
TEST_P(bgr2gray, parallel)
{
Mat src(/*rows*/ get<0>(GetParam()), /*cols*/ get<1>(GetParam()), CV_8UC3), ref, dst;
randu(src, 0, 255);
bgr2gray_u8(src, ref);
bgr2gray_u8_parallel(src, dst);
EXPECT_EQ(countNonZero(ref != dst), 0);
}
INSTANTIATE_TEST_CASE_P(/**/, bgr2gray, Combine( Values(3, 4), Values(2, 5) ));
[==========] Running 4 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from bgr2gray
[ RUN ] bgr2gray.parallel/0, where GetParam() = (3, 2)
[ OK ] bgr2gray.parallel/0 (14 ms)
[ RUN ] bgr2gray.parallel/1, where GetParam() = (3, 5)
[ OK ] bgr2gray.parallel/1 (0 ms)
[ RUN ] bgr2gray.parallel/2, where GetParam() = (4, 2)
[ OK ] bgr2gray.parallel/2 (0 ms)
[ RUN ] bgr2gray.parallel/3, where GetParam() = (4, 5)
[ OK ] bgr2gray.parallel/3 (0 ms)
[----------] 4 tests from bgr2gray (24 ms total)
[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (27 ms total)
[ PASSED ] 4 tests.
- Use
PERF_TEST
to define performance test - Wrap target code to a block
PERF_SAMPLE_BEGIN()
-PERF_SAMPLE_END()
- OpenCV does as much iterations as it's needed to have stable metrics
PERF_TEST(bgr2gray, u8_parallel)
{
cv::Mat src(480, 640, CV_8UC3), dst;
PERF_SAMPLE_BEGIN()
bgr2gray_u8_parallel(src, dst);
PERF_SAMPLE_END()
SANITY_CHECK_NOTHING();
}
$ ./bin/perf_algo --gtest_filter=bgr2gray.u8_parallel
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from bgr2gray
[ RUN ] bgr2gray.u8_parallel
[ PERFSTAT ] (samples=100 mean=0.25 median=0.25 min=0.22 stddev=0.02 (9.5%))
[ OK ] bgr2gray.u8_parallel (28 ms)
[----------] 1 test from bgr2gray (29 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (31 ms total)
[ PASSED ] 1 test.
Set of vectorized instructions that turn to platform specific operations at compile time
- AVX / SSE / SIMD (x86)
- NEON (ARM)
- VSX (PowerPC)
- MSA (MIPS)
- WASM (JavaScript)
#include <opencv2/core/hal/intrin.hpp>
// ...
std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8};
cv::v_int32x4 twos = cv::v_setall_s32(2);
cv::v_int32x4 b0 = cv::v_load(&data[0]);
b0 *= twos;
v_store(&data[0], b0);
b0 = cv::v_load(&data[4]);
b0 -= twos;
v_store(&data[4], b0);
// data = {2, 4, 6, 8, 3, 4, 5, 6}
- Sobel operator
| -1 0 +1 | | -1 -2 -1 |
Gx = | -2 0 +2 | * A, Gy = | 0 0 0 | * A
| -1 0 +1 | | +1 +2 +1 |
cv::Sobel(src, dst, CV_8U, 1, 0); // d/dx
cv::Sobel(src, dst, CV_8U, 0, 1); // d/dy
- Prewitt operator
| -1 0 +1 | | -1 -1 -1 |
Gx = | -1 0 +1 | * A, Gy = | 0 0 0 | * A
| -1 0 +1 | | +1 +1 +1 |
- Roberts cross
| +1 0 | | 0 +1 |
Gx = | 0 -1 | * A, Gy = | -1 0 | * A
---?code=src/prewitt.cpp&lang=cpp&title=Prewitt operator implementation
@snap[south span-100 text-09] @[3-17](Reference implementation: 12.76ms @ 1920x1080) @[19-31](Parallel implementation: 9.83ms @ 1920x1080 (x1.29)) @[39-58](Parallel vectorized implementation: 2.57ms @ 1920x1080 (x4.96)) @[65-84](Parallel vectorized implementation: 2.61ms @ 1920x1080 (x4.88)) @[92-114](Parallel vectorized implementation: 2.54ms @ 1920x1080 (x5.02)) @[115-130](Parallel vectorized implementation: 2.54ms @ 1920x1080 (x5.02)) @snapend
- Go to https://github.com/dkurt/cv_winter_camp_2021 for slides and project source code
- Implement Roberts Cross operator:
input: cv::Mat (single channel, uint8_t)
output: cv::Mat (single channel, int32_t)
out = (Gx)^2 + (Gy)^2, where
| +1 0 | | 0 +1 |
Gx = | 0 -1 | * A, Gy = | -1 0 | * A
- Write regression tests
- Parallelize and vectorize algorithm
- Write performance test and compare efficieny against reference version