Merge branch 'master' into pthreads_integration

This commit is contained in:
Joachim
2020-04-02 10:52:20 +02:00
166 changed files with 1207 additions and 486 deletions

View File

@ -0,0 +1,534 @@
# Detailed build procedure
The last way explains all the commands and modifications done to be able to compile and run OpenCV on the ESP32.
## CMake command:
The following cmake command is launched in the `build/` directory.
```bash
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DESP32=ON \
-DBUILD_SHARED_LIBS=OFF \
-DCV_DISABLE_OPTIMIZATION=OFF \
-DWITH_IPP=OFF \
-DWITH_TBB=OFF \
-DWITH_OPENMP=OFF \
-DWITH_PTHREADS_PF=ON \
-DWITH_QUIRC=OFF \
-DWITH_1394=OFF \
-DWITH_CUDA=OFF \
-DWITH_OPENCL=OFF \
-DWITH_OPENCLAMDFFT=OFF \
-DWITH_OPENCLAMDBLAS=OFF \
-DWITH_VA_INTEL=OFF \
-DWITH_EIGEN=OFF \
\
-DWITH_GSTREAMER=OFF \
-DWITH_GTK=OFF \
-DWITH_JASPER=OFF \
-DWITH_JPEG=OFF \
-DWITH_WEBP=OFF \
-DBUILD_ZLIB=ON \
-DBUILD_PNG=ON \
-DWITH_TIFF=OFF \
-DWITH_V4L=OFF \
-DWITH_LAPACK=OFF \
-DWITH_ITT=OFF \
-DWITH_PROTOBUF=OFF \
-DWITH_IMGCODEC_HDR=OFF \
-DWITH_IMGCODEC_SUNRASTER=OFF \
-DWITH_IMGCODEC_PXM=OFF \
-DWITH_IMGCODEC_PFM=OFF \
\
-DBUILD_LIST=core,imgproc,imgcodecs \
-DBUILD_JAVA=OFF \
-DBUILD_opencv_python=OFF \
-DBUILD_opencv_java=OFF \
\
-DBUILD_opencv_apps=OFF \
-DBUILD_PACKAGE=OFF \
-DBUILD_PERF_TESTS=OFF \
-DBUILD_TESTS=OFF \
-DCV_ENABLE_INTRINSICS=OFF \
-DCV_TRACE=OFF \
-DOPENCV_ENABLE_MEMALIGN=OFF \
\
-DCMAKE_TOOLCHAIN_FILE=~/esp/esp-idf/tools/cmake/toolchain-esp32.cmake \
..
```
* `-DCMAKE_BUILD_TYPE` can be set to `Debug` to simplify debugging, but uses more RAM
* `-DBUILD_ZLIB` and `-DBUILD_PNG` are enabled to statically compile the libs instead of using dynamic libs of the system.
* `-DOPENCV_ENABLE_MEMALIGN` is disabled because the ESP32 doesn't support memory alignment for now (https://github.com/espressif/esp-idf/issues/4218)
* The toolchain file `toolchain-esp32.cmake` is taken from esp-idf github:
```cmake
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER xtensa-esp32-elf-gcc)
set(CMAKE_CXX_COMPILER xtensa-esp32-elf-g++)
set(CMAKE_ASM_COMPILER xtensa-esp32-elf-gcc)
set(CMAKE_C_FLAGS "-mlongcalls -Wno-frame-address" CACHE STRING "C Compiler Base Flags")
set(CMAKE_CXX_FLAGS "-mlongcalls -Wno-frame-address" CACHE STRING "C++ Compiler Base Flags")
# Can be removed after gcc 5.2.0 support is removed (ref GCC_NOT_5_2_0)
set(CMAKE_EXE_LINKER_FLAGS "-nostdlib" CACHE STRING "Linker Base Flags")
```
When the `cmake` command works, the following summary is given:
```bash
-- General configuration for OpenCV 4.2.0-dev =====================================
-- Version control: 4.2.0-375-g8808aaccff-dirty
--
-- Platform:
-- Timestamp: 2020-03-23T09:54:18Z
-- Host: Linux 4.19.10-041910-generic x86_64
-- Target: Generic
-- CMake: 3.16.4
-- CMake generator: Unix Makefiles
-- CMake build tool: /usr/bin/make
-- Configuration: Release
--
-- CPU/HW features:
-- Baseline:
-- requested: DETECT
--
-- C/C++:
-- Built as dynamic libs?: NO
-- C++ standard: 11
-- C++ Compiler: /home/joachim/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-g++ (ver 8.2.0)
-- C++ flags (Release): -mlongcalls -Wno-frame-address -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG
-- C++ flags (Debug): -mlongcalls -Wno-frame-address -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -g -O0 -DDEBUG -D_DEBUG
-- C Compiler: /home/joachim/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc
-- C flags (Release): -mlongcalls -Wno-frame-address -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -O3 -DNDEBUG -DNDEBUG
-- C flags (Debug): -mlongcalls -Wno-frame-address -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -g -O0 -DDEBUG -D_DEBUG
-- Linker flags (Release): -Wl,--gc-sections
-- Linker flags (Debug): -Wl,--gc-sections
-- ccache: NO
-- Precompiled headers: NO
-- Extra dependencies:
-- 3rdparty dependencies: zlib libpng
--
-- OpenCV modules:
-- To be built: core imgcodecs imgproc
-- Disabled: world
-- Disabled by dependency: calib3d features2d flann gapi highgui java_bindings_generator ml objdetect photo python_bindings_generator python_tests stitching video videoio
-- Unavailable: dnn java js python2 python3 ts
-- Applications: -
-- Documentation: NO
-- Non-free algorithms: NO
--
-- GUI:
--
-- Media I/O:
-- ZLib: build (ver 1.2.11)
-- PNG: build (ver 1.6.37)
-- HDR: NO
-- SUNRASTER: NO
-- PXM: NO
-- PFM: NO
--
-- Video I/O:
-- FFMPEG: NO
-- avcodec: NO
-- avformat: NO
-- avutil: NO
-- swscale: NO
-- avresample: NO
--
-- Parallel framework: none
--
-- Other third-party libraries:
-- Custom HAL: NO
--
-- Python (for build): /home/joachim/.espressif/python_env/idf4.2_py2.7_env/bin/python2.7
--
-- Install to: /home/joachim/Documents/HES/02_MSE/22_master_thesis/esp32-opencv/build/install
-- -----------------------------------------------------------------
--
-- Configuring done
-- Generating done
-- Build files have been written to: /home/joachim/Documents/HES/02_MSE/22_master_thesis/esp32-opencv/build
```
## Make command:
When the cmake is done, the compilation is started with:
```bash
make -j5
```
When the compilation has ended, the libs are in the `build/lib` folder.
## Compiling esp-idf project using OpenCV:
When the OpenCV library is cross-compiled, we have in result `*.a` files located in `build/lib` folder. We now want to try to compile an example project using OpenCV on the esp32. A basic example of esp-idf project can be found in [esp32/examples/esp_opencv_basic](esp32/examples/esp_opencv_basic). This project simply creates an OpenCV matrix, fill it with values and prints it on the console.
Esp-idf environment uses cmake and is separated in components. Because OpenCV libs were compiled outside this example project, we use the pre-built library functionality of esp-idf (https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#using-prebuilt-libraries-with-components).
Here are the things done to add the OpenCV library to the project:
* Create a folder named `opencv/` into the `main/` component's folder
* Copy the generated libraries (`libade.a`, `libopencv_core.a`, `libopencv_imgproc.a` and `libopencv_imgcodecs.a`) into this directory
* Create the folder `opencv2/` into this directory, and copy into it the needed headers files :
* `cvconfig.h`
* `opencv_modules.hpp`
* `opencv.hpp`
* `core.hpp`
* `imgproc.hpp`
* `imgcodecs.hpp`
* `core/` folder
* `imgproc/` folder
* `imgcodecs/` folder
* Link the libraries to the project by modifying the `CMakeList.txt` of the `main` project's component is as below :
```cmake
idf_component_register(
SRC main.cpp
INCLUDE_DIRS ./opencv
)
# Be aware that the order of the librairies is important
add_prebuilt_library(opencv_imgcodecs "opencv/libopencv_imgcodecs.a")
add_prebuilt_library(libpng "opencv/3rdparty/liblibpng.a")
add_prebuilt_library(libzlib "opencv/3rdparty/libzlib.a")
add_prebuilt_library(opencv_imgproc "opencv/libopencv_imgproc.a")
add_prebuilt_library(opencv_core "opencv/libopencv_core.a")
add_prebuilt_library(ade "opencv/libade.a")
target_link_libraries(${COMPONENT_LIB} PRIVATE opencv_imgcodecs)
target_link_libraries(${COMPONENT_LIB} PRIVATE libpng)
target_link_libraries(${COMPONENT_LIB} PRIVATE libzlib)
target_link_libraries(${COMPONENT_LIB} PRIVATE opencv_imgproc)
target_link_libraries(${COMPONENT_LIB} PRIVATE opencv_core)
target_link_libraries(${COMPONENT_LIB} PRIVATE ade)
```
* Finally, include the OpenCV headers needed into your source files:
```c++
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
```
## Modified files for OpenCV to compile and run:
To get the cmake configuration and make compilation to work, some modifications on OpenCV files had to be done. They are listed below.
A `cmake` option `ESP32` is added to the `CmakeLists.txt` :
```cmake
OCV_OPTION(ESP32 "Compilation for esp32 target" OFF)
```
To enable it, add the `-DESP32=ON` in the `cmake` command. This will then be used to enable/disable some parts of the codes of the OpenCV project.
A preprocessor definition is also added in the `CMakeLists.txt` file, line 494:
```cmake
if(ESP32)
message(STATUS "Enabled ESP32 target specific build")
add_definitions(-DESP32)
endif()
```
The checks for system libraries (`libpthread`, `libdl`, `libm`, `librt`) are also activated by changing the line 607 of the `CMakeList.txt` file:
```cmake
if(UNIX OF ESP32)
```
The `cmake` command is run, leading to the following errors:
* *Having error `C++11 compiler must support std::atomic`*
The esp32 only has hardware support for 32-bit atomic operations but not wider (https://github.com/espressif/esp-idf/issues/3163)
**FIX:**
* Changed the file `cmake/checks/atomic_check.cpp` in OpenCV repo. The `std::atomic<long long>` was changed in `std::atomic<long>`, and also in file `modules/core/include/opencv2/core/utils/allocator_stats.impl.hpp` line 24.
* *CMake Error at `/usr/share/cmake-3.16/Modules/TestBigEndian.cmake:50`. The ESP32 is in little endian.*
**FIX:**
* In the main `CMakeLists.txt` file, the line 654 is changed :
```cmake
if(IOS OR ESP32)
```
After these fixes, the command `make` is run, with some new errors:
* *alloc.cpp:31:16: error: 'posix_memalign' was not declared in this scope*
**FIX:** Modify `alloc.cpp`
* When there is an `#if defined(ANDROID)`, add ` || defined(ESP32)` after, so that `malloc.h` is included and `memalign` is used
* *#error "<dirent.h> not supported"*
The ESP32 doesn't support directories (which are emulated with the filenames, like `mydir/mysubdir/myfile.c`).
**FIX:** Modify `modules/core/src/glob.cpp`
* Add the following code after line 136:
```c++
#if defined(ESP32)
#include <sys/stat.h>
const char dir_separators[] = "/";
namespace {
struct dirent {
const char *d_name;
};
struct DIR {
dirent ent;
DIR() { }
~DIR()
{
if (ent.d_name)
delete[] ent.d_name;
}
};
DIR* opendir(const char* path)
{
DIR* dir = new DIR;
dir->ent.d_name = 0;
// TODO implement (point the first file starting with 'path' in its name)
return dir;
}
dirent* readdir(DIR* dir)
{
// TODO: implement (point to the next file with 'path' in its name)
return &(dir->ent);
}
void closedir(DIR* dir)
{
delete dir;
}
}
```
The function are not implemented yet. Must be implemented if files reading/writing in SPIFFS needed.
* *system.cpp:1002:20: error: 'mkstemp' was not declared in this scope*
**FIX:**
* Tried to include `<stdlib.h>` where `mkstemp` is, but didn't worked, so just commented lines 1003 to 1007 for now
* *color.simd_helpers.hpp:148:5: error: insn does not satisfy its constraints*
**FIX:**
* Disable optimization only for this function:
```c++
#pragma GCC push_options
#pragma GCC optimize ("-O0")
virtual void operator()(const Range& range) const CV_OVERRIDE
{
// functon content ...
}
#pragma GCC pop_options
```
* *histogram.cpp:1813:1: error: insn does not satisfy its constraints*
**FIX:**
* Disable optimization only for this function:
```c++
#pragma GCC push_options
#pragma GCC optimize ("-O0")
void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
const SparseMat& hist, OutputArray _backProject,
const float** ranges, double scale, bool uniform )
{
// functon content ...
}
#pragma GCC pop_options
```
When the `make` command compiles successfully, the library was tested with an example. This led to some new errors:
* *parallel.cpp:949:58: undefined reference to sysconf*
This error appeared while trying to use the `canny()` method of the imgproc module
**Fix:** Modify `modules/core/src/parallel.cpp`
* Change the line 947 in
```c++
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(ESP32)
```
Which will bypass the unsupported call to `sysconf` that get the number of cpu
* *.dram0.bss will not fit in region dram0_0_seg ; region `dram0_0_seg' overflowed by 13496 bytes*
This error appeared while trying to add `cvtColor()` function
**Fix:**
* The error says that `dram_0_0_seg` region (containing memory allocated statically at compile time) is overflowed.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HEAD:README.md
* Disabling the bluetooth in the `menuconfig` saves 56'156 Bytes, but doesn't work though
* Searching in `build/<project-name>.map` for the `.dram0.bss` section, and looking at the opencv bss variables that are big
* `imgproc/color_lab.cpp` has variables (trilinearLUTE, InvGammaTab and LabCbrtTab) taking 88kB, which is big
* It is deactivated (see [this section](#removing-opencv-unnecessary-parts))
## Get project RAM and Flash usages
### At compilation time:
* The command below can be used to see the different segments sizes of the application :
```bash
$ xtensa-esp32-elf-size -d -A build/<project-name>.elf
```
* The file `build/<project-name>.map` is also very useful. It indicates the memory mapping of the variables and can be used to find big variables in the application.
### At run time:
```c++
ESP_LOGI(TAG, "task stack left: %d Bytes", uxTaskGetStackHighWaterMark(NULL));
ESP_LOGI(TAG, "heap left: %d Bytes", esp_get_free_heap_size());
```
## Adding images codecs support
Things done to read/writes images in JPEG, PNG, etc..
#### PNG
* Remove `-DWITH_PNG=OFF` and add `-DBUILD_PNG=ON` and `-DBUILD_ZLIB=ON` of the cmake command
* => The lib `opencv_imgcodecs.a` build pass
The library is compiled in the `3rdparty/` folder. Copy this folder into the esp32 example project folder.
#### JPEG
* Remove `-DWITH_JPEG=OFF` and add `-DBUILD_JPEG=ON` of the cmake command
* => Problem at compilation time. TODO
## Adding parallel support
To add loop parallelization on the 2 cores of the esp32, the following modifications are done:
* Changed cmake command with `-DWITH_PTHREADS_PF=ON`
* Had to temporary add a pthread_cond usage in the main component for the link to work (otherwise had an *undefined reference to pthread_cond_* functions)
* The pthread_cond implementation is in the esp-idf pthread component. Haven't found yet how to link it
* In `parallel.cpp` function `getNumberOfCPUs`:
* For now, couldn't make `sysconf` function to work (to get the number of cpus), so returns 2 if ESP32 is defined
* In idf menuconfig:
* set pthread default stack size to 8192
These modifications haven't improved the performances on the benchmark for now.
## Removing OpenCV unnecessary parts
Opencv is quite big, even when compiling only the core, imgproc and imgcodec modules. Because the ESP32 has limited resources, it is a good idea to remove some parts of opencv that are in most cases not used.
TODO: List the modules functionalities and what is kept or not
### Core module:
### Imgproc module:
#### Colorspaces
Opencv supports multiple colorspaces (RGB, BGR, RGB565, RGBA, CIELAB, CIEXYZ, Luv, YUV, HSV, HLS, YCrCb, Bayer, Gray). All these colorspaces are not mandatory for an embedded system, so some are removed.
* `color_lab.cpp`: This file contains conversion for CIELAB and CIEXYZ (https://en.wikipedia.org/wiki/CIELAB_color_space). The conversion tables takes a lot of space in the .bss segment (~88kB) , which is already overflowing. Here are the steps done to disable this code:
* Move `color_lab.cpp` to `color_lab.cpp.bak`
* In `color.hpp` disable :
```c++
```
* In `color.cpp` disable:
```c++
```
* todo
========================================================================================================================================================================================================
The Linker Script `esp-idf/components/esp32/ld/esp32.ld` defines the memory layout. It tells the linker where to put the compiler outputs.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> master:esp32/doc/detailed_build_procedure.md
* The region `dram_0_0_seg` has a size of `0x2c200` which corresponds to `~180kB`
* It is said in this file that this dram segment *should* be `0x50000` (`~330kB`) and that extra DRAM is available in heap at runtime, but that due to static ROM memory usage at 176kB mark, the additional static memory cannot be used. (see also https://esp32.com/viewtopic.php?t=6699).
* Also enabling `Bluetooth` and `Trace Memory` features in menuconfig will decrease the amount of RAM available
* Because we can't have more static memory, some features had to be disabled:
* Disabling the Bluetooth (~56kB) and Trace Memory in the menuconfig
* Disabling some OpenCV features not mandatory and taking lot of memory. To find variables taking too much space, the `build/<project-name>.map` file is useful (looking for big variables under the `.dram0.bss` section).
* `imgproc/color_lab.cpp` has variables (trilinearLUTE, InvGammaTab and LabCbrtTab) taking ~88 kB. They are used for colorspace conversions in and from CIE LAB and XYZ images. These functions were removed.

View File

@ -2,15 +2,15 @@
This example uses OpenCV library on the Esp32. Only the modules `core`, `imgproc` and `imgcodecs` are compiled.
The goal of this example is to check which OpenCV features are working and to benchmark their computation time on the target.
The goal of this example is to check which OpenCV features are working and to benchmark their computation time on the target.
The code reads PNG image of different size from the SPIFFS filesystem of the Esp32 (for now, only PNG files are supported). It then performs operations on each image and report the results in an array into the console.
The example tests :
The results obtained with can be seen in [benchmark/bm_concat.rst](benchmark/bm_concat.rst). It was tested on the following hardware:
* ESP32D0WDQ6 (revision 1)
* 8 MB of external SPI RAM
* 16 MB of external SPI Flash
* some matrices initialization, then basic image processing functions on these matrices.
* Reading a 470x400 pixels PNG image from the SPIFFS filesystem of the Esp32. For now, only PNG files are supported.
* Perform grayscale conversion and then binary threshold on the image, then write it on the spi flash
* Perform a canny edges detection on the image and the write it on the spi flash

View File

@ -0,0 +1,63 @@
+------------------------------------------------+-------------+-------------+-------------+-------------+
| Function name and arguments | BUILD_TYPE=Debug |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| | 160x120 | 320x240 | 640x480 | 1024x768 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| All measures are in [ms] |
+================================================+=============+=============+=============+=============+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Threshold** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| binaryThreshold | 4.5 | 18 | 69 | 175 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| triangleThreshold | 8.1 | 32 | 124 | 315 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| OTSUThreshold | 11 | 35 | 127 | 318 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| toZeroThreshold | 4.5 | 18 | 69 | 175 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Blurring** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| GaussianBlur 9x9 kernel | 223 | 875 | 3473 | 9042 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| medianBlur 9x9 kernel | 141 | 608 | 2754 | 7505 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| bilateralFilter diameter=9 | 413 | 1628 | 6487 | 16386 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Morphological tranforms** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| erode 5x5 kernel | 41 | 151 | 587 | 1493 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| dilate 5x5 kernel | 41 | 151 | 587 | 1494 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| open 5x5 kernel | 81 | 299 | 1163 | 2959 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Resize image** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| resize linear interpolation | 10 | 39 | 150 | 378 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| resize cubic interpolation | 21 | 75 | 291 | 733 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Edge detection** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| Sobel | 34 | 116 | 438 | 1129 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| Canny | 81 | 260 | 894 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Hough tranformations** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| HoughLines | 392 | 897 | - | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| HoughLines probabilistic | 699 | 1652 | - | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+

View File

@ -0,0 +1,63 @@
+------------------------------------------------+-------------+-------------+-------------+-------------+
| Function name and arguments | BUILD_TYPE=Release |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| | 160x120 | 320x240 | 640x480 | 1024x768 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| All measures are in [ms] |
+================================================+=============+=============+=============+=============+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Threshold** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| binaryThreshold | 2.6 | 11 | 42 | 107 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| triangleThreshold | 3.9 | 17 | 66 | 168 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| OTSUThreshold | 6.5 | 20 | 69 | 171 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| toZeroThreshold | 2.6 | 11 | 42 | 107 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Blurring** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| GaussianBlur 9x9 kernel | 34 | 128 | 504 | 1458 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| medianBlur 9x9 kernel | 56 | 273 | 1425 | 4091 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| bilateralFilter diameter=9 | 138 | 535 | 2119 | 5293 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Morphological tranforms** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| erode 5x5 kernel | 6.2 | 22 | 84 | 214 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| dilate 5x5 kernel | 6.2 | 22 | 84 | 214 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| open 5x5 kernel | 11 | 41 | 158 | 400 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Resize image** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| resize linear interpolation | 3.8 | 16 | 59 | 147 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| resize cubic interpolation | 6.5 | 27 | 108 | 277 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Edge detection** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| Sobel | 14 | 50 | 187 | 497 |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| Canny | 32 | 108 | 375 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| **Hough tranformations** |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| HoughLines | 313 | 681 | 2121 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+
| HoughLines probabilistic | 608 | 1358 | 3766 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+

View File

@ -0,0 +1,63 @@
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| Function name and arguments | BUILD_TYPE=Debug | BUILD_TYPE=Release |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | 160x120 | 320x240 | 640x480 | 1024x768 | 160x120 | 320x240 | 640x480 | 1024x768 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| All measures are in [ms] | |
+================================================+=============+=============+=============+=============+=============+=============+=============+=============+
| | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| **Threshold** | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| binaryThreshold | 4.5 | 18 | 69 | 175 | 2.6 | 11 | 42 | 107 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| triangleThreshold | 8.1 | 32 | 124 | 315 | 3.9 | 17 | 66 | 168 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| OTSUThreshold | 11 | 35 | 127 | 318 | 6.5 | 20 | 69 | 171 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| toZeroThreshold | 4.5 | 18 | 69 | 175 | 2.6 | 11 | 42 | 107 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| **Blurring** | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| GaussianBlur 9x9 kernel | 223 | 875 | 3473 | 9042 | 34 | 128 | 504 | 1458 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| medianBlur 9x9 kernel | 141 | 608 | 2754 | 7505 | 56 | 273 | 1425 | 4091 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| bilateralFilter diameter=9 | 413 | 1628 | 6487 | 16386 | 138 | 535 | 2119 | 5293 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| **Morphological tranforms** | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| erode 5x5 kernel | 41 | 151 | 587 | 1493 | 6.2 | 22 | 84 | 214 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| dilate 5x5 kernel | 41 | 151 | 587 | 1494 | 6.2 | 22 | 84 | 214 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| open 5x5 kernel | 81 | 299 | 1163 | 2959 | 11 | 41 | 158 | 400 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| **Resize image** | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| resize linear interpolation | 10 | 39 | 150 | 378 | 3.8 | 16 | 59 | 147 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| resize cubic interpolation | 21 | 75 | 291 | 733 | 6.5 | 27 | 108 | 277 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| **Edge detection** | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| Sobel | 34 | 116 | 438 | 1129 | 14 | 50 | 187 | 497 |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| Canny | 81 | 260 | 894 | - | 32 | 108 | 375 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| **Hough tranformations** | |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| HoughLines | 392 | 897 | - | - | 313 | 681 | 2121 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| HoughLines probabilistic | 699 | 1652 | - | - | 608 | 1358 | 3766 | - |
+------------------------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+

View File

@ -1,129 +0,0 @@
============================== Thresholding tests ==============================
Image 160x120 -------------------------
Binary threshold 2 [ms]
Triangle threshold 3 [ms]
OTSU threshold 6 [ms]
To zero threshold 2 [ms]
Image 320x240 -------------------------
Binary threshold 10 [ms]
Triangle threshold 17 [ms]
OTSU threshold 19 [ms]
To zero threshold 10 [ms]
Image 640x480 -------------------------
Binary threshold 42 [ms]
Triangle threshold 66 [ms]
OTSU threshold 68 [ms]
To zero threshold 42 [ms]
================================ Blurring tests ================================
Image 160x120 -------------------------
GaussianBlur9x9 33 [ms]
medianBlur9x9 53 [ms]
bilateralFilter 137 [ms]
Image 320x240 -------------------------
GaussianBlur9x9 128 [ms]
medianBlur9x9 272 [ms]
bilateralFilter 534 [ms]
Image 640x480 -------------------------
GaussianBlur9x9 503 [ms]
medianBlur9x9 1424 [ms]
bilateralFilter 2118 [ms]
======================= Morphology transformations tests =======================
Image 160x120 -------------------------
erode 8 [ms]
dilate 8 [ms]
open 14 [ms]
Image 320x240 -------------------------
erode 30 [ms]
dilate 30 [ms]
open 57 [ms]
Image 640x480 -------------------------
erode 117 [ms]
dilate 117 [ms]
open 224 [ms]
================================ Resizing tests ================================
Image 160x120 -------------------------
linear resize 3 [ms]
cubic resize 6 [ms]
pyrUp 11 [ms]
Image 320x240 -------------------------
linear resize 16 [ms]
cubic resize 26 [ms]
pyrUp 49 [ms]
Image 640x480 -------------------------
linear resize 59 [ms]
cubic resize 107 [ms]
pyrUp 195 [ms]
============================= Edge detection tests =============================
Image 160x120 -------------------------
Sobel 14 [ms]
Canny: 35 [ms]
Image 320x240 -------------------------
Sobel 49 [ms]
Canny: 123 [ms]
Image 640x480 -------------------------
Sobel 186 [ms]
Canny: 462 [ms]
============================= Hough transform tests ============================
Image 160x120 -------------------------
HoughLines 847 [ms]
HoughLineP 1580 [ms]
Image 320x240 -------------------------
HoughLines 3121 [ms]
HoughLineP 6209 [ms]
Image 640x480 -------------------------
HoughLines 9954 [ms]
HoughLineP 17904 [ms]
OpenCV compiled with:
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DESP32=ON \
-DBUILD_SHARED_LIBS=OFF \
-DCV_DISABLE_OPTIMIZATION=OFF \
-DWITH_IPP=OFF \
-DWITH_TBB=OFF \
-DWITH_OPENMP=OFF \
-DWITH_PTHREADS_PF=OFF \
-DWITH_QUIRC=OFF \
-DWITH_1394=OFF \
-DWITH_CUDA=OFF \
-DWITH_OPENCL=OFF \
-DWITH_OPENCLAMDFFT=OFF \
-DWITH_OPENCLAMDBLAS=OFF \
-DWITH_VA_INTEL=OFF \
-DWITH_EIGEN=OFF \
\
-DWITH_GSTREAMER=OFF \
-DWITH_GTK=OFF \
-DWITH_JASPER=OFF \
-DWITH_JPEG=OFF \
-DWITH_WEBP=OFF \
-DBUILD_ZLIB=ON \
-DBUILD_PNG=ON \
-DWITH_TIFF=OFF \
-DWITH_V4L=OFF \
-DWITH_LAPACK=OFF \
-DWITH_ITT=OFF \
-DWITH_PROTOBUF=OFF \
-DWITH_IMGCODEC_HDR=OFF \
-DWITH_IMGCODEC_SUNRASTER=OFF \
-DWITH_IMGCODEC_PXM=OFF \
-DWITH_IMGCODEC_PFM=OFF \
\
-DBUILD_LIST=core,imgproc,imgcodecs \
-DBUILD_JAVA=OFF \
-DBUILD_opencv_python=OFF \
-DBUILD_opencv_java=OFF \
\
-DBUILD_opencv_apps=OFF \
-DBUILD_PACKAGE=OFF \
-DBUILD_PERF_TESTS=OFF \
-DBUILD_TESTS=OFF \
-DCV_ENABLE_INTRINSICS=OFF \
-DCV_TRACE=OFF \
-DOPENCV_ENABLE_MEMALIGN=OFF \
\
-DCMAKE_TOOLCHAIN_FILE=~/esp/esp-idf/tools/cmake/toolchain-esp32.cmake \
..

View File

@ -2,6 +2,7 @@ idf_component_register(
SRCS
main.cpp
system.cpp
report.cpp
INCLUDE_DIRS
.
./opencv

View File

@ -11,21 +11,18 @@
#include <chrono>
#include <iostream>
#include <sys/unistd.h>
#include <pthread.h>
#include <thread>
#include <tuple>
#include "system.hpp"
#include "measure.hpp"
#include "report.hpp"
using namespace cv;
using namespace std;
const char* TAG="opencv_tests";
const int REPEAT = 3; // number of times to repeat the function call for the average
const int NB_IMAGES = 3; // number of images with different resolutions for the tests
const String images_res[] = {"160x120", "320x240", "640x480"};
extern "C" {
void app_main(void);
@ -44,83 +41,104 @@ Mat read_image_specific_res(const String &fileName)
return img;
}
void test_thresholds(const Mat &src)
{
Mat dst;
// apply thresholds
BENCHMARK_MS("Binary threshold", REPEAT, threshold, src, dst, 128, 255, THRESH_BINARY);
BENCHMARK_MS("Triangle threshold", REPEAT, threshold, src, dst, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
BENCHMARK_MS("OTSU threshold", REPEAT, threshold, src, dst, 0, 255, THRESH_BINARY | THRESH_OTSU);
BENCHMARK_MS("To zero threshold", REPEAT, threshold, src, dst, 128, 255, THRESH_TOZERO);
int64_t BM_binThresh(const Mat& src) {
Mat dst;
return BENCHMARK(threshold, src, dst, 128, 255, THRESH_BINARY);
}
void test_blurring(const Mat &src)
{
int64_t BM_triangleThresh(const Mat& src) {
Mat dst;
// apply blurs
BENCHMARK_MS("GaussianBlur9x9", REPEAT, GaussianBlur, src, dst, Size(9, 9), 0, 0, BORDER_DEFAULT);
BENCHMARK_MS("medianBlur9x9", REPEAT, medianBlur, src, dst, 9);
BENCHMARK_MS("bilateralFilter", REPEAT, bilateralFilter, src, dst, 9, 18, 5, BORDER_DEFAULT);
return BENCHMARK(threshold, src, dst, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
}
void test_morphology_transform(const Mat &src)
{
int64_t BM_OTSUThresh(const Mat& src) {
Mat dst;
// create a kernel for the transformation
Mat element = getStructuringElement(MORPH_RECT, Size(9, 9), Point(4, 4));
// apply transformations
BENCHMARK_MS("erode", REPEAT, erode, src, dst, element, Point(-1,-1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue());
BENCHMARK_MS("dilate", REPEAT, dilate, src, dst, element, Point(-1,-1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue());
BENCHMARK_MS("open", REPEAT, morphologyEx, src, dst, MORPH_OPEN, element, Point(-1,-1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue());
return BENCHMARK(threshold, src, dst, 0, 255, THRESH_OTSU | THRESH_BINARY);
}
void test_resize(const Mat &src)
{
int64_t BM_toZeroThresh(const Mat& src) {
Mat dst;
BENCHMARK_MS("linear resize", REPEAT, resize, src, dst, Size(), 0.75, 0.75, INTER_LINEAR);
BENCHMARK_MS("cubic resize", REPEAT, resize, src, dst, Size(), 0.75, 0.75, INTER_CUBIC);
BENCHMARK_MS("pyrUp", REPEAT, pyrUp, src, dst, Size(), BORDER_DEFAULT);
// FIXME: pyrDown uses a lot of stack and then causes the next function to crash with a LoadProhibited
//BENCHMARK_MS("pyrDown", REPEAT, pyrDown, src, dst, Size(), BORDER_DEFAULT);
return BENCHMARK(threshold, src, dst, 128, 255, THRESH_TOZERO);
}
void test_edge_detect(const Mat &src)
{
int64_t BM_GaussianBlur9x9(const Mat& src) {
Mat dst;
return BENCHMARK(GaussianBlur, src, dst, Size(9, 9), 0, 0, BORDER_DEFAULT);
}
BENCHMARK_MS("Sobel", REPEAT, Sobel, src, dst, 2, 2, 1, 3, 1, 0, BORDER_DEFAULT);
//BENCHMARK_MS("Canny", REPEAT, Canny, src, dst, 8, 24, 3, false); // FIXME: can't deduce template parameter 'F'
Canny(src, dst, 8, 24, 3, false); // cache warm up
int64_t BM_medianBlur9x9(const Mat& src) {
Mat dst;
return BENCHMARK(medianBlur, src, dst, 9);
}
int64_t BM_bilateralFilter(const Mat& src) {
Mat dst;
return BENCHMARK(bilateralFilter, src, dst, 9, 18, 5, BORDER_DEFAULT);
}
int64_t BM_erode(const Mat& src) {
Mat dst;
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(4, 4));
return BENCHMARK(erode, src, dst, element, Point(-1,-1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue());
}
int64_t BM_dilate(const Mat& src) {
Mat dst;
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(4, 4));
return BENCHMARK(dilate, src, dst, element, Point(-1,-1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue());
}
int64_t BM_open(const Mat& src) {
Mat dst;
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(4, 4));
return BENCHMARK(morphologyEx, src, dst, MORPH_OPEN, element, Point(-1,-1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue());
}
int64_t BM_resizeLinear(const Mat& src) {
Mat dst;
return BENCHMARK(resize, src, dst, Size(), 0.75, 0.75, INTER_LINEAR);
}
int64_t BM_resizeCubic(const Mat& src) {
Mat dst;
return BENCHMARK(resize, src, dst, Size(), 0.75, 0.75, INTER_CUBIC);
}
int64_t BM_Sobel(const Mat& src) {
Mat dst;
return BENCHMARK(Sobel, src, dst, 2, 2, 1, 3, 1, 0, BORDER_DEFAULT);
}
int64_t BM_Canny(const Mat& src) {
Mat dst;
Canny(src, dst, 50, 200, 3, false); // cache warm up
auto start = chrono::system_clock::now();
Canny(src, dst, 8, 24, 3, false);
auto duration = chrono::duration_cast<chrono::milliseconds >(chrono::system_clock::now() - start);
std::cout << "Canny" << ": " << duration.count() << " [" << "ms" << "]" << std::endl;
Canny(src, dst, 50, 200, 3, false);
auto duration = chrono::duration_cast<chrono::microseconds >(chrono::system_clock::now() - start);
return duration.count();
}
void test_hough(const Mat &src)
{
int64_t BM_HoughLines(const Mat& src) {
Mat dst, blurred, edge;
blur(src, blurred, Size(3,3));
Canny(blurred, edge, 10, 30, 3, false);
// hough
Canny(blurred, edge, 50, 200, 3, false);
vector<Vec2f> lines;
BENCHMARK_MS("HoughLines", REPEAT, HoughLines, edge, lines, 1, CV_PI/180, 100, 0, 0, 0, CV_PI);
// probabilistic hough
vector<Vec4i> linesP;
BENCHMARK_MS("HoughLineP", REPEAT, HoughLinesP, edge, linesP, 1, CV_PI/180, 100, 80, 0);
return BENCHMARK(HoughLines, edge, lines, 1, CV_PI/180, 100, 0, 0, 0, CV_PI);
}
int64_t BM_HoughLinesP(const Mat& src) {
Mat dst, blurred, edge;
blur(src, blurred, Size(3,3));
Canny(blurred, edge, 50, 200, 3, false);
vector<Vec4i> linesP;
return BENCHMARK(HoughLinesP, edge, linesP, 1, CV_PI/180, 100, 80, 0);
}
void app_main(void)
{
pthread_cond_t cond_test = PTHREAD_COND_INITIALIZER;
pthread_cond_init(&cond_test, nullptr);
unsigned ncpus = std::thread::hardware_concurrency();
ESP_LOGI(TAG, "Number of CPU with std::thread::hardware_concurrency() = %d", ncpus);
ESP_LOGI(TAG, "Starting main");
disp_mem_infos();
@ -128,58 +146,46 @@ void app_main(void)
init_spiffs();
/* Read the images for the tests */
Mat src = read_image_specific_res("/spiffs/"+images_res[0]+".png");
Mat src2 = read_image_specific_res("/spiffs/"+images_res[1]+".png");
Mat src3 = read_image_specific_res("/spiffs/"+images_res[2]+".png");
vector<Mat> matrices;
matrices.push_back(src);
matrices.push_back(src2);
matrices.push_back(src3);
// TODO: rename measure.hpp in benchmark.hpp and add printHeader method
// TODO: make an array of function and call them from a single loop
/* Conversions and thresholds tests */
printf("============================== Thresholding tests ==============================\n");
for(int i = 0; i < NB_IMAGES; i++) {
printf("Image %s -------------------------\n", images_res[i].c_str());
test_thresholds(matrices[i]);
const vector<string> images_res = {"160x120", "320x240", "640x480", "1024x768"};
imagesList testImages;
for(const String &res : images_res) {
testImages.push_back(tuple<string, const Mat&>(res, read_image_specific_res("/spiffs/"+res+".png")));
}
/* Blurring tests */
printf("================================ Blurring tests ================================\n");
for(int i = 0; i < NB_IMAGES; i++) {
printf("Image %s -------------------------\n", images_res[i].c_str());
test_blurring(matrices[i]);
}
Report report("BUILD_TYPE=Release", testImages);
/* Morphology transformations */
printf("======================= Morphology transformations tests =======================\n");
for(int i = 0; i < NB_IMAGES; i++) {
printf("Image %s -------------------------\n", images_res[i].c_str());
test_morphology_transform(matrices[i]);
}
TestGroup &thresholds = report.addGroup("Threshold");
thresholds.addTestCase(TestCase("binaryThreshold", BM_binThresh));
thresholds.addTestCase(TestCase("triangleThreshold", BM_triangleThresh));
thresholds.addTestCase(TestCase("OTSUThreshold", BM_OTSUThresh));
thresholds.addTestCase(TestCase("toZeroThreshold", BM_toZeroThresh));
/* Edge detection */
printf("================================ Resizing tests ================================\n");
for(int i = 0; i < NB_IMAGES; i++) {
printf("Image %s -------------------------\n", images_res[i].c_str());
test_resize(matrices[i]);
}
TestGroup &blurrings = report.addGroup("Blurring");
blurrings.addTestCase(TestCase("GaussianBlur 9x9 kernel", BM_GaussianBlur9x9));
blurrings.addTestCase(TestCase("medianBlur 9x9 kernel", BM_medianBlur9x9));
blurrings.addTestCase(TestCase("bilateralFilter diameter=9", BM_bilateralFilter));
/* Image resizing */
printf("============================= Edge detection tests =============================\n");
for(int i = 0; i < NB_IMAGES; i++) {
printf("Image %s -------------------------\n", images_res[i].c_str());
test_edge_detect(matrices[i]);
}
TestGroup &morph = report.addGroup("Morphological tranforms");
morph.addTestCase(TestCase("erode 5x5 kernel", BM_erode));
morph.addTestCase(TestCase("dilate 5x5 kernel", BM_dilate));
morph.addTestCase(TestCase("open 5x5 kernel", BM_open));
/* Hough transform */
printf("============================= Hough transform tests ============================\n");
for(int i = 0; i < NB_IMAGES; i++) {
printf("Image %s -------------------------\n", images_res[i].c_str());
test_hough(matrices[i]);
}
TestGroup &resize = report.addGroup("Resize image");
resize.addTestCase(TestCase("resize linear interpolation", BM_resizeLinear));
resize.addTestCase(TestCase("resize cubic interpolation", BM_resizeCubic));
TestGroup &edgeDetect = report.addGroup("Edge detection");
edgeDetect.addTestCase(TestCase("Sobel", BM_Sobel));
edgeDetect.addTestCase(TestCase("Canny", BM_Canny));
TestGroup &houghTransform = report.addGroup("Hough tranformations");
houghTransform.addTestCase(TestCase("HoughLines", BM_HoughLines));
houghTransform.addTestCase(TestCase("HoughLines probabilistic", BM_HoughLinesP));
report.startBenchmark();
string summary = report.getSummary();
cout << summary << endl;
ESP_LOGI(TAG, "End of main");
}

View File

@ -1,103 +0,0 @@
//
// Helper to measure time taken by functions
//
// Code taken from https://github.com/picanumber/bureaucrat/blob/master/time_lapse.h
//
#ifndef MEASURE_HPP
#define MEASURE_HPP
#include <chrono>
#include <iostream>
#include <string>
/*
* @brief Macro to simplify the benchmark() function usage.
* - more concise
* - already fill the unit type
*
* @param name (String) representing the name of the function (for the log)
* @param repeat (Int) number of times to call the function for the time average
* @param fct (F type) function to call
* @param ... (Args type) arguments of the function to call
*
* Usage examples:
* - without macro:
* measure<std::chrono::milliseconds>::benchmark("ms", "medianBlur", repeat, medianBlur, src, dst, 9);
* - with macro:
* BENCHMARK_MS("medianBlur", repeat, medianBlur, src, dst, 9);
*/
#define BENCHMARK_NS(name, repeat, fct, ...) measure<std::chrono::nanoseconds>::benchmark("ns", name, repeat, fct, __VA_ARGS__)
#define BENCHMARK_US(name, repeat, fct, ...) measure<std::chrono::microseconds>::benchmark("us", name, repeat, fct, __VA_ARGS__)
#define BENCHMARK_MS(name, repeat, fct, ...) measure<std::chrono::milliseconds>::benchmark("ms", name, repeat, fct, __VA_ARGS__)
#define BENCHMARK_S(name, repeat, fct, ...) measure<std::chrono::seconds>::benchmark("s", name, repeat, fct, __VA_ARGS__)
#define fw(what) std::forward<decltype(what)>(what)
/**
* @ class measure
* @ brief Class to measure the execution time of a callable
*/
template <
typename TimeT = std::chrono::milliseconds, class ClockT = std::chrono::system_clock
>
struct measure
{
/**
* @ fn execution
* @ brief Returns the quantity (count) of the elapsed time as TimeT units
*/
template<typename F, typename ...Args>
static typename TimeT::rep execution(F&& func, Args&&... args)
{
auto start = ClockT::now();
fw(func)(std::forward<Args>(args)...);
auto duration = std::chrono::duration_cast<TimeT>(ClockT::now() - start);
return duration.count();
}
/**
* Function that executes the function 'repeat' times, measure the average time taken and logs on the console
* the time.
* @tparam F
* @tparam Args
* @param unit String representing the time unit (for the log). Can be either 's', 'ms', 'us' or 'ns'
* @param repeat Number of times to do the measure
* @param func Function to benchmark
* @param args Arguments of the function 'func'
*/
template<typename F, typename... Args>
static void benchmark(const std::string &unit, const std::string &name, int repeat, F&& func, Args&&... args)
{
auto avg = duration(func, (args)...);
for(int i = 0; i < repeat-1; i++) {
avg += duration(func, (args)...);
}
std::cout << name << "\t " << (avg / repeat).count() << " [" << unit << "]" << std::endl;
}
/**
* @ fn duration
* @ brief Returns the duration (in chrono's type system) of the elapsed time
*/
template<typename F, typename... Args>
static TimeT duration(F&& func, Args&&... args)
{
auto start = ClockT::now();
fw(func)(std::forward<Args>(args)...);
return std::chrono::duration_cast<TimeT>(ClockT::now() - start);
}
};
#undef fw
#endif // MEASURE_HPP

View File

@ -0,0 +1,208 @@
//
// Created by joachim on 01.04.20.
//
#include "report.hpp"
#include <utility>
#include <iomanip>
using namespace std;
// TestCase class
TestCase::TestCase(string _name, int _iterations, function<int(const cv::Mat &)> _func) :
name(move(_name)), iterations(_iterations), func(move(_func)) {}
TestCase::TestCase(string _name, function<int(const cv::Mat &)> _func) :
TestCase(move(_name), DEFAULT_ITERATIONS, move(_func)) {}
void TestCase::executeOn(const imagesList &testImages) {
for(auto img : testImages) {
float timeTaken;
try {
timeTaken = (float) func(get<1>(img)) / 1000.0f;
} catch(cv::Exception& e) {
cout << "Exception while trying to execute function " << name << " on image " << get<0>(img) << " :\n" << e.msg;
timeTaken = -1;
}
resultTime.push_back(timeTaken);
cout << "Testing " << name << " on " << get<0>(img) << " took "
<< resultTime.back() << " [ms] (in " << iterations << " iterations)" << endl;
}
}
// TestGroup class
TestGroup::TestGroup(string _name) : name(move(_name)) {}
void TestGroup::addTestCase(const TestCase &test) {
tests.push_back(test);
}
// Report class
Report::Report(string _name, const imagesList& _images) : name(move(_name)), images(_images), summary(_images) {}
TestGroup &Report::addGroup(const string &_name) {
groups.push_back(TestGroup(_name));
return groups.back();
}
TestGroup &Report::getGroup(const string &_name) {
auto it = find_if(groups.begin(), groups.end(), [&_name] (const TestGroup& g) {return (g.name == _name);});
if(it == groups.end()) {
cout << "group not found!" << endl;
return *it; // todo: exception?
}
else {
return *it;
}
}
void Report::startBenchmark() {
cout << "starting benchmark with " << images.size() << " images, " << groups.size() << " groups" << endl;
for(auto& group : groups) {
cout << "Group contains " << group.tests.size() << " testcases" << endl;
for(auto& test : group.tests) {
test.executeOn(images);
}
}
}
string Report::getSummary() {
string sum;
sum += summary.summaryHeader(name);
for(const auto& group : groups) {
sum += summary.summarySection(group);
for(const auto& test : group.tests) {
sum += summary.summaryTest(test);
}
}
return sum;
}
// Summary class
Summary::Summary(imagesList _images) : images(move(_images)) {
// Fill the columns width vector
columnsWidth.push_back(COL1_WIDTH);
for(int i = 0; i < images.size(); i++) {
columnsWidth.push_back(COL_VALUES_WIDTH);
}
// Get the total width FIXME: columns width and alignment is a bit messy
totalWidth = 0;
for (auto& w : columnsWidth)
totalWidth += (w-1);
totalWidth += 1;
}
string Summary::lineSeparator(const char sep) {
string line;
for(int size : columnsWidth) {
line += "+";
line += string(size-2, sep);
}
line += "+\n";
return line;
}
string Summary::alignTextLeft(const string &text, int colWidth) {
string s;
s += " " + text;
s += string(colWidth - text.size() - 3, ' ');
return s;
}
string Summary::alignTextRight(const string &text, int colWidth) {
string s;
s += string(colWidth - text.size() - 3, ' ');
s += text + " ";
return s;
}
string Summary::alignTextCenter(const string &text, int colWidth) {
string s;
int spaces = colWidth - text.size() - 2;
s += string(spaces/2, ' ') + text + string(spaces/2, ' ');
s += (spaces % 2 != 0) ? " " : "";
return s;
}
string Summary::lineText(const vector<string> &colTexts) {
string line;
int numOfTextCol = colTexts.size();
int remainingWidth = totalWidth;
for(int c = 0; c < numOfTextCol; c++) {
// if last text but not last column, fit it in the rest of the row
line += "|";
if((c == numOfTextCol-1) && (c < columnsWidth.size()-1)) {
line += alignTextLeft(colTexts[c], remainingWidth);
}
else {
// align text left on first col, right on the rest
line += (c==0 ? alignTextLeft(colTexts[c], columnsWidth.at(c)) : alignTextRight(colTexts[c], columnsWidth.at(c)));
remainingWidth -= (columnsWidth.at(c)-1);
}
}
line += "|\n";
return line;
}
string Summary::summaryHeader(const string &reportName) {
string summaryHeaderLines;
// extract images names
vector<string> imagesNames;
for(auto img : images) {
imagesNames.push_back(get<0>(img));
}
imagesNames.insert(imagesNames.begin(), "");
summaryHeaderLines += lineSeparator('-');
summaryHeaderLines += lineText({"Function name and arguments", reportName});
summaryHeaderLines += lineSeparator('-');
summaryHeaderLines += lineText(imagesNames);
summaryHeaderLines += lineSeparator('-');
summaryHeaderLines += lineText({"Measures are in [ms]"});
summaryHeaderLines += lineSeparator('=');
return summaryHeaderLines;
}
string Summary::summarySection(const TestGroup &group) {
string summarySectionLines;
summarySectionLines += lineText({""});
summarySectionLines += lineSeparator('-');
summarySectionLines += lineText({"**" + group.name + "**"});
summarySectionLines += lineSeparator('-');
return summarySectionLines;
}
string Summary::summaryTest(const TestCase &test) {
string summaryTestLines;
vector<string> text;
// fill text vector with name and values
text.push_back(test.name);
for(auto res : test.resultTime) {
string value;
if(res == -1) {
value = " - ";
}
else {
stringstream ss;
ss << fixed << setprecision(((res < 10) ? 1 : 0)) << res;
value = ss.str();
}
text.push_back(value);
}
summaryTestLines += lineText(text);
summaryTestLines += lineSeparator('-');
return summaryTestLines;
}

View File

@ -0,0 +1,167 @@
//
// Helper to benchmark time taken by functions
//
// Code taken from https://github.com/picanumber/bureaucrat/blob/master/time_lapse.h
// and https://github.com/espressif/esp-dsp/blob/master/test/report.inc
//
#ifndef REPORT_HPP
#define REPORT_HPP
#include <opencv2/core.hpp>
#include <chrono>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <string>
#include <algorithm>
#define BENCHMARK(fct, ...) Report::benchmark(fct, __VA_ARGS__)
using functionSignature = std::function<int (const cv::Mat&)>;
using imagesList = std::vector<std::tuple<std::string, cv::Mat> >;
#define fw(what) std::forward<decltype(what)>(what)
// ==============
// class TestCase
// ==============
class TestCase
{
public:
static constexpr int DEFAULT_ITERATIONS = 3;
std::string name;
std::vector<float> resultTime;
int iterations;
functionSignature func;
TestCase(std::string _name, int _iterations, functionSignature _func);
TestCase(std::string _name, functionSignature _func);
void executeOn(const imagesList &testImages);
};
// ===============
// class TestGroup
// ===============
class TestGroup
{
public:
std::string name;
std::vector<TestCase> tests;
explicit TestGroup(std::string _name);
void addTestCase(const TestCase& test);
};
// =============
// class Summary
// =============
class Summary
{
private:
const int COL1_WIDTH = 50;
const int COL_VALUES_WIDTH = 15;
imagesList images;
std::vector<int> columnsWidth;
int totalWidth;
std::string lineSeparator(const char sep);
std::string alignTextLeft(const std::string &text, int colWidth);
std::string alignTextRight(const std::string &text, int colWidth);
std::string alignTextCenter(const std::string &text, int colWidth);
std::string lineText(const std::vector<std::string>& colTexts);
public:
Summary(imagesList _images);
std::string summaryHeader(const std::string &reportName);
std::string summarySection(const TestGroup& group);
std::string summaryTest(const TestCase& test);
};
// ============
// class Report
// ============
class Report
/**
* @ class report
* @ brief Class to report a benchmark of image processing functions
*/
{
private:
std::string name;
std::vector<TestGroup> groups;
imagesList images;
Summary summary;
public:
explicit Report(std::string _name, const imagesList& _images);
TestGroup& addGroup(const std::string &_name);
TestGroup& getGroup(const std::string &_name);
void startBenchmark();
std::string getSummary();
/**
* Function that executes the function 'repeat' times, benchmark the average time taken and logs on the console
* the time.
* @tparam F
* @tparam Args
* @param unit String representing the time unit (for the log). Can be either 's', 'ms', 'us' or 'ns'
* @param repeat Number of times to do the benchmark
* @param func Function to benchmark
* @param args Arguments of the function 'func'
*/
template<typename F, typename... Args>
static int64_t benchmark(int repeat, F&& func, Args&&... args)
{
auto avg = duration(func, (args)...);
for(int i = 0; i < repeat-1; i++) {
avg += duration(func, (args)...);
}
return (avg/repeat).count();
}
template<typename F, typename... Args>
static int64_t benchmark(F&& func, Args&&... args)
{
const int defaultIterations = 3;
return benchmark(defaultIterations, func, (args)...);
}
using TimeT = std::chrono::microseconds ;
using ClockT = std::chrono::system_clock ;
/**
* @ fn duration
* @ brief Returns the duration (in chrono's type system microseconds) of the elapsed time
*/
template<typename F, typename... Args>
static TimeT duration(F&& func, Args&&... args)
{
auto start = ClockT::now();
fw(func)(std::forward<Args>(args)...);
return std::chrono::duration_cast<TimeT>(ClockT::now() - start);
}
};
#undef fw
#endif // REPORT_HPP

View File

@ -2,5 +2,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 2M,
storage, data, spiffs, , 1M,
factory, app, factory, 0x10000, 3M,
storage, data, spiffs, , 1500k,

1 # Espressif ESP32 Partition Table
2 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 2M, factory, app, factory, 0x10000, 3M,
6 storage, data, spiffs, , 1M, storage, data, spiffs, , 1500k,

View File

@ -83,10 +83,10 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
@ -355,7 +355,7 @@ CONFIG_ADC_CAL_LUT_ENABLE=y
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384
CONFIG_ESP_MAIN_TASK_STACK_SIZE=20480
CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
@ -884,7 +884,7 @@ CONFIG_OPENSSL_ASSERT_DO_NOTHING=y
# PThreads
#
CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192
CONFIG_PTHREAD_STACK_MIN=768
CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
@ -1088,7 +1088,7 @@ CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
# CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
CONFIG_MAIN_TASK_STACK_SIZE=16384
CONFIG_MAIN_TASK_STACK_SIZE=20480
CONFIG_IPC_TASK_STACK_SIZE=1024
CONFIG_CONSOLE_UART_DEFAULT=y
# CONFIG_CONSOLE_UART_CUSTOM is not set
@ -1149,7 +1149,7 @@ CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
# CONFIG_PPP_SUPPORT is not set
CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192
CONFIG_ESP32_PTHREAD_STACK_MIN=768
CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y
# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set

View File

@ -83,10 +83,10 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
@ -355,7 +355,7 @@ CONFIG_ADC_CAL_LUT_ENABLE=y
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384
CONFIG_ESP_MAIN_TASK_STACK_SIZE=20480
CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
@ -567,7 +567,7 @@ CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
@ -884,7 +884,7 @@ CONFIG_OPENSSL_ASSERT_DO_NOTHING=y
# PThreads
#
CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=8192
CONFIG_PTHREAD_STACK_MIN=768
CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 KiB

Some files were not shown because too many files have changed in this diff Show More