diff --git a/3rdparty/carotene/hal/tegra_hal.hpp b/3rdparty/carotene/hal/tegra_hal.hpp index e6a320992e..b91f862d1a 100644 --- a/3rdparty/carotene/hal/tegra_hal.hpp +++ b/3rdparty/carotene/hal/tegra_hal.hpp @@ -1531,7 +1531,7 @@ class TegraCvtColor_##name##_Invoker : public cv::ParallelLoopBody \ public: \ TegraCvtColor_##name##_Invoker(const uchar * src_data_, size_t src_step_, uchar * dst_data_, size_t dst_step_, int width_, int height_) : \ cv::ParallelLoopBody(), src_data(src_data_), src_step(src_step_), dst_data(dst_data_), dst_step(dst_step_), width(width_), height(height_) {} \ - virtual void operator()(const cv::Range& range) const \ + virtual void operator()(const cv::Range& range) const CV_OVERRIDE \ { \ CAROTENE_NS::func(CAROTENE_NS::Size2D(width, range.end-range.start), __VA_ARGS__); \ } \ diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 95e98e6e08..260a08fab6 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,6 +1,39 @@ add_definitions(-D__OPENCV_BUILD=1) add_definitions(-D__OPENCV_APPS=1) +# Unified function for creating OpenCV applications: +# ocv_add_application(tgt [MODULES [ ...]] SRCS [ ...]) +function(ocv_add_application the_target) + cmake_parse_arguments(APP "" "" "MODULES;SRCS" ${ARGN}) + ocv_check_dependencies(${APP_MODULES}) + if(NOT OCV_DEPENDENCIES_FOUND) + return() + endif() + + project(${the_target}) + ocv_target_include_modules_recurse(${the_target} ${APP_MODULES}) + ocv_target_include_directories(${the_target} PRIVATE "${OpenCV_SOURCE_DIR}/include/opencv") + ocv_add_executable(${the_target} ${APP_SRCS}) + ocv_target_link_libraries(${the_target} ${APP_MODULES}) + set_target_properties(${the_target} PROPERTIES + DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" + ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} + RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} + OUTPUT_NAME "${the_target}") + + if(ENABLE_SOLUTION_FOLDERS) + set_target_properties(${the_target} PROPERTIES FOLDER "applications") + endif() + + if(INSTALL_CREATE_DISTRIB) + if(BUILD_SHARED_LIBS) + install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev) + endif() + else() + install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev) + endif() +endfunction() + link_libraries(${OPENCV_LINKER_LIBS}) macro(ocv_add_app directory) diff --git a/apps/annotation/CMakeLists.txt b/apps/annotation/CMakeLists.txt index 9288e86b42..a30846db41 100644 --- a/apps/annotation/CMakeLists.txt +++ b/apps/annotation/CMakeLists.txt @@ -1,36 +1,3 @@ -SET(OPENCV_ANNOTATION_DEPS opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs opencv_videoio) -ocv_check_dependencies(${OPENCV_ANNOTATION_DEPS}) - -if(NOT OCV_DEPENDENCIES_FOUND) - return() -endif() - -project(annotation) -set(the_target opencv_annotation) - -ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv") -ocv_target_include_modules_recurse(${the_target} ${OPENCV_ANNOTATION_DEPS}) - -file(GLOB SRCS *.cpp) - -set(annotation_files ${SRCS}) -ocv_add_executable(${the_target} ${annotation_files}) -ocv_target_link_libraries(${the_target} ${OPENCV_ANNOTATION_DEPS}) - -set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_annotation") - -if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(${the_target} PROPERTIES FOLDER "applications") -endif() - -if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev) - endif() -else() - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev) -endif() +ocv_add_application(opencv_annotation + MODULES opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs opencv_videoio + SRCS opencv_annotation.cpp) diff --git a/apps/createsamples/CMakeLists.txt b/apps/createsamples/CMakeLists.txt index a285c69e41..7fb2b679c2 100644 --- a/apps/createsamples/CMakeLists.txt +++ b/apps/createsamples/CMakeLists.txt @@ -1,38 +1,4 @@ -set(OPENCV_CREATESAMPLES_DEPS opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d opencv_videoio) -ocv_check_dependencies(${OPENCV_CREATESAMPLES_DEPS}) - -if(NOT OCV_DEPENDENCIES_FOUND) - return() -endif() - -project(createsamples) -set(the_target opencv_createsamples) - -ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv") -ocv_target_include_modules_recurse(${the_target} ${OPENCV_CREATESAMPLES_DEPS}) - file(GLOB SRCS *.cpp) -file(GLOB HDRS *.h*) - -set(createsamples_files ${SRCS} ${HDRS}) - -ocv_add_executable(${the_target} ${createsamples_files}) -ocv_target_link_libraries(${the_target} ${OPENCV_CREATESAMPLES_DEPS}) - -set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_createsamples") - -if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(${the_target} PROPERTIES FOLDER "applications") -endif() - -if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev) - endif() -else() - install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev) -endif() +ocv_add_application(opencv_createsamples + MODULES opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d opencv_videoio + SRCS ${SRCS}) diff --git a/apps/interactive-calibration/CMakeLists.txt b/apps/interactive-calibration/CMakeLists.txt index 4a1a7446a8..dacbb13c79 100644 --- a/apps/interactive-calibration/CMakeLists.txt +++ b/apps/interactive-calibration/CMakeLists.txt @@ -1,41 +1,6 @@ -set(OPENCV_INTERACTIVECALIBRATION_DEPS opencv_core opencv_imgproc opencv_features2d opencv_highgui opencv_calib3d opencv_videoio) +set(DEPS opencv_core opencv_imgproc opencv_features2d opencv_highgui opencv_calib3d opencv_videoio) if(${BUILD_opencv_aruco}) - list(APPEND OPENCV_INTERACTIVECALIBRATION_DEPS opencv_aruco) + list(APPEND DEPS opencv_aruco) endif() -ocv_check_dependencies(${OPENCV_INTERACTIVECALIBRATION_DEPS}) - -if(NOT OCV_DEPENDENCIES_FOUND) - return() -endif() - -project(interactive-calibration) -set(the_target opencv_interactive-calibration) - -ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv") -ocv_target_include_modules_recurse(${the_target} ${OPENCV_INTERACTIVECALIBRATION_DEPS}) - file(GLOB SRCS *.cpp) -file(GLOB HDRS *.h*) - -set(interactive-calibration_files ${SRCS} ${HDRS}) - -ocv_add_executable(${the_target} ${interactive-calibration_files}) -ocv_target_link_libraries(${the_target} ${OPENCV_INTERACTIVECALIBRATION_DEPS}) - -set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_interactive-calibration") - -if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(${the_target} PROPERTIES FOLDER "applications") -endif() - -if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev) - endif() -else() - install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev) -endif() +ocv_add_application(opencv_interactive-calibration MODULES ${DEPS} SRCS ${SRCS}) diff --git a/apps/traincascade/CMakeLists.txt b/apps/traincascade/CMakeLists.txt index 96b9781067..ef80ce8b2f 100644 --- a/apps/traincascade/CMakeLists.txt +++ b/apps/traincascade/CMakeLists.txt @@ -1,42 +1,5 @@ -set(OPENCV_TRAINCASCADE_DEPS opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d) -ocv_check_dependencies(${OPENCV_TRAINCASCADE_DEPS}) - -if(NOT OCV_DEPENDENCIES_FOUND) - return() -endif() - -project(traincascade) -set(the_target opencv_traincascade) - -ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual - -Winconsistent-missing-override -Wsuggest-override -) - -ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv") -ocv_target_include_modules_recurse(${the_target} ${OPENCV_TRAINCASCADE_DEPS}) - +ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual -Winconsistent-missing-override -Wsuggest-override) file(GLOB SRCS *.cpp) -file(GLOB HDRS *.h*) - -set(traincascade_files ${SRCS} ${HDRS}) - -ocv_add_executable(${the_target} ${traincascade_files}) -ocv_target_link_libraries(${the_target} ${OPENCV_TRAINCASCADE_DEPS}) - -set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_traincascade") - -if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(${the_target} PROPERTIES FOLDER "applications") -endif() - -if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev) - endif() -else() - install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev) -endif() +ocv_add_application(opencv_traincascade + MODULES opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d + SRCS ${SRCS}) diff --git a/apps/version/CMakeLists.txt b/apps/version/CMakeLists.txt index cc4abb33aa..89e739b1ba 100644 --- a/apps/version/CMakeLists.txt +++ b/apps/version/CMakeLists.txt @@ -1,49 +1,5 @@ -set(OPENCV_APPLICATION_DEPS opencv_core) -ocv_check_dependencies(${OPENCV_APPLICATION_DEPS}) -if(NOT OCV_DEPENDENCIES_FOUND) - return() -endif() - -project(opencv_version) -set(the_target opencv_version) -ocv_target_include_modules_recurse(${the_target} ${OPENCV_APPLICATION_DEPS}) -ocv_add_executable(${the_target} opencv_version.cpp) -ocv_target_link_libraries(${the_target} ${OPENCV_APPLICATION_DEPS}) - -set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_version") - -set_target_properties(${the_target} PROPERTIES FOLDER "applications") - -if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT libs) - endif() -else() - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT libs) -endif() - +ocv_add_application(opencv_version MODULES opencv_core SRCS opencv_version.cpp) if(WIN32) - project(opencv_version_win32) - set(the_target opencv_version_win32) - ocv_target_include_modules_recurse(${the_target} ${OPENCV_APPLICATION_DEPS}) - ocv_add_executable(${the_target} opencv_version.cpp) - ocv_target_link_libraries(${the_target} ${OPENCV_APPLICATION_DEPS}) - target_compile_definitions(${the_target} PRIVATE "OPENCV_WIN32_API=1") - set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_version_win32") - - set_target_properties(${the_target} PROPERTIES FOLDER "applications") - - if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT libs) - endif() - else() - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT libs) - endif() + ocv_add_application(opencv_version_win32 MODULES opencv_core SRCS opencv_version.cpp) + target_compile_definitions(opencv_version_win32 PRIVATE "OPENCV_WIN32_API=1") endif() diff --git a/apps/visualisation/CMakeLists.txt b/apps/visualisation/CMakeLists.txt index 6f748103e4..eaddf776ec 100644 --- a/apps/visualisation/CMakeLists.txt +++ b/apps/visualisation/CMakeLists.txt @@ -1,36 +1,3 @@ -SET(OPENCV_VISUALISATION_DEPS opencv_core opencv_highgui opencv_imgproc opencv_videoio opencv_imgcodecs) -ocv_check_dependencies(${OPENCV_VISUALISATION_DEPS}) - -if(NOT OCV_DEPENDENCIES_FOUND) - return() -endif() - -project(visualisation) -set(the_target opencv_visualisation) - -ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv") -ocv_target_include_modules_recurse(${the_target} ${OPENCV_VISUALISATION_DEPS}) - -file(GLOB SRCS *.cpp) - -set(visualisation_files ${SRCS}) -ocv_add_executable(${the_target} ${visualisation_files}) -ocv_target_link_libraries(${the_target} ${OPENCV_VISUALISATION_DEPS}) - -set_target_properties(${the_target} PROPERTIES - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" - ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - OUTPUT_NAME "opencv_visualisation") - -if(ENABLE_SOLUTION_FOLDERS) - set_target_properties(${the_target} PROPERTIES FOLDER "applications") -endif() - -if(INSTALL_CREATE_DISTRIB) - if(BUILD_SHARED_LIBS) - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev) - endif() -else() - install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev) -endif() +ocv_add_application(opencv_visualisation + MODULES opencv_core opencv_highgui opencv_imgproc opencv_videoio opencv_imgcodecs + SRCS opencv_visualisation.cpp) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 65029ddbff..fae91c165f 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1624,7 +1624,7 @@ endif() macro(ocv_git_describe var_name path) if(GIT_FOUND) - execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --tags --exact-match --dirty + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --exact-match --dirty WORKING_DIRECTORY "${path}" OUTPUT_VARIABLE ${var_name} RESULT_VARIABLE GIT_RESULT diff --git a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown index cb5d0ad4d6..f56e639005 100644 --- a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown +++ b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown @@ -4,32 +4,34 @@ Camera Calibration {#tutorial_py_calibration} Goal ---- -In this section, - - We will learn about distortions in camera, intrinsic and extrinsic parameters of camera etc. - - We will learn to find these parameters, undistort images etc. +In this section, we will learn about + +* types of distortion caused by cameras +* how to find the intrinsic and extrinsic properties of a camera +* how to undistort images based off these properties Basics ------ -Today's cheap pinhole cameras introduces a lot of distortion to images. Two major distortions are +Some pinhole cameras introduce significant distortion to images. Two major kinds of distortion are radial distortion and tangential distortion. -Due to radial distortion, straight lines will appear curved. Its effect is more as we move away from -the center of image. For example, one image is shown below, where two edges of a chess board are -marked with red lines. But you can see that border is not a straight line and doesn't match with the +Radial distortion causes straight lines to appear curved. Radial distortion becomes larger the farther points are from +the center of the image. For example, one image is shown below in which two edges of a chess board are +marked with red lines. But, you can see that the border of the chess board is not a straight line and doesn't match with the red line. All the expected straight lines are bulged out. Visit [Distortion (optics)](http://en.wikipedia.org/wiki/Distortion_%28optics%29) for more details. ![image](images/calib_radial.jpg) -This distortion is represented as follows: +Radial distortion can be represented as follows: \f[x_{distorted} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \\ y_{distorted} = y( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6)\f] -Similarly, another distortion is the tangential distortion which occurs because image taking lense -is not aligned perfectly parallel to the imaging plane. So some areas in image may look nearer than -expected. It is represented as below: +Similarly, tangential distortion occurs because the image-taking lense +is not aligned perfectly parallel to the imaging plane. So, some areas in the image may look nearer than +expected. The amount of tangential distortion can be represented as below: \f[x_{distorted} = x + [ 2p_1xy + p_2(r^2+2x^2)] \\ y_{distorted} = y + [ p_1(r^2+ 2y^2)+ 2p_2xy]\f] @@ -38,10 +40,9 @@ In short, we need to find five parameters, known as distortion coefficients give \f[Distortion \; coefficients=(k_1 \hspace{10pt} k_2 \hspace{10pt} p_1 \hspace{10pt} p_2 \hspace{10pt} k_3)\f] -In addition to this, we need to find a few more information, like intrinsic and extrinsic parameters -of a camera. Intrinsic parameters are specific to a camera. It includes information like focal -length (\f$f_x,f_y\f$), optical centers (\f$c_x, c_y\f$) etc. It is also called camera matrix. It depends on -the camera only, so once calculated, it can be stored for future purposes. It is expressed as a 3x3 +In addition to this, we need to some other information, like the intrinsic and extrinsic parameters +of the camera. Intrinsic parameters are specific to a camera. They include information like focal +length (\f$f_x,f_y\f$) and optical centers (\f$c_x, c_y\f$). The focal length and optical centers can be used to create a camera matrix, which can be used to remove distortion due to the lenses of a specific camera. The camera matrix is unique to a specific camera, so once calculated, it can be reused on other images taken by the same camera. It is expressed as a 3x3 matrix: \f[camera \; matrix = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ]\f] @@ -49,20 +50,16 @@ matrix: Extrinsic parameters corresponds to rotation and translation vectors which translates a coordinates of a 3D point to a coordinate system. -For stereo applications, these distortions need to be corrected first. To find all these parameters, -what we have to do is to provide some sample images of a well defined pattern (eg, chess board). We -find some specific points in it ( square corners in chess board). We know its coordinates in real -world space and we know its coordinates in image. With these data, some mathematical problem is -solved in background to get the distortion coefficients. That is the summary of the whole story. For -better results, we need atleast 10 test patterns. +For stereo applications, these distortions need to be corrected first. To find these parameters, +we must provide some sample images of a well defined pattern (e.g. a chess board). We +find some specific points of which we already know the relative positions (e.g. square corners in the chess board). We know the coordinates of these points in real world space and we know the coordinates in the image, so we can solve for the distortion coefficients. For better results, we need at least 10 test patterns. Code ---- -As mentioned above, we need atleast 10 test patterns for camera calibration. OpenCV comes with some -images of chess board (see samples/cpp/left01.jpg -- left14.jpg), so we will utilize it. For sake of -understanding, consider just one image of a chess board. Important input datas needed for camera -calibration is a set of 3D real world points and its corresponding 2D image points. 2D image points +As mentioned above, we need at least 10 test patterns for camera calibration. OpenCV comes with some +images of a chess board (see samples/data/left01.jpg -- left14.jpg), so we will utilize these. Consider an image of a chess board. The important input data needed for calibration of the camera +is the set of 3D real world points and the corresponding 2D coordinates of these points in the image. 2D image points are OK which we can easily find from the image. (These image points are locations where two black squares touch each other in chess boards) @@ -72,7 +69,7 @@ values. But for simplicity, we can say chess board was kept stationary at XY pla and camera was moved accordingly. This consideration helps us to find only X,Y values. Now for X,Y values, we can simply pass the points as (0,0), (1,0), (2,0), ... which denotes the location of points. In this case, the results we get will be in the scale of size of chess board square. But if -we know the square size, (say 30 mm), and we can pass the values as (0,0),(30,0),(60,0),..., we get +we know the square size, (say 30 mm), we can pass the values as (0,0), (30,0), (60,0), ... . Thus, we get the results in mm. (In this case, we don't know square size since we didn't take those images, so we pass in terms of square size). @@ -80,23 +77,22 @@ pass in terms of square size). ### Setup -So to find pattern in chess board, we use the function, **cv.findChessboardCorners()**. We also -need to pass what kind of pattern we are looking, like 8x8 grid, 5x5 grid etc. In this example, we +So to find pattern in chess board, we can use the function, **cv.findChessboardCorners()**. We also +need to pass what kind of pattern we are looking for, like 8x8 grid, 5x5 grid etc. In this example, we use 7x6 grid. (Normally a chess board has 8x8 squares and 7x7 internal corners). It returns the corner points and retval which will be True if pattern is obtained. These corners will be placed in an order (from left-to-right, top-to-bottom) -@sa This function may not be able to find the required pattern in all the images. So one good option +@sa This function may not be able to find the required pattern in all the images. So, one good option is to write the code such that, it starts the camera and check each frame for required pattern. Once -pattern is obtained, find the corners and store it in a list. Also provides some interval before +the pattern is obtained, find the corners and store it in a list. Also, provide some interval before reading next frame so that we can adjust our chess board in different direction. Continue this -process until required number of good patterns are obtained. Even in the example provided here, we -are not sure out of 14 images given, how many are good. So we read all the images and take the good +process until the required number of good patterns are obtained. Even in the example provided here, we +are not sure how many images out of the 14 given are good. Thus, we must read all the images and take only the good ones. -@sa Instead of chess board, we can use some circular grid, but then use the function -**cv.findCirclesGrid()** to find the pattern. It is said that less number of images are enough when -using circular grid. +@sa Instead of chess board, we can alternatively use a circular grid. In this case, we must use the function +**cv.findCirclesGrid()** to find the pattern. Fewer images are sufficient to perform camera calibration using a circular grid. Once we find the corners, we can increase their accuracy using **cv.cornerSubPix()**. We can also draw the pattern using **cv.drawChessboardCorners()**. All these steps are included in below code: @@ -146,22 +142,23 @@ One image with pattern drawn on it is shown below: ### Calibration -So now we have our object points and image points we are ready to go for calibration. For that we -use the function, **cv.calibrateCamera()**. It returns the camera matrix, distortion coefficients, +Now that we have our object points and image points, we are ready to go for calibration. We can +use the function, **cv.calibrateCamera()** which returns the camera matrix, distortion coefficients, rotation and translation vectors etc. @code{.py} ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) @endcode + ### Undistortion -We have got what we were trying. Now we can take an image and undistort it. OpenCV comes with two -methods, we will see both. But before that, we can refine the camera matrix based on a free scaling +Now, we can take an image and undistort it. OpenCV comes with two +methods for doing this. However first, we can refine the camera matrix based on a free scaling parameter using **cv.getOptimalNewCameraMatrix()**. If the scaling parameter alpha=0, it returns undistorted image with minimum unwanted pixels. So it may even remove some pixels at image corners. -If alpha=1, all pixels are retained with some extra black images. It also returns an image ROI which +If alpha=1, all pixels are retained with some extra black images. This function also returns an image ROI which can be used to crop the result. -So we take a new image (left12.jpg in this case. That is the first image in this chapter) +So, we take a new image (left12.jpg in this case. That is the first image in this chapter) @code{.py} img = cv.imread('left12.jpg') h, w = img.shape[:2] @@ -169,7 +166,7 @@ newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h)) @endcode #### 1. Using **cv.undistort()** -This is the shortest path. Just call the function and use ROI obtained above to crop the result. +This is the easiest way. Just call the function and use ROI obtained above to crop the result. @code{.py} # undistort dst = cv.undistort(img, mtx, dist, None, newcameramtx) @@ -181,7 +178,7 @@ cv.imwrite('calibresult.png', dst) @endcode #### 2. Using **remapping** -This is curved path. First find a mapping function from distorted image to undistorted image. Then +This way is a little bit more difficult. First, find a mapping function from the distorted image to the undistorted image. Then use the remap function. @code{.py} # undistort @@ -193,23 +190,22 @@ x, y, w, h = roi dst = dst[y:y+h, x:x+w] cv.imwrite('calibresult.png', dst) @endcode -Both the methods give the same result. See the result below: +Still, both the methods give the same result. See the result below: ![image](images/calib_result.jpg) You can see in the result that all the edges are straight. -Now you can store the camera matrix and distortion coefficients using write functions in Numpy +Now you can store the camera matrix and distortion coefficients using write functions in NumPy (np.savez, np.savetxt etc) for future uses. Re-projection Error ------------------- -Re-projection error gives a good estimation of just how exact is the found parameters. This should -be as close to zero as possible. Given the intrinsic, distortion, rotation and translation matrices, -we first transform the object point to image point using **cv.projectPoints()**. Then we calculate +Re-projection error gives a good estimation of just how exact the found parameters are. The closer the re-projection error is to zero, the more accurate the parameters we found are. Given the intrinsic, distortion, rotation and translation matrices, +we must first transform the object point to image point using **cv.projectPoints()**. Then, we can calculate the absolute norm between what we got with our transformation and the corner finding algorithm. To -find the average error we calculate the arithmetical mean of the errors calculate for all the +find the average error, we calculate the arithmetical mean of the errors calculated for all the calibration images. @code{.py} mean_error = 0 diff --git a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown index 1326bc5126..896b5f7d0c 100644 --- a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown +++ b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown @@ -183,7 +183,7 @@ minimizes the **weighted within-class variance** given by the relation : where -\f[q_1(t) = \sum_{i=1}^{t} P(i) \quad \& \quad q_1(t) = \sum_{i=t+1}^{I} P(i)\f]\f[\mu_1(t) = \sum_{i=1}^{t} \frac{iP(i)}{q_1(t)} \quad \& \quad \mu_2(t) = \sum_{i=t+1}^{I} \frac{iP(i)}{q_2(t)}\f]\f[\sigma_1^2(t) = \sum_{i=1}^{t} [i-\mu_1(t)]^2 \frac{P(i)}{q_1(t)} \quad \& \quad \sigma_2^2(t) = \sum_{i=t+1}^{I} [i-\mu_1(t)]^2 \frac{P(i)}{q_2(t)}\f] +\f[q_1(t) = \sum_{i=1}^{t} P(i) \quad \& \quad q_2(t) = \sum_{i=t+1}^{I} P(i)\f]\f[\mu_1(t) = \sum_{i=1}^{t} \frac{iP(i)}{q_1(t)} \quad \& \quad \mu_2(t) = \sum_{i=t+1}^{I} \frac{iP(i)}{q_2(t)}\f]\f[\sigma_1^2(t) = \sum_{i=1}^{t} [i-\mu_1(t)]^2 \frac{P(i)}{q_1(t)} \quad \& \quad \sigma_2^2(t) = \sum_{i=t+1}^{I} [i-\mu_2(t)]^2 \frac{P(i)}{q_2(t)}\f] It actually finds a value of t which lies in between two peaks such that variances to both classes are minimum. It can be simply implemented in Python as follows: diff --git a/doc/tutorials/features2d/akaze_matching/akaze_matching.markdown b/doc/tutorials/features2d/akaze_matching/akaze_matching.markdown index b9f55d6573..d0f772439b 100644 --- a/doc/tutorials/features2d/akaze_matching/akaze_matching.markdown +++ b/doc/tutorials/features2d/akaze_matching/akaze_matching.markdown @@ -7,8 +7,7 @@ Introduction In this tutorial we will learn how to use AKAZE @cite ANB13 local features to detect and match keypoints on two images. We will find keypoints on a pair of images with given homography matrix, match them and count the - -number of inliers (i. e. matches that fit in the given homography). +number of inliers (i.e. matches that fit in the given homography). You can find expanded version of this example here: @@ -16,7 +15,7 @@ You can find expanded version of this example here: Data ---- -We are going to use images 1 and 3 from *Graffity* sequence of Oxford dataset. +We are going to use images 1 and 3 from *Graffiti* sequence of [Oxford dataset](http://www.robots.ox.ac.uk/~vgg/data/data-aff.html). ![](images/graf.png) @@ -27,107 +26,148 @@ Homography is given by a 3 by 3 matrix: 3.4663091e-04 -1.4364524e-05 1.0000000e+00 @endcode You can find the images (*graf1.png*, *graf3.png*) and homography (*H1to3p.xml*) in -*opencv/samples/cpp*. +*opencv/samples/data/*. ### Source Code -@include cpp/tutorial_code/features2D/AKAZE_match.cpp +@add_toggle_cpp +- **Downloadable code**: Click + [here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp) + +- **Code at glance:** + @include samples/cpp/tutorial_code/features2D/AKAZE_match.cpp +@end_toggle + +@add_toggle_java +- **Downloadable code**: Click + [here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java) + +- **Code at glance:** + @include samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java +@end_toggle + +@add_toggle_python +- **Downloadable code**: Click + [here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py) + +- **Code at glance:** + @include samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py +@end_toggle ### Explanation --# **Load images and homography** - @code{.cpp} - Mat img1 = imread("graf1.png", IMREAD_GRAYSCALE); - Mat img2 = imread("graf3.png", IMREAD_GRAYSCALE); +- **Load images and homography** - Mat homography; - FileStorage fs("H1to3p.xml", FileStorage::READ); - fs.getFirstTopLevelNode() >> homography; - @endcode - We are loading grayscale images here. Homography is stored in the xml created with FileStorage. +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp load +@end_toggle --# **Detect keypoints and compute descriptors using AKAZE** - @code{.cpp} - vector kpts1, kpts2; - Mat desc1, desc2; +@add_toggle_java +@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java load +@end_toggle - AKAZE akaze; - akaze(img1, noArray(), kpts1, desc1); - akaze(img2, noArray(), kpts2, desc2); - @endcode - We create AKAZE object and use it's *operator()* functionality. Since we don't need the *mask* - parameter, *noArray()* is used. +@add_toggle_python +@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py load +@end_toggle --# **Use brute-force matcher to find 2-nn matches** - @code{.cpp} - BFMatcher matcher(NORM_HAMMING); - vector< vector > nn_matches; - matcher.knnMatch(desc1, desc2, nn_matches, 2); - @endcode - We use Hamming distance, because AKAZE uses binary descriptor by default. +We are loading grayscale images here. Homography is stored in the xml created with FileStorage. --# **Use 2-nn matches to find correct keypoint matches** - @code{.cpp} - for(size_t i = 0; i < nn_matches.size(); i++) { - DMatch first = nn_matches[i][0]; - float dist1 = nn_matches[i][0].distance; - float dist2 = nn_matches[i][1].distance; +- **Detect keypoints and compute descriptors using AKAZE** - if(dist1 < nn_match_ratio * dist2) { - matched1.push_back(kpts1[first.queryIdx]); - matched2.push_back(kpts2[first.trainIdx]); - } - } - @endcode - If the closest match is *ratio* closer than the second closest one, then the match is correct. +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp AKAZE +@end_toggle --# **Check if our matches fit in the homography model** - @code{.cpp} - for(int i = 0; i < matched1.size(); i++) { - Mat col = Mat::ones(3, 1, CV_64F); - col.at(0) = matched1[i].pt.x; - col.at(1) = matched1[i].pt.y; +@add_toggle_java +@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java AKAZE +@end_toggle - col = homography * col; - col /= col.at(2); - float dist = sqrt( pow(col.at(0) - matched2[i].pt.x, 2) + - pow(col.at(1) - matched2[i].pt.y, 2)); +@add_toggle_python +@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py AKAZE +@end_toggle - if(dist < inlier_threshold) { - int new_i = inliers1.size(); - inliers1.push_back(matched1[i]); - inliers2.push_back(matched2[i]); - good_matches.push_back(DMatch(new_i, new_i, 0)); - } - } - @endcode - If the distance from first keypoint's projection to the second keypoint is less than threshold, - then it it fits in the homography. +We create AKAZE and detect and compute AKAZE keypoints and descriptors. Since we don't need the *mask* +parameter, *noArray()* is used. - We create a new set of matches for the inliers, because it is required by the drawing function. +- **Use brute-force matcher to find 2-nn matches** --# **Output results** - @code{.cpp} - Mat res; - drawMatches(img1, inliers1, img2, inliers2, good_matches, res); - imwrite("res.png", res); - ... - @endcode - Here we save the resulting image and print some statistics. +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp 2-nn matching +@end_toggle -### Results +@add_toggle_java +@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java 2-nn matching +@end_toggle -Found matches -------------- +@add_toggle_python +@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py 2-nn matching +@end_toggle + +We use Hamming distance, because AKAZE uses binary descriptor by default. + +- **Use 2-nn matches and ratio criterion to find correct keypoint matches** +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp ratio test filtering +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java ratio test filtering +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py ratio test filtering +@end_toggle + +If the closest match distance is significantly lower than the second closest one, then the match is correct (match is not ambiguous). + +- **Check if our matches fit in the homography model** + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp homography check +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java homography check +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py homography check +@end_toggle + +If the distance from first keypoint's projection to the second keypoint is less than threshold, +then it fits the homography model. + +We create a new set of matches for the inliers, because it is required by the drawing function. + +- **Output results** + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp draw final matches +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java draw final matches +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py draw final matches +@end_toggle + +Here we save the resulting image and print some statistics. + +Results +------- + +### Found matches ![](images/res.png) -A-KAZE Matching Results ------------------------ +Depending on your OpenCV version, you should get results coherent with: + @code{.none} Keypoints 1: 2943 Keypoints 2: 3511 Matches: 447 Inliers: 308 - Inlier Ratio: 0.689038} + Inlier Ratio: 0.689038 @endcode diff --git a/doc/tutorials/features2d/table_of_content_features2d.markdown b/doc/tutorials/features2d/table_of_content_features2d.markdown index 37e4e41a1d..1f941f9d01 100644 --- a/doc/tutorials/features2d/table_of_content_features2d.markdown +++ b/doc/tutorials/features2d/table_of_content_features2d.markdown @@ -98,6 +98,8 @@ OpenCV. - @subpage tutorial_akaze_matching + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 3.0 *Author:* Fedor Morozov diff --git a/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown b/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown index 12ef87fc7d..ca1ec47258 100644 --- a/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown +++ b/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown @@ -16,42 +16,152 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from - [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp). +[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp). @include samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java) +@include samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py) +@include samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py +@end_toggle Explanation / Result -------------------- --# Load the source image and check if it is loaded without any problem, then show it: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image - ![](images/source.jpeg) +- Load the source image and check if it is loaded without any problem, then show it: --# Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg - ![](images/black_bg.jpeg) +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image +@end_toggle --# Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative): - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp - ![](images/laplace.jpeg) - ![](images/sharp.jpeg) +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java load_image +@end_toggle --# Now we transform our new sharpened source image to a grayscale and a binary one, respectively: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin - ![](images/bin.jpeg) +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py load_image +@end_toggle --# We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist - ![](images/dist_transf.jpeg) +![](images/source.jpeg) --# We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks - ![](images/peaks.jpeg) +- Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform: --# From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds - ![](images/markers.jpeg) +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg +@end_toggle --# Finally, we can apply the watershed algorithm, and visualize the result: - @snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed - ![](images/final.jpeg) \ No newline at end of file +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java black_bg +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py black_bg +@end_toggle + +![](images/black_bg.jpeg) + +- Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative): + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java sharp +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py sharp +@end_toggle + +![](images/laplace.jpeg) +![](images/sharp.jpeg) + +- Now we transform our new sharpened source image to a grayscale and a binary one, respectively: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java bin +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py bin +@end_toggle + +![](images/bin.jpeg) + +- We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java dist +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py dist +@end_toggle + +![](images/dist_transf.jpeg) + +- We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java peaks +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py peaks +@end_toggle + +![](images/peaks.jpeg) + +- From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java seeds +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py seeds +@end_toggle + +![](images/markers.jpeg) + +- Finally, we can apply the watershed algorithm, and visualize the result: + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java watershed +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py watershed +@end_toggle + +![](images/final.jpeg) diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown index 978b900ab2..99cc2c146e 100644 --- a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown +++ b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown @@ -15,55 +15,167 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp) @include samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java) +@include samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py) +@include samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py +@end_toggle Explanation ----------- The main function is rather simple, as follows from the comments we do the following: --# Open the image, convert it into grayscale and blur it to get rid of the noise. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp setup --# Create a window with header "Source" and display the source file in it. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp createWindow --# Create a trackbar on the source_window and assign a callback function to it +- Open the image, convert it into grayscale and blur it to get rid of the noise. + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp setup +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java setup +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py setup +@end_toggle + +- Create a window with header "Source" and display the source file in it. + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp createWindow +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java createWindow +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py createWindow +@end_toggle + +- Create a trackbar on the `source_window` and assign a callback function to it. In general callback functions are used to react to some kind of signal, in our case it's trackbar's state change. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp taskbar --# Explicit one-time call of `thresh_callback` is necessary to display + Explicit one-time call of `thresh_callback` is necessary to display the "Contours" window simultaniously with the "Source" window. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp callback00 --# Wait for user to close the windows. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp waitForIt +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp trackbar +@end_toggle -The callback function `thresh_callback` does all the interesting job. +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java trackbar +@end_toggle +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py trackbar +@end_toggle --# Writes to `threshold_output` the threshold of the grayscale picture (you can check out about thresholding @ref tutorial_threshold "here"). - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp threshold --# Finds contours and saves them to the vectors `contour` and `hierarchy`. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp findContours --# For every found contour we now apply approximation to polygons - with accuracy +-3 and stating that the curve must me closed. +The callback function does all the interesting job. +- Use @ref cv::Canny to detect edges in the images. + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp Canny +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java Canny +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py Canny +@end_toggle + +- Finds contours and saves them to the vectors `contour` and `hierarchy`. + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp findContours +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java findContours +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py findContours +@end_toggle + +- For every found contour we now apply approximation to polygons + with accuracy +-3 and stating that the curve must be closed. After that we find a bounding rect for every polygon and save it to `boundRect`. - At last we find a minimum enclosing circle for every polygon and save it to `center` and `radius` vectors. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp allthework + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp allthework +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java allthework +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py allthework +@end_toggle We found everything we need, all we have to do is to draw. --# Create new Mat of unsigned 8-bit chars, filled with zeros. +- Create new Mat of unsigned 8-bit chars, filled with zeros. It will contain all the drawings we are going to make (rects and circles). - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp zeroMat --# For every contour: pick a random color, draw the contour, the bounding rectangle and - the minimal enclosing circle with it, - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp forContour --# Display the results: create a new window "Contours" and show everything we added to drawings on it. - @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp showDrawings + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp zeroMat +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java zeroMat +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py zeroMat +@end_toggle + +- For every contour: pick a random color, draw the contour, the bounding rectangle and + the minimal enclosing circle with it. + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp forContour +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java forContour +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py forContour +@end_toggle + +- Display the results: create a new window "Contours" and show everything we added to drawings on it. + +@add_toggle_cpp +@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp showDrawings +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java showDrawings +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py showDrawings +@end_toggle Result ------ diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown index eb21cf5bc7..a482936d79 100644 --- a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown +++ b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown @@ -15,9 +15,23 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp) @include samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/GeneralContoursDemo2.java) +@include samples/java/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/GeneralContoursDemo2.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/generalContours_demo2.py) +@include samples/python/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/generalContours_demo2.py +@end_toggle Explanation ----------- diff --git a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown index af467bdc72..c1171bb2aa 100644 --- a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown +++ b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown @@ -15,9 +15,23 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp) @include samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/find_contours/FindContoursDemo.java) +@include samples/java/tutorial_code/ShapeDescriptors/find_contours/FindContoursDemo.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/find_contours/findContours_demo.py) +@include samples/python/tutorial_code/ShapeDescriptors/find_contours/findContours_demo.py +@end_toggle Explanation ----------- diff --git a/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown b/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown index cfb9241b81..7d7fae1b7c 100644 --- a/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown +++ b/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown @@ -14,10 +14,23 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp) - @include samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java) +@include samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/hull/hull_demo.py) +@include samples/python/tutorial_code/ShapeDescriptors/hull/hull_demo.py +@end_toggle Explanation ----------- diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown b/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown index 231ff37500..de9e79ca86 100644 --- a/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown +++ b/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown @@ -16,9 +16,23 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp) @include samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/moments/MomentsDemo.java) +@include samples/java/tutorial_code/ShapeDescriptors/moments/MomentsDemo.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/moments/moments_demo.py) +@include samples/python/tutorial_code/ShapeDescriptors/moments/moments_demo.py +@end_toggle Explanation ----------- diff --git a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown index 1f50410616..4a42eea836 100644 --- a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown +++ b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown @@ -14,9 +14,23 @@ Theory Code ---- +@add_toggle_cpp This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp) @include samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp +@end_toggle + +@add_toggle_java +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/point_polygon_test/PointPolygonTestDemo.java) +@include samples/java/tutorial_code/ShapeDescriptors/point_polygon_test/PointPolygonTestDemo.java +@end_toggle + +@add_toggle_python +This tutorial code's is shown lines below. You can also download it from +[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/point_polygon_test/pointPolygonTest_demo.py) +@include samples/python/tutorial_code/ShapeDescriptors/point_polygon_test/pointPolygonTest_demo.py +@end_toggle Explanation ----------- diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index fc93ae0e3d..59c985e1dd 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -225,6 +225,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_find_contours + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán @@ -233,6 +235,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_hull + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán @@ -241,6 +245,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_bounding_rects_circles + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán @@ -249,6 +255,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_bounding_rotated_ellipses + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán @@ -257,6 +265,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_moments + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán @@ -265,6 +275,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_point_polygon_test + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán @@ -273,6 +285,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_distance_transform + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Theodore Tsesmelis diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 54b193cb70..fcd295da6f 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1992,6 +1992,31 @@ CV_EXPORTS_W int decomposeHomographyMat(InputArray H, OutputArrayOfArrays translations, OutputArrayOfArrays normals); +/** @brief Filters homography decompositions based on additional information. + +@param rotations Vector of rotation matrices. +@param normals Vector of plane normal matrices. +@param beforePoints Vector of (rectified) visible reference points before the homography is applied +@param afterPoints Vector of (rectified) visible reference points after the homography is applied +@param possibleSolutions Vector of int indices representing the viable solution set after filtering +@param pointsMask optional Mat/Vector of 8u type representing the mask for the inliers as given by the findHomography function + +This function is intended to filter the output of the decomposeHomographyMat based on additional +information as described in @cite Malis . The summary of the method: the decomposeHomographyMat function +returns 2 unique solutions and their "opposites" for a total of 4 solutions. If we have access to the +sets of points visible in the camera frame before and after the homography transformation is applied, +we can determine which are the true potential solutions and which are the opposites by verifying which +homographies are consistent with all visible reference points being in front of the camera. The inputs +are left unchanged; the filtered solution set is returned as indices into the existing one. + +*/ +CV_EXPORTS_W void filterHomographyDecompByVisibleRefpoints(InputArrayOfArrays rotations, + InputArrayOfArrays normals, + InputArray beforePoints, + InputArray afterPoints, + OutputArray possibleSolutions, + InputArray pointsMask = noArray()); + /** @brief The base class for stereo correspondence algorithms. */ class CV_EXPORTS_W StereoMatcher : public Algorithm diff --git a/modules/calib3d/src/homography_decomp.cpp b/modules/calib3d/src/homography_decomp.cpp index 252da7967b..6975a7ef11 100644 --- a/modules/calib3d/src/homography_decomp.cpp +++ b/modules/calib3d/src/homography_decomp.cpp @@ -1,50 +1,51 @@ /*M/////////////////////////////////////////////////////////////////////////////////////// - // - // This is a homography decomposition implementation contributed to OpenCV - // by Samson Yilma. It implements the homography decomposition algorithm - // described in the research report: - // Malis, E and Vargas, M, "Deeper understanding of the homography decomposition - // for vision-based control", Research Report 6303, INRIA (2007) - // - // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. - // - // By downloading, copying, installing or using the software you agree to this license. - // If you do not agree to this license, do not download, install, - // copy or use the software. - // - // - // License Agreement - // For Open Source Computer Vision Library - // - // Copyright (C) 2014, Samson Yilma (samson_yilma@yahoo.com), all rights reserved. - // - // Third party copyrights are property of their respective owners. - // - // Redistribution and use in source and binary forms, with or without modification, - // are permitted provided that the following conditions are met: - // - // * Redistribution's of source code must retain the above copyright notice, - // this list of conditions and the following disclaimer. - // - // * Redistribution's in binary form must reproduce the above copyright notice, - // this list of conditions and the following disclaimer in the documentation - // and/or other materials provided with the distribution. - // - // * The name of the copyright holders may not be used to endorse or promote products - // derived from this software without specific prior written permission. - // - // This software is provided by the copyright holders and contributors "as is" and - // any express or implied warranties, including, but not limited to, the implied - // warranties of merchantability and fitness for a particular purpose are disclaimed. - // In no event shall the Intel Corporation or contributors be liable for any direct, - // indirect, incidental, special, exemplary, or consequential damages - // (including, but not limited to, procurement of substitute goods or services; - // loss of use, data, or profits; or business interruption) however caused - // and on any theory of liability, whether in contract, strict liability, - // or tort (including negligence or otherwise) arising in any way out of - // the use of this software, even if advised of the possibility of such damage. - // - //M*/ +// +// This is a homography decomposition implementation contributed to OpenCV +// by Samson Yilma. It implements the homography decomposition algorithm +// described in the research report: +// Malis, E and Vargas, M, "Deeper understanding of the homography decomposition +// for vision-based control", Research Report 6303, INRIA (2007) +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2014, Samson Yilma (samson_yilma@yahoo.com), all rights reserved. +// Copyright (C) 2018, Intel Corporation, all rights reserved. +// +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ #include "precomp.hpp" #include @@ -489,4 +490,67 @@ int decomposeHomographyMat(InputArray _H, return nsols; } +void filterHomographyDecompByVisibleRefpoints(InputArrayOfArrays _rotations, + InputArrayOfArrays _normals, + InputArray _beforeRectifiedPoints, + InputArray _afterRectifiedPoints, + OutputArray _possibleSolutions, + InputArray _pointsMask) +{ + CV_Assert(_beforeRectifiedPoints.type() == CV_32FC2 && _afterRectifiedPoints.type() == CV_32FC2); + CV_Assert(_pointsMask.empty() || _pointsMask.type() == CV_8U); + + Mat beforeRectifiedPoints = _beforeRectifiedPoints.getMat(); + Mat afterRectifiedPoints = _afterRectifiedPoints.getMat(); + Mat pointsMask = _pointsMask.getMat(); + int nsolutions = (int)_rotations.total(); + int npoints = (int)beforeRectifiedPoints.total(); + CV_Assert(pointsMask.empty() || pointsMask.checkVector(1, CV_8U) == npoints); + const uchar* pointsMaskPtr = pointsMask.data; + + std::vector solutionMask(nsolutions, (uchar)1); + std::vector normals(nsolutions); + std::vector rotnorm(nsolutions); + Mat R; + + for( int i = 0; i < nsolutions; i++ ) + { + _normals.getMat(i).convertTo(normals[i], CV_64F); + CV_Assert(normals[i].total() == 3); + _rotations.getMat(i).convertTo(R, CV_64F); + rotnorm[i] = R*normals[i]; + CV_Assert(rotnorm[i].total() == 3); + } + + for( int j = 0; j < npoints; j++ ) + { + if( !pointsMaskPtr || pointsMaskPtr[j] ) + { + Point2f prevPoint = beforeRectifiedPoints.at(j); + Point2f currPoint = afterRectifiedPoints.at(j); + + for( int i = 0; i < nsolutions; i++ ) + { + if( !solutionMask[i] ) + continue; + + const double* normal_i = normals[i].ptr(); + const double* rotnorm_i = rotnorm[i].ptr(); + double prevNormDot = normal_i[0]*prevPoint.x + normal_i[1]*prevPoint.y + normal_i[2]; + double currNormDot = rotnorm_i[0]*currPoint.x + rotnorm_i[1]*currPoint.y + rotnorm_i[2]; + + if (prevNormDot <= 0 || currNormDot <= 0) + solutionMask[i] = (uchar)0; + } + } + } + + std::vector possibleSolutions; + for( int i = 0; i < nsolutions; i++ ) + if( solutionMask[i] ) + possibleSolutions.push_back(i); + + Mat(possibleSolutions).copyTo(_possibleSolutions); +} + } //namespace cv diff --git a/modules/calib3d/test/test_filter_homography_decomp.cpp b/modules/calib3d/test/test_filter_homography_decomp.cpp new file mode 100644 index 0000000000..533d9ddf56 --- /dev/null +++ b/modules/calib3d/test/test_filter_homography_decomp.cpp @@ -0,0 +1,575 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2016, OpenCV Foundation, all rights reserved. +// +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/calib3d.hpp" + +namespace opencv_test { namespace { + +class CV_FilterHomographyDecompTest : public cvtest::BaseTest { + +public: + CV_FilterHomographyDecompTest() + { + buildTestDataSet(); + } + +protected: + void run(int) + { + vector finalSolutions; + filterHomographyDecompByVisibleRefpoints(_rotations, _normals, _prevRectifiedPoints, _currRectifiedPoints, finalSolutions, _mask); + + //there should be at least 2 solution + ASSERT_EQ(finalSolutions, _validSolutions); + } + +private: + + void buildTestDataSet() + { + double rotationsArray[4][9] = { + { + 0.98811084196540500, + -0.15276633082836735, + 0.017303530150126534, + 0.14161851662094097, + 0.94821044891315664, + 0.28432576443578628, + -0.059842791884259422, + -0.27849487021693553, + 0.95857156619751127 + }, + { + 0.98811084196540500, + -0.15276633082836735, + 0.017303530150126534, + 0.14161851662094097, + 0.94821044891315664, + 0.28432576443578628, + -0.059842791884259422, + -0.27849487021693553, + 0.95857156619751127 + }, + { + 0.95471096402077438, + -0.21080808634428211, + -0.20996886890771557, + 0.20702063153797226, + 0.97751379914116743, + -0.040115216641822840, + 0.21370407880090386, + -0.0051694506925720751, + 0.97688476468997820 + }, + { + 0.95471096402077438, + -0.21080808634428211, + -0.20996886890771557, + 0.20702063153797226, + 0.97751379914116743, + -0.040115216641822840, + 0.21370407880090386, + -0.0051694506925720751, + 0.97688476468997820 + } + }; + + double normalsArray[4][3] = { + { + -0.023560516110791116, + 0.085818414407956692, + 0.99603217911325403 + }, + { + 0.023560516110791116, + -0.085818414407956692, + -0.99603217911325403 + }, + { + -0.62483547397726014, + -0.56011861446691769, + 0.54391889853844289 + }, + { + 0.62483547397726014, + 0.56011861446691769, + -0.54391889853844289 + } + }; + + uchar maskArray[514] = + { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, + 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, + 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, + 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + static const float currRectifiedPointArr[] = + { + -0.565732896f, -0.321162999f, -0.416198403f, -0.299646467f, -0.408354312f, -0.290387660f, + -0.386555284f, -0.287677139f, -0.348475337f, -0.276208878f, -0.415957332f, -0.266133875f, + -0.354961902f, -0.257545590f, -0.420189440f, -0.255190015f, -0.379785866f, -0.252570540f, + -0.144345313f, -0.249134675f, -0.162417486f, -0.223227784f, -0.129876539f, -0.219722182f, + -0.470801264f, -0.211166814f, 0.0992607549f, -0.209064797f, 0.123508267f, -0.196303099f, + -0.521849990f, -0.190706849f, -0.513497114f, -0.189186409f, -0.534959674f, -0.185138911f, + 0.121614374f, -0.182721153f, 0.154205695f, -0.183763996f, -0.516449869f, -0.181606859f, + -0.523427486f, -0.180088669f, 0.149494573f, -0.179563865f, -0.552187204f, -0.172630817f, + -0.322249800f, -0.172333881f, 0.127574071f, -0.165683150f, 0.159817487f, -0.162389070f, + -0.578930736f, -0.160272732f, -0.600617707f, -0.155920163f, -0.249115735f, -0.154711768f, + -0.543279886f, -0.144873798f, -0.529992998f, -0.142433196f, 0.0554505363f, -0.142878756f, + -0.613355398f, -0.132748783f, 0.190059289f, -0.128930226f, -0.255682647f, -0.127393380f, + 0.0299431719f, -0.125339776f, -0.282943249f, -0.118550651f, -0.0348402821f, -0.115398556f, + -0.0362741761f, -0.110100254f, -0.319089264f, -0.104354575f, -0.0401916653f, -0.0852083191f, + -0.372183621f, -0.0812346712f, -0.00707253255f, -0.0810251758f, 0.267345309f, -0.0787685066f, + 0.258760840f, -0.0768160895f, -0.377273679f, -0.0763452053f, -0.0314898677f, -0.0743160769f, + 0.223423928f, -0.0724818707f, 0.00284322398f, -0.0720727518f, 0.232531011f, -0.0682833865f, + 0.282355100f, -0.0655683428f, -0.233353317f, -0.0613981225f, 0.290982842f, -0.0607336313f, + -0.0994169787f, -0.0376472026f, 0.257561266f, -0.0331368558f, 0.265076399f, -0.0320781991f, + 0.0454338901f, -0.0238198638f, 0.0409987904f, -0.0186991505f, -0.502306283f, -0.0172236171f, + -0.464807063f, -0.0149533665f, -0.185798749f, -0.00540314987f, 0.182073534f, -0.000651287497f, + -0.435764432f, 0.00162558386f, -0.181552932f, 0.00792864431f, -0.700565279f, 0.0110246018f, + -0.144087434f, 0.0120453080f, -0.524990261f, 0.0138590708f, -0.182723984f, 0.0165519360f, + -0.217308879f, 0.0208590515f, 0.462978750f, 0.0247372910f, 0.0956632495f, 0.0323494300f, + 0.0843820646f, 0.0424364135f, 0.122466311f, 0.0441578403f, -0.162433729f, 0.0528083183f, + 0.0964344442f, 0.0624147579f, -0.271349967f, 0.0727724135f, -0.266336441f, 0.0719895661f, + 0.0675768778f, 0.0848240927f, -0.689944625f, 0.0889045894f, -0.680990934f, 0.0903657600f, + -0.119472280f, 0.0930491239f, -0.124393739f, 0.0933082998f, -0.323403478f, 0.0937438533f, + -0.323273063f, 0.0969979763f, -0.352427900f, 0.101048596f, -0.327554941f, 0.104539163f, + -0.330044419f, 0.114519835f, 0.0235135648f, 0.118004657f, -0.671623945f, 0.130437061f, + -0.385111898f, 0.142786101f, -0.376281500f, 0.145800456f, -0.0169987213f, 0.148056105f, + -0.326495141f, 0.152596891f, -0.337120056f, 0.154522225f, -0.336885720f, 0.154304653f, + 0.322089493f, 0.155130088f, -0.0713477954f, 0.163638428f, -0.0208650175f, 0.171433330f, + -0.380652726f, 0.172022790f, -0.0599780641f, 0.182294667f, 0.244408697f, 0.194245726f, + -0.101454332f, 0.198159069f, 0.257901788f, 0.200226694f, -0.0775909275f, 0.205242962f, + 0.231870517f, 0.222396746f, -0.546760798f, 0.242291704f, -0.538914979f, 0.243761152f, + 0.206653103f, 0.244874880f, -0.595693469f, 0.264329463f, -0.581023335f, 0.265664101f, + 0.00444878871f, 0.267031074f, -0.573156178f, 0.271591753f, -0.543381274f, 0.271759123f, + 0.00450209389f, 0.271335930f, -0.223618075f, 0.278416723f, 0.161934286f, 0.289435983f, + -0.199636295f, 0.296817899f, -0.250217140f, 0.299677849f, -0.258231103f, 0.314012855f, + -0.628315628f, 0.316889286f, 0.320948511f, 0.316358119f, -0.246845752f, 0.320511192f, + 0.0687271580f, 0.321383297f, 0.0784438103f, 0.322898388f, 0.0946765989f, 0.325111747f, + -0.249674007f, 0.328731328f, -0.244633347f, 0.329467386f, -0.245841011f, 0.334985316f, + 0.118609101f, 0.343532443f, 0.0497615598f, 0.348162144f, -0.221477821f, 0.349263757f, + 0.0759577379f, 0.351840734f, 0.0504637137f, 0.373238713f, 0.0730970055f, 0.376537383f, + -0.204333842f, 0.381100655f, -0.557245076f, -0.339432925f, -0.402010202f, -0.288829565f, + -0.350465477f, -0.281259984f, -0.352995187f, -0.264569730f, -0.466762394f, -0.217114508f, + 0.152002022f, -0.217566550f, 0.146226048f, -0.183914393f, 0.0949312001f, -0.177005857f, + -0.211882949f, -0.175594494f, -0.531562269f, -0.173924312f, -0.0727246776f, -0.167270422f, + 0.0546481088f, -0.140193000f, -0.296819001f, -0.137850702f, -0.261863053f, -0.139540121f, + 0.187967837f, -0.131033540f, 0.322852045f, -0.112108752f, -0.0432251953f, -0.102951847f, + -0.0453428440f, -0.0914504975f, -0.0182842426f, -0.0918859020f, 0.0140433423f, -0.0904538929f, + -0.377287626f, -0.0817026496f, 0.266108125f, -0.0797783583f, 0.257961422f, -0.0767710134f, + -0.495943695f, -0.0683977529f, 0.231466040f, -0.0675206482f, -0.240675926f, -0.0551427566f, + -0.482824773f, -0.0510699376f, -0.491354793f, -0.0414650664f, -0.0960614979f, -0.0377000235f, + -0.102409534f, -0.0369749814f, -0.471273214f, -0.0325376652f, -0.483320534f, -0.0174943600f, + -0.457503378f, -0.0152483145f, -0.178161725f, -0.0153892851f, -0.483233035f, -0.0106405178f, + -0.472914547f, -0.0105228210f, -0.166542307f, -0.00667150877f, 0.181261331f, -0.00449455017f, + -0.474292487f, -0.00428914558f, -0.185297221f, -0.00575157674f, -0.494381040f, -0.00278507406f, + -0.141748473f, -0.00289725070f, -0.487515569f, 0.000758233888f, 0.322646528f, 0.0197495818f, + 0.142943904f, 0.0276249554f, -0.563232243f, 0.0306834858f, -0.555995941f, 0.0367121249f, + 0.114935011f, 0.0496927276f, -0.152954608f, 0.0538645200f, -0.594885707f, 0.0562511310f, + 0.0678326488f, 0.0756176412f, -0.667605639f, 0.0828208700f, -0.354470938f, 0.101424232f, + 0.0228204262f, 0.120382607f, -0.639557123f, 0.124422595f, -0.690505445f, 0.126883239f, + -0.395509213f, 0.130242139f, -0.00618012529f, 0.139929801f, 0.175945997f, 0.140235618f, + 0.198833048f, 0.167587668f, -0.334679037f, 0.177859858f, 0.236127406f, 0.192743436f, + 0.283146858f, 0.204260647f, -0.0354267135f, 0.206209183f, 0.247388184f, 0.207016930f, + -0.0422560424f, 0.212493256f, 0.261681855f, 0.215763748f, 0.207528576f, 0.219807997f, + -0.300219178f, 0.221922547f, 0.206393883f, 0.245171010f, 0.239619836f, 0.244768366f, + -0.523026288f, 0.250639766f, -0.591975033f, 0.254252791f, 0.246785000f, 0.252878994f, + 0.272995651f, 0.255815417f, 0.00825022161f, 0.265591830f, 0.192723796f, 0.266924977f, + -0.222951472f, 0.290150762f, -0.545146644f, 0.304910392f, 0.131736591f, 0.319247276f, + 0.319435924f, 0.317917794f, 0.0687546134f, 0.321296155f, -0.255853772f, 0.327258259f, + 0.0948092714f, 0.325284332f, 0.104488030f, 0.327628911f, -0.245483562f, 0.327617317f, + 0.0647632629f, 0.363111496f, -0.382861346f, -0.287226975f, -0.354297429f, -0.278708905f, + -0.356116027f, -0.262691110f, -0.369049937f, -0.237850189f, -0.146217853f, -0.233530551f, + 0.102752604f, -0.223108903f, 0.137545392f, -0.218163848f, 0.125815898f, -0.216970086f, + -0.557826996f, -0.194665924f, -0.533946335f, -0.184958249f, 0.0976954028f, -0.173691019f, + -0.240166873f, -0.160652772f, 0.166464865f, -0.154563308f, -0.0330923162f, -0.125799045f, + -0.290044904f, -0.118914597f, 0.00350888353f, -0.108661920f, -0.0109116854f, -0.106212743f, + -0.0298740193f, -0.102953635f, -0.287203342f, -0.0997403413f, -0.269498408f, -0.0981520712f, + -0.000815737061f, -0.0938294530f, 0.274663270f, -0.0844340026f, -0.371082008f, -0.0805466920f, + -0.368196100f, -0.0743779093f, 0.00675902702f, -0.0735078678f, 0.226267770f, -0.0744194537f, + -0.241736412f, -0.0630025938f, -0.408663541f, -0.0564615242f, 0.251640886f, -0.0519632548f, + 0.249993712f, -0.0519672707f, -0.426033378f, -0.0365641154f, -0.467352122f, -0.0305716563f, + 0.251341015f, -0.0268137120f, -0.443456501f, -0.0243669953f, -0.502199471f, -0.0151771074f, + -0.178487480f, -0.0155749097f, 0.178145915f, -0.00528379623f, -0.492981344f, -0.00174682145f, + -0.150337398f, 0.000692513015f, -0.457302928f, 0.00352234906f, 0.190587431f, 0.00151424226f, + -0.482671946f, 0.00682042213f, -0.158589542f, 0.0150188655f, -0.182223722f, 0.0145649035f, + 0.107089065f, 0.0223725326f, 0.135399371f, 0.0275243558f, -0.552838683f, 0.0275048595f, + -0.432176501f, 0.0248741303f, -0.192510992f, 0.0281074084f, -0.553043425f, 0.0298770685f, + -0.684887648f, 0.0436144769f, 0.0850105733f, 0.0448755622f, -0.165784389f, 0.0439001285f, + 0.102653719f, 0.0457992665f, 0.114853017f, 0.0504316092f, -0.647432685f, 0.0608204119f, + 0.0828530043f, 0.0608987175f, 0.0894377902f, 0.0742467493f, 0.0702404827f, 0.0767309442f, + -0.613642335f, 0.0779517740f, -0.670592189f, 0.0849624202f, -0.395209312f, 0.0854151621f, + 0.125186160f, 0.0919951499f, -0.359707922f, 0.102121405f, -0.354259193f, 0.101300709f, + 0.0304000825f, 0.110619470f, -0.677573025f, 0.114422500f, 0.0305799693f, 0.121603437f, + -0.358950615f, 0.121660560f, -0.718753040f, 0.134569481f, 0.256451160f, 0.141883001f, + -0.0904129520f, 0.146879435f, -0.0184279438f, 0.148968369f, -0.356992692f, 0.160104826f, + -0.337676436f, 0.161766291f, 0.201174691f, 0.169025913f, -0.378423393f, 0.170933828f, + -0.601599216f, 0.174998865f, -0.0902864039f, 0.184311926f, -0.0584819093f, 0.184186250f, + 0.294467270f, 0.182560727f, 0.250262231f, 0.186239958f, -0.326370239f, 0.191697389f, + -0.0980727375f, 0.196913749f, 0.253085673f, 0.201914877f, -0.0344332159f, 0.205900863f, + 0.255287141f, 0.203029931f, -0.452713937f, 0.205191836f, 0.264822274f, 0.217408702f, + -0.0290334225f, 0.221684650f, -0.583990574f, 0.237398431f, -0.145020664f, 0.240374506f, + 0.249667659f, 0.254706532f, 0.274279058f, 0.256447285f, -0.282936275f, 0.259140193f, + 0.241211995f, 0.260401577f, -0.590560019f, 0.272659779f, -0.574947417f, 0.272671998f, + -0.224780366f, 0.279990941f, -0.525540829f, 0.287235677f, -0.247069210f, 0.298608154f, + -0.201292604f, 0.298156679f, 0.319822490f, 0.317605704f, -0.248013541f, 0.320789784f, + 0.0957527757f, 0.326543272f, 0.105006196f, 0.328469753f, -0.264089525f, 0.332354158f, + -0.670460403f, 0.339870930f, 0.118318990f, 0.345167071f, 0.0737744719f, 0.353734553f, + 0.0655663237f, 0.361025929f, -0.306805104f, 0.363820761f, 0.0524423867f, 0.371921480f, + 0.0713953897f, 0.375074357f, -0.411387652f, -0.268335998f, -0.357590824f, -0.263346583f, + -0.407676578f, -0.253785878f, 0.0660323426f, -0.253718942f, -0.157670841f, -0.225629836f, + 0.170453921f, -0.220800355f, -0.475751191f, -0.209005311f, -0.331408232f, -0.203059763f, + -0.173841938f, -0.199112654f, -0.503261328f, -0.193795130f, -0.532277644f, -0.190292686f, + -0.0972326621f, -0.191563144f, -0.0692789108f, -0.172031537f, -0.318824291f, -0.169072524f, + -0.576232314f, -0.162124678f, -0.0839322209f, -0.156304389f, -0.583625376f, -0.142171323f, + -0.0546422042f, -0.135338858f, 0.0501612425f, -0.132490858f, -0.645011544f, -0.111341864f, + -0.0925374180f, -0.0483307689f, -0.444242209f, -0.0263337940f, 0.0335495919f, -0.0281750113f, + 0.274629444f, -0.0259516705f, 0.213774025f, -0.0240113474f, -0.194874078f, -0.0151330847f, + 0.175111562f, -0.00868577976f, -0.185011521f, -0.000680683181f, 0.152071685f, 0.0204544198f, + 0.321354061f, 0.0199794695f, -0.192160159f, 0.0275637116f, -0.189656645f, 0.0275667012f, + 0.137452200f, 0.0298070628f, -0.194602579f, 0.0449027494f, -0.647751570f, 0.0625102371f, + 0.124078721f, 0.0639316663f, 0.125849217f, 0.0762147456f, -0.614036798f, 0.0778791085f, + -0.684063017f, 0.0867959261f, -0.670344174f, 0.0846142769f, -0.127689242f, 0.0883567855f, + 0.123796627f, 0.0907361880f, -0.356352538f, 0.101948388f, -0.388843179f, 0.110183217f, + 0.0316384435f, 0.123791300f, -0.627986908f, 0.146491125f, -0.0747071728f, 0.158135459f, + -0.0235102437f, 0.168867558f, -0.0903210714f, 0.184088305f, 0.292073458f, 0.183571488f, + -0.0585953295f, 0.184784085f, -0.0317775607f, 0.218368888f, 0.209752038f, 0.223883361f, + -0.295424402f, 0.229150623f, -0.144439027f, 0.237902716f, -0.284140587f, 0.262761474f, + 0.289083928f, 0.276900887f, 0.159017235f, 0.300793648f, -0.204925507f, 0.298536539f, + -0.544958472f, 0.305164427f, -0.261615157f, 0.306550682f, 0.0977220088f, 0.327949613f, + 0.109876208f, 0.337665111f, -0.283918083f, 0.347385526f, 0.0436712503f, 0.350702018f, + 0.114512287f, 0.367949426f, 0.106543839f, 0.375095814f, 0.505324781f, -0.272183985f, + 0.0645913780f, -0.251512915f, -0.457196057f, -0.225893468f, -0.480293810f, -0.222602293f, + -0.138176888f, -0.209798917f, -0.110901751f, -0.198036820f, -0.196451947f, -0.191723794f, + -0.537742376f, -0.174413025f, -0.0650562346f, -0.174762890f, -0.567489207f, -0.165461496f, + 0.0879585966f, -0.163023785f, -0.303777844f, -0.142031133f, 0.199195996f, -0.141861767f, + 0.0491657220f, -0.132264882f, -0.497363061f, -0.107934952f, -0.000536393432f, -0.102828167f, + 0.0155952247f, -0.0998895392f, -0.363601953f, -0.0897399634f, -0.224325985f, -0.0719678402f, + -0.0638299435f, -0.0646244809f, -0.108656809f, -0.0468749776f, -0.0865045264f, -0.0512534790f, + -0.469339728f, -0.0279338267f, 0.0578282699f, -0.0133374622f, -0.195265710f, -0.0115369316f, + 0.296735317f, -0.0132813146f, 0.0664219409f, 0.0134935537f, 0.126060545f, 0.0333039127f, + 0.139887005f, 0.0334976614f, -0.547339618f, 0.0433730707f, 0.0866046399f, 0.0527233221f, + 0.131943896f, 0.0657638907f, -0.280056775f, 0.0685855150f, 0.0746403933f, 0.0795079395f, + 0.125382811f, 0.0822770745f, -0.648187757f, 0.103887804f, -0.107411072f, 0.107508548f, + 0.0155869983f, 0.108978622f, 0.0189307462f, 0.129617691f, 0.162685350f, 0.127225950f, + -0.0875291452f, 0.142281070f, 0.319728941f, 0.148827255f, -0.0259547811f, 0.169724479f, + 0.259297132f, 0.190075457f, -0.467013776f, 0.212794706f, -0.315732479f, 0.219243437f, + -0.111042649f, 0.217940107f, 0.239550352f, 0.222786069f, 0.263966352f, 0.260309041f, + 0.320023954f, -0.222228840f, -0.322707742f, -0.213004455f, -0.224977970f, -0.169595599f, + -0.605799317f, -0.142425537f, 0.0454332717f, -0.129945949f, 0.205748767f, -0.113405459f, + 0.317985803f, -0.118630089f, 0.497755647f, -0.0962266177f, -0.393495560f, -0.0904672816f, + 0.240035087f, -0.0737613589f, -0.212947786f, -0.0280145984f, 0.0674179196f, 0.0124880793f, + -0.545862198f, 0.0207057912f, -0.284409463f, 0.0626631007f, -0.107082598f, 0.0854173824f, + 0.0578137375f, 0.0917839557f, 0.145844117f, 0.102937251f, 0.183878779f, 0.119614877f, + -0.626380265f, 0.140862882f, -0.0325521491f, 0.161834121f, -0.590211987f, 0.167720392f, + 0.289599866f, 0.186565816f, -0.328821093f, 0.187714070f, -0.289086968f, 0.205165654f, + -0.445392698f, 0.215343162f, 0.173715711f, 0.273563296f, 0.284015119f, 0.270610362f, + 0.0174398609f, 0.283809274f, -0.496335506f, -0.202981815f, 0.0389454551f, -0.166210428f, + -0.317301393f, -0.156280205f, -0.396320462f, -0.0949599668f, -0.213638976f, -0.0776446015f, + 0.497601509f, -0.0928353444f, -0.260220319f, -0.0718628615f, -0.116495222f, -0.0543703064f, + -0.118132629f, -0.0156126227f, 0.0242815297f, 0.00629332382f, -0.537928998f, 0.00815516617f, + 0.317720622f, 0.0271231923f, -0.582170665f, 0.0478387438f, -0.536856830f, 0.0466793887f, + -0.220819592f, 0.0433096550f, -0.246473342f, 0.0572598167f, 0.481240988f, 0.0503845438f, + -0.102453016f, 0.0649363101f, -0.149955124f, 0.0744054317f, -0.248215869f, 0.0916868672f, + -0.101221249f, 0.110788561f, -0.437672526f, 0.179065496f, -0.0383506976f, 0.183546484f, + -0.279600590f, 0.208760634f, 0.182261929f, 0.275244594f, 0.0253023170f, -0.170456246f, + -0.476852804f, -0.123630777f, -0.0803126246f, -0.0782076195f, -0.133338496f, -0.0659459904f, + -0.0822777376f, -0.00390591589f, 0.149250969f, 0.104314201f, 0.0418044887f, 0.149009049f, + -0.438308835f, 0.164682120f + }; + + const Point2f* currRectifiedPointArr_2f = (const Point2f*)currRectifiedPointArr; + vector currRectifiedPoints(currRectifiedPointArr_2f, + currRectifiedPointArr_2f + sizeof(currRectifiedPointArr) / sizeof(currRectifiedPointArr[0]) / 2); + + _currRectifiedPoints.swap(currRectifiedPoints); + + static const float prevRectifiedPointArr[] = { + -0.599324584f, -0.381164283f, -0.387985110f, -0.385367423f, -0.371437579f, -0.371891201f, + -0.340867460f, -0.370632380f, -0.289822906f, -0.364118159f, -0.372411519f, -0.335272551f, + -0.289586753f, -0.335766882f, -0.372335523f, -0.316857219f, -0.321099430f, -0.323233813f, + 0.208661616f, -0.153931335f, -0.559897065f, 0.193362445f, 0.0181128159f, -0.325224668f, + -0.427504510f, 0.105302416f, 0.487470537f, -0.187071189f, 0.343267351f, -0.339755565f, + -0.477639943f, -0.204375938f, -0.466626763f, -0.204072326f, 0.340813518f, -0.347292691f, + 0.342682719f, -0.320172101f, 0.383663863f, -0.327343374f, -0.467062414f, -0.193995550f, + -0.475603998f, -0.189820126f, 0.552475691f, 0.198386014f, -0.508027375f, -0.174297482f, + -0.211989403f, -0.217261642f, 0.180832058f, -0.127527758f, -0.112721168f, -0.125876635f, + -0.112387165f, -0.167135969f, -0.562491000f, -0.140186235f, 0.395156831f, -0.298828602f, + -0.485202312f, -0.135626689f, 0.148358017f, -0.195937276f, -0.248159677f, -0.254669130f, + -0.568366945f, -0.105187029f, -0.0714842379f, -0.0832463056f, -0.497599572f, -0.205334768f, + -0.0948727652f, 0.245045587f, 0.160857186f, 0.138075173f, 0.164952606f, -0.195109487f, + 0.165254518f, -0.186554477f, -0.183777973f, -0.124357253f, 0.166813776f, -0.153241888f, + -0.241765827f, -0.0820638761f, 0.208661616f, -0.153931335f, 0.540147483f, -0.203156039f, + 0.529201686f, -0.199348077f, -0.248159677f, -0.254669130f, 0.180369601f, -0.139303327f, + 0.570952237f, -0.185722873f, 0.221771300f, -0.143187970f, 0.498627752f, -0.183768719f, + 0.561214447f, -0.188666284f, -0.241409421f, -0.253560483f, 0.569648385f, -0.184499770f, + 0.276665628f, -0.0881819800f, 0.533934176f, -0.142226711f, -0.299728751f, -0.330407321f, + 0.270322412f, -0.256552309f, -0.255016476f, -0.0823200271f, -0.378096581f, 0.0264666155f, + -0.331565350f, 0.0210608803f, 0.0100810500f, -0.0213523544f, -0.248159677f, -0.254669130f, + 0.249623299f, 0.164078355f, 0.0190342199f, -0.00415771967f, 0.604407132f, -0.259350061f, + 0.0660026148f, -0.00787150953f, 0.605921566f, 0.114344336f, 0.0208173525f, 0.00527517078f, + -0.0200567022f, 0.0183092188f, -0.184784368f, -0.193566754f, -0.0125719802f, -0.344967902f, + 0.343063682f, -0.0121044181f, 0.389022052f, -0.0171062462f, 0.163190305f, 0.200014487f, + 0.362440646f, 0.0120019922f, -0.427743971f, 0.100272447f, -0.0714842379f, -0.0832463056f, + 0.0664352402f, 0.0467514023f, -0.559897065f, 0.193362445f, -0.549086213f, 0.193808615f, + -0.241472989f, -0.253163874f, -0.241765827f, -0.0820638761f, -0.122216024f, 0.132651567f, + -0.122216024f, 0.132651567f, 0.515065968f, 0.205271944f, 0.180832058f, -0.127527758f, + -0.123633556f, 0.154476687f, -0.248159677f, -0.254669130f, 0.0208173525f, 0.00527517078f, + -0.483276874f, 0.191274792f, -0.167928949f, 0.200682297f, 0.232745290f, -0.211950779f, + -0.288701504f, -0.334238827f, -0.119621970f, 0.204155236f, -0.119621970f, 0.204155236f, + 0.632996142f, 0.0804972649f, 0.189231426f, 0.164325386f, 0.249623299f, 0.164078355f, + 0.0676716864f, 0.0479496233f, 0.207636267f, 0.184271768f, -0.300510556f, 0.358790994f, + -0.107678331f, 0.188473806f, 0.565983415f, 0.144723341f, 0.191329703f, 0.213909492f, + -0.0283227600f, -0.373237878f, -0.184958130f, 0.200373843f, 0.0346363746f, -0.0259889495f, + -0.112387165f, -0.167135969f, 0.251426309f, 0.210430339f, -0.477397382f, -0.131372169f, + -0.0667442903f, 0.0997460634f, 0.251426309f, 0.210430339f, -0.317926824f, 0.375238001f, + -0.0621999837f, 0.280056626f, 0.0443522707f, 0.321513236f, 0.471269101f, 0.260774940f, + -0.107678331f, 0.188473806f, 0.0208210852f, 0.350526422f, 0.0157474391f, 0.367335707f, + 0.632996142f, 0.0804972649f, 0.646697879f, 0.265504390f, 0.0295150280f, 0.371205181f, + 0.376071006f, 0.313471258f, -0.379525930f, 0.364357829f, -0.00628023129f, -0.0373278372f, + 0.0291138459f, 0.381194293f, 0.0358079821f, 0.381886899f, 0.0344478637f, 0.386993408f, + 0.433862329f, 0.328515977f, 0.359724253f, 0.345606029f, 0.0651357397f, 0.397334814f, + 0.388413996f, 0.344747871f, -0.140228778f, 0.216103494f, 0.389989913f, 0.372472703f, + 0.444995403f, 0.300240308f, -0.606455386f, 0.100793049f, -0.362332910f, -0.371920794f, + -0.478956074f, 0.234040022f, -0.289441198f, -0.344822973f, -0.0714842379f, -0.0832463056f, + 0.375879139f, -0.374975592f, 0.376526117f, -0.326493502f, 0.313251913f, -0.306372881f, + -0.0577337518f, 0.0893306211f, -0.483683407f, -0.179540694f, -0.0763650239f, -0.258294433f, + 0.276665628f, -0.0881819800f, -0.167122558f, -0.175508693f, -0.164081737f, 0.176902041f, + 0.276665628f, -0.0881819800f, 0.602967978f, -0.260941893f, 0.158573851f, -0.178748295f, + 0.159815103f, -0.160761341f, 0.194283918f, -0.165657878f, 0.231515527f, -0.172808051f, + -0.247000366f, 0.277822912f, 0.538969517f, -0.204621449f, 0.531404376f, -0.198565826f, + -0.388338953f, -0.0433262810f, 0.499413073f, -0.181929186f, -0.237337112f, 0.0934364349f, + -0.368045300f, -0.0204487685f, -0.374767631f, -0.00678646797f, -0.0667242110f, -0.248651102f, + -0.248159677f, -0.254669130f, -0.345217139f, -0.00101677026f, -0.353382975f, 0.0210586078f, + -0.322639942f, 0.0211628731f, 0.0184581745f, -0.0366852731f, 0.0259528626f, -0.0136881955f, + -0.339446336f, 0.0286702402f, 0.0335014127f, -0.0271516014f, 0.465966076f, 0.0830826238f, + -0.337860256f, 0.0362124667f, 0.188271523f, -0.146541893f, -0.298272073f, -0.323130161f, + 0.0643569306f, -0.0264105909f, -0.353804410f, 0.0433940105f, 0.618646920f, -0.0855877250f, + 0.411329508f, -0.0414552018f, -0.427743971f, 0.100272447f, -0.247000366f, 0.277822912f, + 0.381912649f, -0.00914942939f, 0.0664352402f, 0.0467514023f, 0.138687640f, -0.114854909f, + -0.0170480162f, -0.372787565f, -0.535477102f, 0.183755845f, -0.155668780f, 0.144164801f, + -0.427504510f, 0.105302416f, -0.484430760f, 0.227277100f, -0.361284673f, -0.373513311f, + -0.316764563f, 0.331503242f, -0.0230990555f, 0.314180285f, 0.101539977f, -0.256640851f, + -0.210743994f, -0.111771651f, -0.560086846f, 0.151153624f, 0.542884171f, 0.141691014f, + 0.596041858f, 0.144990161f, 0.239398748f, 0.207432285f, 0.557545543f, 0.155783832f, + 0.233033463f, 0.214694947f, 0.572789013f, 0.162068501f, 0.512761712f, 0.176260322f, + 0.287076950f, 0.0868823677f, 0.515065968f, 0.205271944f, 0.552475691f, 0.198386014f, + -0.301232725f, 0.347804308f, -0.379525930f, 0.364357829f, 0.561403453f, 0.206571117f, + 0.590792358f, 0.206283644f, -0.428855836f, 0.100270294f, 0.300039053f, -0.283949375f, + 0.0481642894f, 0.334260821f, -0.173260480f, -0.167126089f, 0.444995403f, 0.300240308f, + 0.646697879f, 0.265504390f, 0.375487208f, 0.314186513f, 0.0217850581f, 0.381838262f, + 0.404422343f, 0.313856274f, 0.417644382f, 0.314869910f, 0.0358079821f, 0.381886899f, + 0.378262609f, 0.358303785f, -0.336999178f, -0.367679387f, -0.295442462f, -0.365161836f, + -0.293496192f, -0.342732310f, -0.298767596f, -0.303165644f, -0.0111337993f, -0.342149645f, + 0.310648471f, -0.374146342f, 0.359467417f, -0.373746723f, 0.340779394f, -0.369219989f, + -0.527450860f, -0.203896046f, -0.490746915f, -0.194764644f, 0.314866364f, -0.300261766f, + -0.0298556220f, 0.0591949411f, 0.319549739f, 0.0552458987f, 0.163977623f, -0.209844783f, + -0.149107113f, -0.149005055f, 0.212483421f, -0.191198543f, 0.197611198f, -0.187811792f, + 0.174361721f, -0.179897651f, 0.0387913659f, -0.0366905928f, -0.122265801f, -0.126270071f, + 0.211038783f, -0.172842503f, 0.246728286f, 0.134398326f, -0.0577337518f, 0.0893306211f, + -0.415295422f, 0.105914228f, -0.292730510f, 0.0379575789f, 0.489636958f, -0.194117576f, + -0.254337519f, 0.0937413648f, 0.336177140f, 0.305443168f, 0.526942134f, -0.164069965f, + 0.524966419f, -0.165161178f, -0.379173398f, 0.332068861f, -0.340792000f, 0.00105464540f, + 0.525632977f, -0.134992197f, -0.308774501f, 0.00290521770f, -0.375407755f, 0.0294080544f, + 0.0178439785f, -0.0365749858f, -0.255016476f, -0.0823200271f, -0.359951973f, 0.0446678996f, + 0.0564084686f, -0.0197724514f, -0.315141559f, 0.0424463004f, 0.292196661f, 0.279810339f, + -0.345294952f, 0.0533128195f, 0.0458479226f, -0.00109126628f, 0.0179449394f, 0.00371767790f, + 0.365872562f, -0.0412087664f, 0.403013051f, -0.0416624695f, -0.0714842379f, -0.0832463056f, + -0.209011748f, 0.133690849f, 0.0122421598f, 0.0230175443f, -0.0577337518f, 0.0893306211f, + -0.572846889f, 0.141102776f, 0.345340014f, -0.0111671211f, 0.0479373708f, 0.0379454680f, + 0.363291621f, -0.00829032529f, 0.381912649f, -0.00914942939f, -0.521542430f, 0.151489466f, + 0.345966965f, 0.0110620018f, 0.354562849f, 0.0254590791f, 0.334322065f, 0.0310698878f, + -0.00463629747f, -0.0357710384f, -0.538667142f, 0.185365483f, -0.209011748f, 0.133690849f, + 0.398122877f, 0.0403857268f, -0.160881191f, 0.145009249f, -0.155668780f, 0.144164801f, + -0.0714842379f, -0.0832463056f, -0.536377013f, 0.221241340f, -0.0632879063f, -0.247039422f, + -0.155869946f, 0.169341147f, 0.578685045f, -0.223878756f, 0.557447612f, 0.0768704116f, + -0.188812047f, 0.228197843f, 0.246747240f, 0.136472240f, -0.142677084f, 0.213736445f, + -0.118143238f, 0.208306640f, -0.388338953f, -0.0433262810f, -0.163515776f, 0.231573820f, + -0.0738375857f, -0.256104171f, 0.173092276f, 0.191535592f, 0.208548918f, 0.185476139f, + -0.392410189f, 0.0686017647f, 0.555366814f, 0.130478472f, -0.101943128f, -0.113997340f, + 0.0716935173f, 0.340265751f, 0.561738014f, 0.148283109f, 0.242452115f, 0.205116034f, + 0.561738014f, 0.148283109f, -0.427743971f, 0.100272447f, 0.578137994f, 0.163653031f, + 0.251277626f, 0.223055005f, -0.376505047f, 0.343530416f, -0.0714842379f, -0.0832463056f, + 0.567448437f, 0.207419440f, 0.590792358f, 0.206283644f, 0.578685045f, -0.223878756f, + 0.0635343120f, -0.00499309227f, -0.370767444f, 0.384881169f, -0.485191971f, -0.120962359f, + 0.512761712f, 0.176260322f, -0.375972956f, 0.0288736783f, -0.147176415f, -0.185790271f, + 0.0752977654f, 0.339190871f, 0.646697879f, 0.265504390f, 0.0282997675f, 0.373214334f, + 0.410353780f, 0.316089481f, 0.417644382f, 0.314869910f, 0.0147482762f, 0.389459789f, + -0.182916895f, -0.140514761f, 0.433515042f, 0.330774426f, 0.388069838f, 0.347381502f, + 0.378925055f, 0.357438952f, 0.247128293f, -0.116897359f, -0.0230906308f, 0.314556211f, + 0.388534039f, 0.370789021f, -0.368050814f, -0.339653373f, -0.292694926f, -0.341653705f, + -0.353774697f, -0.320387989f, 0.599263310f, -0.264537901f, -0.0213720929f, -0.326088905f, + -0.571947694f, 0.141147330f, -0.0577337518f, 0.0893306211f, 0.108424753f, -0.267108470f, + -0.0317604132f, -0.0458168685f, -0.0967136100f, 0.242639020f, -0.486509413f, -0.204596937f, + 0.239178345f, -0.219647482f, 0.108424753f, -0.267108470f, -0.280393064f, -0.283867925f, + -0.533659995f, -0.151733354f, 0.0880429000f, -0.240412414f, -0.534965396f, -0.124174178f, + 0.142445788f, -0.118948005f, 0.0947291106f, 0.0767719224f, -0.597055852f, -0.0692315027f, + -0.254337519f, 0.0937413648f, -0.308869720f, 0.00354974205f, -0.409894019f, -0.0694356859f, + 0.556049764f, -0.137727231f, -0.0317604132f, -0.0458168685f, -0.524152219f, 0.239541322f, + 0.108424753f, -0.267108470f, 0.0143662402f, -0.0164190196f, 0.150936082f, 0.128616557f, + 0.618646920f, -0.0855877250f, 0.0122421598f, 0.0230175443f, 0.0122421598f, 0.0230175443f, + -0.188812047f, 0.228197843f, 0.00441747159f, -0.297387213f, -0.520719767f, 0.152393058f, + 0.392849416f, 0.00738697406f, 0.400074363f, 0.0185570847f, -0.161484867f, -0.192373112f, + -0.554901838f, 0.190730989f, -0.538667142f, 0.185365483f, -0.0667442903f, 0.0997460634f, + 0.399885803f, 0.0410231315f, -0.159816831f, 0.145826310f, -0.193316415f, 0.161277503f, + -0.0678345188f, 0.287081748f, -0.383089483f, -0.283330113f, -0.538667142f, 0.185365483f, + 0.245664895f, 0.162005231f, 0.173092276f, 0.191535592f, 0.601281762f, 0.120500855f, + 0.208548918f, 0.185476139f, 0.246893004f, 0.220670119f, 0.516039073f, 0.178782418f, + -0.254337519f, 0.0937413648f, -0.254337519f, 0.0937413648f, -0.0230990555f, 0.314180285f, + 0.610029638f, 0.227215171f, -0.254337519f, 0.0937413648f, 0.0697976872f, 0.343245506f, + 0.538969517f, -0.204621449f, 0.00916308723f, 0.359826297f, 0.410353780f, 0.316089481f, + 0.423950195f, 0.324112266f, 0.166566655f, 0.145402640f, 0.354594171f, 0.350193948f, + 0.433712035f, 0.356235564f, 0.425307065f, 0.364637494f, 0.166924104f, -0.152513608f, + 0.594130874f, -0.268246830f, -0.0843627378f, -0.0962528363f, 0.108424753f, -0.267108470f, + 0.00760878995f, -0.304247797f, -0.471018314f, -0.178305879f, -0.0817007348f, -0.0933016762f, + 0.232274890f, 0.154553935f, 0.108424753f, -0.267108470f, -0.525787771f, -0.161353886f, + -0.206048280f, 0.241006181f, -0.178062543f, -0.184703678f, 0.105906568f, 0.268231422f, + -0.0817007348f, -0.0933016762f, 0.490914792f, 0.276718110f, -0.176861435f, -0.153617889f, + 0.0387795344f, 0.0457828715f, 0.456206828f, -0.250739783f, 0.0982551053f, 0.104225174f, + 0.142445788f, -0.118948005f, 0.108424753f, -0.267108470f, -0.0817007348f, -0.0933016762f, + -0.340707630f, 0.00498990202f, 0.0947291106f, 0.0767719224f, 0.169802040f, 0.203134149f, + 0.577375948f, -0.125099033f, 0.318376005f, -0.0486588739f, 0.388697982f, -0.0351444185f, + 0.406605273f, -0.0364143848f, 0.274859309f, 0.0776181892f, 0.349759877f, -7.70174083e-05f, + 0.402967423f, 0.00697830878f, 0.105906568f, 0.268231422f, 0.338973522f, 0.0359939188f, + 0.394951165f, 0.0322254188f, -0.503028810f, 0.203627899f, -0.0840740278f, -0.234684706f, + 0.108424753f, -0.267108470f, 0.286642373f, 0.103878126f, -0.0817007348f, -0.0933016762f, + 0.332983583f, -0.0356097035f, 0.628004134f, 0.0766527727f, -0.112659439f, -0.196833044f, + 0.568797410f, 0.136423931f, 0.456206828f, -0.250739783f, -0.254337519f, 0.0937413648f, + -0.206692874f, -0.210832119f, 0.550912619f, 0.171586066f, 0.581267595f, 0.213235661f, + 0.334484309f, 0.303876013f, -0.469516128f, 0.0883551016f, 0.133899942f, 0.106862970f, + -0.560961962f, -0.114681393f, -0.0840740278f, -0.234684706f, 0.459386230f, -0.236088052f, + 0.594130874f, -0.268246830f, -0.124856450f, 0.193096936f, -0.469516128f, 0.0883551016f, + 0.514290810f, -0.193822652f, 0.158255994f, 0.233290926f, 0.317973822f, -0.0477817170f, + -0.0817007348f, -0.0933016762f, -0.0702776462f, -0.0671426803f, 0.440836668f, -0.100193374f, + 0.326240778f, 0.0523138903f, -0.279556662f, -0.283929169f, -0.485202312f, -0.135626689f, + -0.467358112f, 0.246376559f, 0.232274890f, 0.154553935f, 0.258349210f, -0.269529581f, + 0.600620329f, 0.126268178f, -0.0985416993f, 0.245674044f, -0.279264033f, -0.0990248993f, + 0.108424753f, -0.267108470f, 0.259638488f, -0.100053802f, 0.605106652f, 0.223564968f, + 0.129683495f, -0.100376993f, -0.0953388065f, 0.112722203f, -0.440420747f, -0.0396305211f, + -0.0181254297f, 0.0439292751f, -0.0878356919f, 0.0847257674f, -0.271582603f, 0.126064256f, + -0.183777973f, -0.124357253f, 0.431088895f, 0.0680654719f, -0.469516128f, 0.0883551016f, + -0.445174575f, 0.133306518f, -0.0878356919f, 0.0847257674f, -0.279039949f, 0.0810008645f, + 0.612402737f, -0.0826834291f, -0.454494953f, 0.122878648f, 0.244000912f, -0.264438629f, + 0.142445788f, -0.118948005f, 0.129683495f, -0.100376993f, -0.210078895f, 0.131698489f, + -0.277847171f, 0.0665081516f, 0.431088895f, 0.0680654719f, 0.252345473f, 0.0688349009f, + 0.133899942f, 0.106862970f, 0.133899942f, 0.106862970f, -0.486509413f, -0.204596937f, + -0.0940247625f, 0.0698821172f, 0.133899942f, 0.106862970f, -0.440420747f, -0.0396305211f, + -0.0878356919f, 0.0847257674f, -0.0954068601f, -0.0968973264f, -0.277847171f, 0.0665081516f, + -0.277847171f, 0.0665081516f, 0.266677618f, 0.111257851f, 0.292424291f, -0.230888903f, + -0.0954068601f, -0.0968973264f + }; + + const Point2f* prevRectifiedPointArr_2f = (const Point2f*)prevRectifiedPointArr; + vector prevRectifiedPoints(prevRectifiedPointArr_2f, prevRectifiedPointArr_2f + + sizeof(prevRectifiedPointArr) / sizeof(prevRectifiedPointArr[0]) / 2); + + _prevRectifiedPoints.swap(prevRectifiedPoints); + + int validSolutionArr[2] = { 0, 2 }; + + vector validSolutions(validSolutionArr, validSolutionArr + + sizeof(validSolutionArr) / sizeof(validSolutionArr[0])); + + _validSolutions.swap(validSolutions); + + vector rotations; + vector normals; + + for (size_t i = 0; i < (sizeof(rotationsArray) / sizeof(*rotationsArray)); i++) { + Mat tempRotMat = Mat(Matx33d( + rotationsArray[i][0], + rotationsArray[i][1], + rotationsArray[i][2], + rotationsArray[i][3], + rotationsArray[i][4], + rotationsArray[i][5], + rotationsArray[i][6], + rotationsArray[i][7], + rotationsArray[i][8] + )); + + Mat tempNormMat = Mat(Matx31d( + normalsArray[i][0], + normalsArray[i][1], + normalsArray[i][2] + )); + + rotations.push_back(tempRotMat); + normals.push_back(tempNormMat); + } + + _rotations.swap(rotations); + _normals.swap(normals); + + _mask = Mat(514, 1, CV_8U, maskArray).clone(); + } + + bool isValidResult(const vector& solutions) + { + return (solutions == _validSolutions); + } + + vector _validSolutions; + vector _prevRectifiedPoints, _currRectifiedPoints; + Mat _mask; + vector _rotations, _normals; +}; + +TEST(Calib3d_FilterDecomposeHomography, regression) { CV_FilterHomographyDecompTest test; test.safe_run(); } + +}} diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 5e7f4a879a..e67e58b98e 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -463,9 +463,14 @@ static bool ipp_Mat_setTo_Mat(Mat &dst, Mat &_val, Mat &mask) return false; if (dst.depth() == CV_32F) + { for (int i = 0; i < (int)(_val.total()); i++) - if (_val.at(i) < iwTypeGetMin(ipp32f) || _val.at(i) > iwTypeGetMax(ipp32f)) + { + float v = (float)(_val.at(i)); // cast to float + if (cvIsNaN(v) || cvIsInf(v)) // accept finite numbers only return false; + } + } if(dst.dims <= 2) { diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 18906f8dcd..ad480eb8d3 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1612,6 +1612,32 @@ TEST(Mat, regression_7873_mat_vector_initialize) ASSERT_EQ(2, sub_mat.size[2]); } +TEST(Mat, regression_10507_mat_setTo) +{ + Size sz(6, 4); + Mat test_mask(sz, CV_8UC1, cv::Scalar::all(255)); + test_mask.at(1,0) = 0; + test_mask.at(0,1) = 0; + for (int cn = 1; cn <= 4; cn++) + { + cv::Mat A(sz, CV_MAKE_TYPE(CV_32F, cn), cv::Scalar::all(5)); + A.setTo(cv::Scalar::all(std::numeric_limits::quiet_NaN()), test_mask); + int nans = 0; + for (int y = 0; y < A.rows; y++) + { + for (int x = 0; x < A.cols; x++) + { + for (int c = 0; c < cn; c++) + { + float v = A.ptr(y, x)[c]; + nans += (v == v) ? 0 : 1; + } + } + } + EXPECT_EQ(nans, cn * (sz.area() - 2)) << "A=" << A << std::endl << "mask=" << test_mask << std::endl; + } +} + #ifdef CV_CXX_STD_ARRAY TEST(Core_Mat_array, outputArray_create_getMat) { diff --git a/modules/dnn/CMakeLists.txt b/modules/dnn/CMakeLists.txt index 9549439fd4..e306dde188 100644 --- a/modules/dnn/CMakeLists.txt +++ b/modules/dnn/CMakeLists.txt @@ -12,7 +12,8 @@ ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX) ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java js) -ocv_option(OPENCV_DNN_OPENCL "Build with OpenCL support" HAVE_OPENCL) +ocv_option(OPENCV_DNN_OPENCL "Build with OpenCL support" HAVE_OPENCL AND NOT APPLE) + if(OPENCV_DNN_OPENCL AND HAVE_OPENCL) add_definitions(-DCV_OCL4DNN=1) else() diff --git a/modules/dnn/include/opencv2/dnn/all_layers.hpp b/modules/dnn/include/opencv2/dnn/all_layers.hpp index 55b85a0b56..9ba180c7d1 100644 --- a/modules/dnn/include/opencv2/dnn/all_layers.hpp +++ b/modules/dnn/include/opencv2/dnn/all_layers.hpp @@ -361,6 +361,23 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN static Ptr create(const LayerParams& params); }; + /** + * Permute channels of 4-dimensional input blob. + * @param group Number of groups to split input channels and pick in turns + * into output blob. + * + * \f[ groupSize = \frac{number\ of\ channels}{group} \f] + * \f[ output(n, c, h, w) = input(n, groupSize \times (c \% group) + \lfloor \frac{c}{group} \rfloor, h, w) \f] + * Read more at https://arxiv.org/pdf/1707.01083.pdf + */ + class CV_EXPORTS ShuffleChannelLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + + int group; + }; + /** * @brief Adds extra values for specific axes. * @param paddings Vector of paddings in format @@ -575,6 +592,17 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN static Ptr create(const LayerParams& params); }; + /** + * @brief Bilinear resize layer from https://github.com/cdmh/deeplab-public + * + * It differs from @ref ResizeLayer in output shape and resize scales computations. + */ + class CV_EXPORTS InterpLayer : public Layer + { + public: + static Ptr create(const LayerParams& params); + }; + class CV_EXPORTS ProposalLayer : public Layer { public: diff --git a/modules/dnn/perf/perf_net.cpp b/modules/dnn/perf/perf_net.cpp index e8569dcf10..16138cb99f 100644 --- a/modules/dnn/perf/perf_net.cpp +++ b/modules/dnn/perf/perf_net.cpp @@ -144,7 +144,8 @@ PERF_TEST_P_(DNNTestNetwork, SSD) PERF_TEST_P_(DNNTestNetwork, OpenFace) { if (backend == DNN_BACKEND_HALIDE || - backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU) + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16) || + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)) throw SkipTestException(""); processNet("dnn/openface_nn4.small2.v1.t7", "", "", Mat(cv::Size(96, 96), CV_32FC3)); @@ -248,6 +249,15 @@ PERF_TEST_P_(DNNTestNetwork, EAST_text_detection) processNet("dnn/frozen_east_text_detection.pb", "", "", Mat(cv::Size(320, 320), CV_32FC3)); } +PERF_TEST_P_(DNNTestNetwork, FastNeuralStyle_eccv16) +{ + if (backend == DNN_BACKEND_HALIDE || + (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) || + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)) + throw SkipTestException(""); + processNet("dnn/fast_neural_style_eccv16_starry_night.t7", "", "", Mat(cv::Size(320, 240), CV_32FC3)); +} + const tuple testCases[] = { #ifdef HAVE_HALIDE tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU), diff --git a/modules/dnn/src/darknet/darknet_io.cpp b/modules/dnn/src/darknet/darknet_io.cpp index 91ebb0fa8b..03805dd364 100644 --- a/modules/dnn/src/darknet/darknet_io.cpp +++ b/modules/dnn/src/darknet/darknet_io.cpp @@ -212,6 +212,44 @@ namespace cv { fused_layer_names.push_back(last_layer); } + void setAvgpool() + { + cv::dnn::LayerParams avgpool_param; + avgpool_param.set("pool", "ave"); + avgpool_param.set("global_pooling", true); + avgpool_param.name = "Pooling-name"; + avgpool_param.type = "Pooling"; + darknet::LayerParameter lp; + + std::string layer_name = cv::format("avgpool_%d", layer_id); + lp.layer_name = layer_name; + lp.layer_type = avgpool_param.type; + lp.layerParams = avgpool_param; + lp.bottom_indexes.push_back(last_layer); + last_layer = layer_name; + net->layers.push_back(lp); + layer_id++; + fused_layer_names.push_back(last_layer); + } + + void setSoftmax() + { + cv::dnn::LayerParams softmax_param; + softmax_param.name = "Softmax-name"; + softmax_param.type = "Softmax"; + darknet::LayerParameter lp; + + std::string layer_name = cv::format("softmax_%d", layer_id); + lp.layer_name = layer_name; + lp.layer_type = softmax_param.type; + lp.layerParams = softmax_param; + lp.bottom_indexes.push_back(last_layer); + last_layer = layer_name; + net->layers.push_back(lp); + layer_id++; + fused_layer_names.push_back(last_layer); + } + void setConcat(int number_of_inputs, int *input_indexes) { cv::dnn::LayerParams concat_param; @@ -541,6 +579,17 @@ namespace cv { int pad = getParam(layer_params, "pad", 0); setParams.setMaxpool(kernel_size, pad, stride); } + else if (layer_type == "avgpool") + { + setParams.setAvgpool(); + } + else if (layer_type == "softmax") + { + int groups = getParam(layer_params, "groups", 1); + if (groups != 1) + CV_Error(Error::StsNotImplemented, "Softmax from Darknet with groups != 1"); + setParams.setSoftmax(); + } else if (layer_type == "route") { std::string bottom_layers = getParam(layer_params, "layers", ""); diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 98d6fdc186..0177b31a47 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -66,6 +66,15 @@ static bool DNN_DISABLE_MEMORY_OPTIMIZATIONS = utils::getConfigurationParameterB static bool DNN_OPENCL_ALLOW_ALL_DEVICES = utils::getConfigurationParameterBool("OPENCV_DNN_OPENCL_ALLOW_ALL_DEVICES", false); #endif +static int PARAM_DNN_BACKEND_DEFAULT = (int)utils::getConfigurationParameterSizeT("OPENCV_DNN_BACKEND_DEFAULT", +#ifdef HAVE_INF_ENGINE + (size_t)DNN_BACKEND_INFERENCE_ENGINE +#else + (size_t)DNN_BACKEND_OPENCV +#endif +); + + using std::vector; using std::map; using std::make_pair; @@ -851,11 +860,8 @@ struct Net::Impl CV_TRACE_FUNCTION(); if (preferableBackend == DNN_BACKEND_DEFAULT) -#ifdef HAVE_INF_ENGINE - preferableBackend = DNN_BACKEND_INFERENCE_ENGINE; -#else - preferableBackend = DNN_BACKEND_OPENCV; -#endif + preferableBackend = (Backend)PARAM_DNN_BACKEND_DEFAULT; + CV_Assert(preferableBackend != DNN_BACKEND_OPENCV || preferableTarget == DNN_TARGET_CPU || preferableTarget == DNN_TARGET_OPENCL || @@ -982,52 +988,26 @@ struct Net::Impl ld.inputBlobsId[inNum] = from; } - static void splitPin(const String &pinAlias, String &layerName, String &outName) - { - size_t delimPos = pinAlias.find('.'); - layerName = pinAlias.substr(0, delimPos); - outName = (delimPos == String::npos) ? String() : pinAlias.substr(delimPos + 1); - } - int resolvePinOutputName(LayerData &ld, const String &outName) { if (outName.empty()) return 0; - - if (std::isdigit(outName[0])) - { - char *lastChar; - long inum = std::strtol(outName.c_str(), &lastChar, 10); - - if (*lastChar == 0) - { - CV_Assert(inum == (int)inum); - return (int)inum; - } - } - return ld.getLayerInstance()->outputNameToIndex(outName); } - LayerPin getPinByAlias(const String &pinAlias) + LayerPin getPinByAlias(const String &layerName) { LayerPin pin; - String layerName, outName; - splitPin(pinAlias, layerName, outName); - pin.lid = (layerName.empty()) ? 0 : getLayerId(layerName); if (pin.lid >= 0) - pin.oid = resolvePinOutputName(getLayerData(pin.lid), outName); + pin.oid = resolvePinOutputName(getLayerData(pin.lid), layerName); return pin; } - std::vector getLayerOutPins(const String &pinAlias) + std::vector getLayerOutPins(const String &layerName) { - String layerName, outName; - splitPin(pinAlias, layerName, outName); - int lid = (layerName.empty()) ? 0 : getLayerId(layerName); std::vector pins; @@ -1466,7 +1446,7 @@ struct Net::Impl // TODO: OpenCL target support more fusion styles. if ( preferableBackend == DNN_BACKEND_OPENCV && IS_DNN_OPENCL_TARGET(preferableTarget) && (!cv::ocl::useOpenCL() || (ld.layerInstance->type != "Convolution" && - ld.layerInstance->type != "MVN")) ) + ld.layerInstance->type != "MVN" && ld.layerInstance->type != "Pooling")) ) continue; Ptr& currLayer = ld.layerInstance; @@ -2013,11 +1993,17 @@ Net Net::readFromModelOptimizer(const String& xml, const String& bin) backendNode->net = Ptr(new InfEngineBackendNet(ieNet)); for (auto& it : ieNet.getOutputsInfo()) { + Ptr cvLayer(new InfEngineBackendLayer(it.second)); + InferenceEngine::CNNLayerPtr ieLayer = ieNet.getLayerByName(it.first.c_str()); + CV_Assert(ieLayer); + LayerParams lp; int lid = cvNet.addLayer(it.first, "", lp); LayerData& ld = cvNet.impl->layers[lid]; - ld.layerInstance = Ptr(new InfEngineBackendLayer(it.second)); + cvLayer->name = it.first; + cvLayer->type = ieLayer->type; + ld.layerInstance = cvLayer; ld.backendNodes[DNN_BACKEND_INFERENCE_ENGINE] = backendNode; for (int i = 0; i < inputsNames.size(); ++i) @@ -2038,12 +2024,6 @@ int Net::addLayer(const String &name, const String &type, LayerParams ¶ms) { CV_TRACE_FUNCTION(); - if (name.find('.') != String::npos) - { - CV_Error(Error::StsBadArg, "Added layer name \"" + name + "\" must not contain dot symbol"); - return -1; - } - if (impl->getLayerId(name) >= 0) { CV_Error(Error::StsBadArg, "Layer \"" + name + "\" already into net"); @@ -2683,7 +2663,7 @@ int Layer::inputNameToIndex(String) int Layer::outputNameToIndex(const String&) { - return -1; + return 0; } bool Layer::supportBackend(int backendId) diff --git a/modules/dnn/src/init.cpp b/modules/dnn/src/init.cpp index e5c3a279e5..8db0828e62 100644 --- a/modules/dnn/src/init.cpp +++ b/modules/dnn/src/init.cpp @@ -84,6 +84,7 @@ void initializeLayerFactory() CV_DNN_REGISTER_LAYER_CLASS(Reshape, ReshapeLayer); CV_DNN_REGISTER_LAYER_CLASS(Flatten, FlattenLayer); CV_DNN_REGISTER_LAYER_CLASS(Resize, ResizeLayer); + CV_DNN_REGISTER_LAYER_CLASS(Interp, InterpLayer); CV_DNN_REGISTER_LAYER_CLASS(CropAndResize, CropAndResizeLayer); CV_DNN_REGISTER_LAYER_CLASS(Convolution, ConvolutionLayer); @@ -115,6 +116,7 @@ void initializeLayerFactory() CV_DNN_REGISTER_LAYER_CLASS(Crop, CropLayer); CV_DNN_REGISTER_LAYER_CLASS(Eltwise, EltwiseLayer); CV_DNN_REGISTER_LAYER_CLASS(Permute, PermuteLayer); + CV_DNN_REGISTER_LAYER_CLASS(ShuffleChannel, ShuffleChannelLayer); CV_DNN_REGISTER_LAYER_CLASS(PriorBox, PriorBoxLayer); CV_DNN_REGISTER_LAYER_CLASS(PriorBoxClustered, PriorBoxLayer); CV_DNN_REGISTER_LAYER_CLASS(Reorg, ReorgLayer); diff --git a/modules/dnn/src/layers/batch_norm_layer.cpp b/modules/dnn/src/layers/batch_norm_layer.cpp index d42face4ec..3b472328c8 100644 --- a/modules/dnn/src/layers/batch_norm_layer.cpp +++ b/modules/dnn/src/layers/batch_norm_layer.cpp @@ -96,6 +96,46 @@ public: shift = bias_; } + virtual bool tryFuse(Ptr& top) CV_OVERRIDE + { + Mat w, b; + top->getScaleShift(w, b); + if (w.empty() && b.empty()) + return false; + + const int numChannels = weights_.total(); + const int numFusedWeights = w.total(); + const int numFusedBias = b.total(); + + if ((numFusedWeights != numChannels && numFusedWeights != 1 && !w.empty()) || + (numFusedBias != numChannels && numFusedBias != 1 && !b.empty())) + return false; + + if (!w.empty()) + { + w = w.reshape(1, 1); + if (numFusedWeights == 1) + { + multiply(weights_, w.at(0), weights_); + multiply(bias_, w.at(0), bias_); + } + else + { + multiply(weights_, w, weights_); + multiply(bias_, w, bias_); + } + } + if (!b.empty()) + { + b = b.reshape(1, 1); + if (numFusedBias == 1) + add(bias_, b.at(0), bias_); + else + add(bias_, b.reshape(1, 1), bias_); + } + return true; + } + bool getMemoryShapes(const std::vector &inputs, const int requiredOutputs, std::vector &outputs, diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index 5eac3e90f3..27818e5e7c 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -81,9 +81,10 @@ public: virtual bool supportBackend(int backendId) CV_OVERRIDE { - return backendId == DNN_BACKEND_OPENCV || - backendId == DNN_BACKEND_HALIDE && haveHalide() || - backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine(); + if (backendId == DNN_BACKEND_INFERENCE_ENGINE) + return preferableTarget != DNN_TARGET_MYRIAD || type != "Deconvolution" || adjustPad == Size(); + else + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE; } void finalize(const std::vector &inputs, std::vector &outputs) CV_OVERRIDE diff --git a/modules/dnn/src/layers/crop_and_resize_layer.cpp b/modules/dnn/src/layers/crop_and_resize_layer.cpp index a9bca1f04b..ad2280f30c 100644 --- a/modules/dnn/src/layers/crop_and_resize_layer.cpp +++ b/modules/dnn/src/layers/crop_and_resize_layer.cpp @@ -1,3 +1,9 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2018, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. #include "../precomp.hpp" #include "layers_common.hpp" diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp index 801916d9c4..c95bdcd509 100644 --- a/modules/dnn/src/layers/elementwise_layers.cpp +++ b/modules/dnn/src/layers/elementwise_layers.cpp @@ -115,9 +115,7 @@ public: virtual bool supportBackend(int backendId) CV_OVERRIDE { - return backendId == DNN_BACKEND_OPENCV || - backendId == DNN_BACKEND_HALIDE && haveHalide() || - backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine(); + return func.supportBackend(backendId, this->preferableTarget); } virtual Ptr tryAttach(const Ptr& node) CV_OVERRIDE @@ -238,6 +236,12 @@ struct ReLUFunctor explicit ReLUFunctor(float slope_=1.f) : slope(slope_) {} + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE || + backendId == DNN_BACKEND_INFERENCE_ENGINE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { float s = slope; @@ -353,6 +357,12 @@ struct ReLU6Functor CV_Assert(minValue <= maxValue); } + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE || + backendId == DNN_BACKEND_INFERENCE_ENGINE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize ) @@ -445,6 +455,12 @@ struct TanHFunctor { typedef TanHLayer Layer; + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE || + backendId == DNN_BACKEND_INFERENCE_ENGINE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize ) @@ -509,6 +525,12 @@ struct SigmoidFunctor { typedef SigmoidLayer Layer; + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE || + backendId == DNN_BACKEND_INFERENCE_ENGINE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize ) @@ -575,6 +597,11 @@ struct ELUFunctor explicit ELUFunctor() {} + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize ) @@ -638,6 +665,11 @@ struct AbsValFunctor { typedef AbsLayer Layer; + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize ) @@ -701,6 +733,11 @@ struct BNLLFunctor { typedef BNLLLayer Layer; + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize ) @@ -751,6 +788,14 @@ struct PowerFunctor explicit PowerFunctor(float power_ = 1.f, float scale_ = 1.f, float shift_ = 0.f) : power(power_), scale(scale_), shift(shift_) {} + bool supportBackend(int backendId, int targetId) + { + if (backendId == DNN_BACKEND_INFERENCE_ENGINE) + return (targetId != DNN_TARGET_OPENCL && targetId != DNN_TARGET_OPENCL_FP16) || power == 1.0; + else + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { float a = scale, b = shift, p = power; @@ -853,6 +898,11 @@ struct ChannelsPReLUFunctor scale_umat = scale.getUMat(ACCESS_READ); } + bool supportBackend(int backendId, int) + { + return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_HALIDE; + } + void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const { CV_Assert(scale.isContinuous() && scale.type() == CV_32F); diff --git a/modules/dnn/src/layers/fully_connected_layer.cpp b/modules/dnn/src/layers/fully_connected_layer.cpp index 5152d60269..499f672918 100644 --- a/modules/dnn/src/layers/fully_connected_layer.cpp +++ b/modules/dnn/src/layers/fully_connected_layer.cpp @@ -310,7 +310,6 @@ public: innerProductOp = Ptr >(new OCL4DNNInnerProduct(config)); } - UMat biasOnesMat = UMat::ones(outerSize, 1, umat_blobs[0].type()); for (size_t i = 0; i < inputs.size(); i++) { MatShape inshape, outshape; @@ -320,7 +319,6 @@ public: UMat srcMat, dstMat; srcMat = inputs[i].reshape(1, inshape.size(), &inshape[0]); dstMat = outputs[i].reshape(1, outshape.size(), &outshape[0]); - dstMat.setTo(0.0f); if (!innerProductOp->Forward(srcMat, (use_half) ? half_blobs[0] : umat_blobs[0], (bias) ? (use_half ? half_blobs[1] : umat_blobs[1]) : UMat(), @@ -332,6 +330,7 @@ public: if (!use_half && bias && (outerSize > 1)) { + UMat biasOnesMat = UMat::ones(outerSize, 1, umat_blobs[0].type()); UMat& biases = umat_blobs[1]; cv::gemm(biasOnesMat, biases, 1, dstMat, 1, dstMat, 0); } @@ -354,6 +353,7 @@ public: if (bias) { + UMat biasOnesMat = UMat::ones(outerSize, 1, umat_blobs[0].type()); UMat& biases = umat_blobs[1]; cv::gemm(biasOnesMat, biases, 1, dstMat, 1, dstMat, 0); } diff --git a/modules/dnn/src/layers/pooling_layer.cpp b/modules/dnn/src/layers/pooling_layer.cpp index eab1dcaa8a..775a044b44 100644 --- a/modules/dnn/src/layers/pooling_layer.cpp +++ b/modules/dnn/src/layers/pooling_layer.cpp @@ -165,6 +165,7 @@ public: (type == AVE ? LIBDNN_POOLING_METHOD_AVE : LIBDNN_POOLING_METHOD_STO); config.avePoolPaddedArea = avePoolPaddedArea; + config.computeMaxIdx = computeMaxIdx; config.use_half = use_half; poolOp = Ptr >(new OCL4DNNPool(config)); } diff --git a/modules/dnn/src/layers/reshape_layer.cpp b/modules/dnn/src/layers/reshape_layer.cpp index 65a81c7820..c9e632dd29 100644 --- a/modules/dnn/src/layers/reshape_layer.cpp +++ b/modules/dnn/src/layers/reshape_layer.cpp @@ -82,17 +82,26 @@ static void computeShapeByReshapeMask(const MatShape &srcShape, { if (matched) { - if (i == 0 || total(srcShape, i, srcRange.end) != maskTotal) + if (total(srcShape, i, srcRange.end) != maskTotal) { srcRange.start = i + 1; break; } + else if (i == 0) + { + srcRange.start = 0; + break; + } } else { matched = total(srcShape, i, srcRange.end) == maskTotal; } } + while (total(srcShape, srcRange.start, srcRange.end) != maskTotal && srcRange.start > 0) + { + srcRange.start -= 1; + } CV_Assert(total(srcShape, srcRange.start, srcRange.end) == maskTotal); } diff --git a/modules/dnn/src/layers/resize_layer.cpp b/modules/dnn/src/layers/resize_layer.cpp index 82bc6542be..358ee8dd99 100644 --- a/modules/dnn/src/layers/resize_layer.cpp +++ b/modules/dnn/src/layers/resize_layer.cpp @@ -11,7 +11,7 @@ namespace cv { namespace dnn { -class ResizeLayerImpl CV_FINAL : public ResizeLayer +class ResizeLayerImpl : public ResizeLayer { public: ResizeLayerImpl(const LayerParams& params) @@ -33,7 +33,7 @@ public: interpolation = params.get("interpolation"); CV_Assert(interpolation == "nearest" || interpolation == "bilinear"); - alignCorners = params.get("align_corners", false); + bool alignCorners = params.get("align_corners", false); if (alignCorners) CV_Error(Error::StsNotImplemented, "Resize with align_corners=true is not implemented"); } @@ -53,8 +53,10 @@ public: virtual bool supportBackend(int backendId) CV_OVERRIDE { - return backendId == DNN_BACKEND_OPENCV || - backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && interpolation == "nearest"; + if (backendId == DNN_BACKEND_INFERENCE_ENGINE) + return interpolation == "nearest" && preferableTarget != DNN_TARGET_MYRIAD; + else + return backendId == DNN_BACKEND_OPENCV; } virtual void finalize(const std::vector& inputs, std::vector &outputs) CV_OVERRIDE @@ -64,6 +66,8 @@ public: outHeight = outputs[0].size[2]; outWidth = outputs[0].size[3]; } + scaleHeight = static_cast(inputs[0]->size[2]) / outHeight; + scaleWidth = static_cast(inputs[0]->size[3]) / outWidth; } void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE @@ -101,8 +105,6 @@ public: const int inpWidth = inp.size[3]; const int inpSpatialSize = inpHeight * inpWidth; const int outSpatialSize = outHeight * outWidth; - const float heightScale = static_cast(inpHeight) / (outHeight); - const float widthScale = static_cast(inpWidth) / (outWidth); const int numPlanes = inp.size[0] * inp.size[1]; CV_Assert(inp.isContinuous(), out.isContinuous()); @@ -110,13 +112,13 @@ public: Mat outPlanes = out.reshape(1, numPlanes * outHeight); for (int y = 0; y < outHeight; ++y) { - float input_y = y * heightScale; + float input_y = y * scaleHeight; int y0 = static_cast(input_y); const float* inpData_row0 = inpPlanes.ptr(y0); const float* inpData_row1 = inpPlanes.ptr(std::min(y0 + 1, inpHeight - 1)); for (int x = 0; x < outWidth; ++x) { - float input_x = x * widthScale; + float input_x = x * scaleWidth; int x0 = static_cast(input_x); int x1 = std::min(x0 + 1, inpWidth - 1); @@ -160,10 +162,10 @@ public: return Ptr(); } -private: +protected: int outWidth, outHeight, zoomFactorWidth, zoomFactorHeight; String interpolation; - bool alignCorners; + float scaleWidth, scaleHeight; }; @@ -172,5 +174,44 @@ Ptr ResizeLayer::create(const LayerParams& params) return Ptr(new ResizeLayerImpl(params)); } +class InterpLayerImpl CV_FINAL : public ResizeLayerImpl +{ +public: + InterpLayerImpl(const LayerParams& params) : ResizeLayerImpl(params) {} + + bool getMemoryShapes(const std::vector &inputs, + const int requiredOutputs, + std::vector &outputs, + std::vector &internals) const CV_OVERRIDE + { + CV_Assert(inputs.size() == 1, inputs[0].size() == 4); + outputs.resize(1, inputs[0]); + outputs[0][2] = outHeight > 0 ? outHeight : (1 + zoomFactorHeight * (outputs[0][2] - 1)); + outputs[0][3] = outWidth > 0 ? outWidth : (1 + zoomFactorWidth * (outputs[0][3] - 1)); + // We can work in-place (do nothing) if input shape == output shape. + return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]); + } + + virtual void finalize(const std::vector& inputs, std::vector &outputs) CV_OVERRIDE + { + if (!outWidth && !outHeight) + { + outHeight = outputs[0].size[2]; + outWidth = outputs[0].size[3]; + } + int inpHeight = inputs[0]->size[2]; + int inpWidth = inputs[0]->size[3]; + scaleHeight = (outHeight > 1) ? (static_cast(inpHeight - 1) / (outHeight - 1)) : 0.f; + scaleWidth = (outWidth > 1) ? (static_cast(inpWidth - 1) / (outWidth - 1)) : 0.f; + } +}; + +Ptr InterpLayer::create(const LayerParams& params) +{ + LayerParams lp(params); + lp.set("interpolation", "bilinear"); + return Ptr(new InterpLayerImpl(lp)); +} + } // namespace dnn } // namespace cv diff --git a/modules/dnn/src/layers/shuffle_channel_layer.cpp b/modules/dnn/src/layers/shuffle_channel_layer.cpp new file mode 100644 index 0000000000..6c69d773a4 --- /dev/null +++ b/modules/dnn/src/layers/shuffle_channel_layer.cpp @@ -0,0 +1,104 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Copyright (C) 2018, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +#include "../precomp.hpp" + +namespace cv { namespace dnn { + +class ShuffleChannelLayerImpl CV_FINAL : public ShuffleChannelLayer +{ +public: + ShuffleChannelLayerImpl(const LayerParams& params) + { + group = params.get("group", 1); + } + + bool getMemoryShapes(const std::vector &inputs, + const int requiredOutputs, + std::vector &outputs, + std::vector &internals) const CV_OVERRIDE + { + CV_Assert(inputs.size() == 1 && inputs[0].size() == 4); + CV_Assert(inputs[0][1] % group == 0); + Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals); + return group == 1; + } + + virtual void finalize(const std::vector& inputs, std::vector &outputs) CV_OVERRIDE + { + if (group != 1) + { + LayerParams lp; + float order[] = {0, 2, 1, 3}; + lp.set("order", DictValue::arrayInt(&order[0], 4)); + permute = PermuteLayer::create(lp); + + Mat inp = *inputs[0]; + Mat out = outputs[0]; + + permuteInpShape.resize(4); + permuteInpShape[0] = inp.size[0]; + permuteInpShape[1] = group; + permuteInpShape[2] = inp.size[1] / group; + permuteInpShape[3] = inp.size[2]*inp.size[3]; + + permuteOutShape.resize(4); + permuteOutShape[0] = permuteInpShape[0]; + permuteOutShape[1] = permuteInpShape[2]; + permuteOutShape[2] = permuteInpShape[1]; + permuteOutShape[3] = permuteInpShape[3]; + + inp = inp.reshape(1, permuteInpShape); + out = out.reshape(1, permuteOutShape); + + std::vector permuteInputs(1, &inp); + std::vector permuteOutputs(1, out); + permute->finalize(permuteInputs, permuteOutputs); + } + } + + void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE + { + CV_TRACE_FUNCTION(); + CV_TRACE_ARG_VALUE(name, "name", name.c_str()); + + Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr); + } + + void forward(std::vector &inputs, std::vector &outputs, std::vector &internals) CV_OVERRIDE + { + CV_TRACE_FUNCTION(); + CV_TRACE_ARG_VALUE(name, "name", name.c_str()); + + Mat inp = *inputs[0]; + Mat out = outputs[0]; + if (inp.data != out.data) + { + if (!permute.empty()) + { + inp = inp.reshape(1, permuteInpShape); + out = out.reshape(1, permuteOutShape); + std::vector permuteInputs(1, &inp); + std::vector permuteOutputs(1, out); + permute->forward(permuteInputs, permuteOutputs, internals); + } + else + inp.copyTo(out); + } + } + +private: + Ptr permute; + std::vector permuteInpShape, permuteOutShape; +}; + +Ptr ShuffleChannelLayer::create(const LayerParams& params) +{ + return Ptr(new ShuffleChannelLayerImpl(params)); +} + +} // namespace dnn +} // namespace cv diff --git a/modules/dnn/src/layers/slice_layer.cpp b/modules/dnn/src/layers/slice_layer.cpp index 4b3a975b2a..f6f4109c61 100644 --- a/modules/dnn/src/layers/slice_layer.cpp +++ b/modules/dnn/src/layers/slice_layer.cpp @@ -41,6 +41,7 @@ //M*/ #include "../precomp.hpp" +#include "../op_inf_engine.hpp" #include "layers_common.hpp" #include @@ -107,6 +108,12 @@ public: } } + virtual bool supportBackend(int backendId) CV_OVERRIDE + { + return backendId == DNN_BACKEND_OPENCV || + backendId == DNN_BACKEND_INFERENCE_ENGINE && sliceRanges.size() == 1; + } + bool getMemoryShapes(const std::vector &inputs, const int requiredOutputs, std::vector &outputs, @@ -247,6 +254,29 @@ public: inpMat(sliceRanges[i]).copyTo(outputs[i]); } } + + virtual Ptr initInfEngine(const std::vector >& inputs) CV_OVERRIDE + { +#ifdef HAVE_INF_ENGINE + InferenceEngine::DataPtr input = infEngineDataNode(inputs[0]); + InferenceEngine::LayerParams lp; + lp.name = name; + lp.type = "Crop"; + lp.precision = InferenceEngine::Precision::FP32; + std::shared_ptr ieLayer(new InferenceEngine::CropLayer(lp)); + + CV_Assert(sliceRanges.size() == 1); + for (int i = sliceRanges[0].size() - 1; i >= 0; --i) + { + ieLayer->axis.push_back(i); + ieLayer->offset.push_back(sliceRanges[0][i].start); + ieLayer->dim.push_back(sliceRanges[0][i].end - sliceRanges[0][i].start); + } + return Ptr(new InfEngineBackendNode(ieLayer)); + +#endif // HAVE_INF_ENGINE + return Ptr(); + } }; Ptr SliceLayer::create(const LayerParams& params) diff --git a/modules/dnn/src/ocl4dnn/include/default_kernel_config.hpp b/modules/dnn/src/ocl4dnn/include/default_kernel_config.hpp index 09e0c27473..a25b2bf0d5 100644 --- a/modules/dnn/src/ocl4dnn/include/default_kernel_config.hpp +++ b/modules/dnn/src/ocl4dnn/include/default_kernel_config.hpp @@ -1,23 +1,24 @@ #ifndef _OPENCV_OCL4DNN_DEFAULT_KERNEL_CONFIG_HPP_ #define _OPENCV_OCL4DNN_DEFAULT_KERNEL_CONFIG_HPP_ -const char *default_kernel_config_intel[] = { +const char *default_kernel_config_intel_fp32[] = { // Below is the information for OpenCL based on which these configurations tuned /******************************************************************************* Number of platforms 1 - Platform Name Intel(R) OpenCL + Platform Name Intel(R) OpenCL HD Graphics Platform Vendor Intel(R) Corporation - Platform Version OpenCL 2.0 + Platform Version OpenCL 2.1 Platform Profile FULL_PROFILE - Platform Extensions cl_intel_accelerator cl_intel_advanced_motion_estimation cl_intel_device_side_avc_motion_estimation cl_intel_driver_diagnostics cl_intel_media_block_io cl_intel_motion_estimation cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_required_subgroup_size cl_intel_subgroups cl_intel_subgroups_short cl_intel_va_api_media_sharing cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_fp16 cl_khr_fp64 cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_spir cl_khr_subgroups + Platform Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_fp64 cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation + Platform Host timer resolution 1ns Platform Extensions function suffix INTEL - Platform Name Intel(R) OpenCL + Platform Name Intel(R) OpenCL HD Graphics Number of devices 1 - Device Name Intel(R) HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO Device Vendor Intel(R) Corporation Device Vendor ID 0x8086 - Device Version OpenCL 2.0 - Driver Version r4.1.61547 + Device Version OpenCL 2.1 NEO + Driver Version 2018ww15-010713 Device OpenCL C Version OpenCL C 2.0 Device Type GPU Device Profile FULL_PROFILE @@ -25,11 +26,12 @@ Number of devices 1 Max clock frequency 950MHz Device Partition (core) Max number of sub-devices 0 - Supported partition types by (0x7F2F00000000) + Supported partition types None Max work item dimensions 3 Max work item sizes 256x256x256 Max work group size 256 Preferred work group size multiple 32 + Max sub-groups per work group 32 Preferred / native vector sizes char 16 / 16 short 8 / 8 @@ -66,15 +68,15 @@ Number of devices 1 Support is emulated in software No Correctly-rounded divide and sqrt operations No Address bits 64, Little-Endian - Global memory size 26888119911 (25.04GiB) + Global memory size 26892222464 (25.05GiB) Error Correction support No - Max memory allocation 4294959103 (4GiB) + Max memory allocation 4294959104 (4GiB) Unified memory for Host and Device Yes Shared Virtual Memory (SVM) capabilities (core) Coarse-grained buffer sharing Yes - Fine-grained buffer sharing Yes + Fine-grained buffer sharing No Fine-grained system sharing No - Atomics Yes + Atomics No Minimum alignment for any data type 128 bytes Alignment of base address 1024 bits (128 bytes) Preferred alignment for atomics @@ -82,13 +84,13 @@ Number of devices 1 Global 64 bytes Local 64 bytes Max size for global variable 65536 (64KiB) - Preferred total size of global vars 4294959103 (4GiB) + Preferred total size of global vars 4294959104 (4GiB) Global Memory cache type Read/Write Global Memory cache size 1572864 Global Memory cache line 64 bytes Image support Yes Max number of samplers per kernel 16 - Max size for 1D images from buffer 268434943 pixels + Max size for 1D images from buffer 268434944 pixels Max 1D or 2D image array size 2048 images Base address alignment for 2D image buffers 4 bytes Pitch alignment for 2D image buffers 4 bytes @@ -102,7 +104,7 @@ Number of devices 1 Max pipe packet size 1024 Local memory type Local Local memory size 65536 (64KiB) - Max constant buffer size 4294959103 (4GiB) + Max constant buffer size 4294959104 (4GiB) Max number of constant args 8 Max size of kernel argument 1024 Queue properties (on host) @@ -120,114 +122,171 @@ Number of devices 1 Execution capabilities Run OpenCL kernels Yes Run native kernels No + Sub-group independent forward progress Yes + IL version SPIR-V_1.0 SPIR versions 1.2 printf() buffer size 4194304 (4MiB) - Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel + Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel; Motion Estimation accelerator version (Intel) 2 Device Available Yes Compiler Available Yes Linker Available Yes - Device Extensions cl_intel_accelerator cl_intel_advanced_motion_estimation cl_intel_device_side_avc_motion_estimation cl_intel_driver_diagnostics cl_intel_media_block_io cl_intel_motion_estimation cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_required_subgroup_size cl_intel_subgroups cl_intel_subgroups_short cl_intel_va_api_media_sharing cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_fp16 cl_khr_fp64 cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_spir cl_khr_subgroups + Device Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_fp64 cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation NULL platform behavior - clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) No platform - clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...) No platform - clCreateContext(NULL, ...) [default] No platform - clCreateContext(NULL, ...) [other] Success [INTEL] - clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU) No platform - clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU) No platform - clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR) No platform - clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No platform - clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) No platform + clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) Intel(R) OpenCL HD Graphics + clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...) Success [INTEL] + clCreateContext(NULL, ...) [default] Success [INTEL] + clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU) Success (1) + Platform Name Intel(R) OpenCL HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO + clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) Success (1) + Platform Name Intel(R) OpenCL HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO + +ICD loader properties + ICD loader Name OpenCL ICD Loader + ICD loader Vendor OCL Icd free software + ICD loader Version 2.2.8 + ICD loader Profile OpenCL 1.2 + NOTE: your OpenCL library declares to support OpenCL 1.2, + but it seems to support up to OpenCL 2.1 too. ********************************************************************************/ -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0","5 5 16 2 1 1 16 1 0 ", -"EU72_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0","2 4 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","6 3 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0","14 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0","2 4 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0","14 1 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU72_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0","2 10 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0","4 6 8 2 1 1 8 1 0 ", -"EU72_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0","2 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0","14 1 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ1_eltwise1","1 16 32 5 1 16 1 1 0 ", -"EU72_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0","2 5 16 2 1 1 16 1 0 ", -"EU72_k11x11_cn3_g1_s4x4_d1x1_b1_in240x240_p0x0_num1_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","3 7 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0","6 2 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0","2 5 16 2 1 1 16 1 0 ", -"EU72_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0","5 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0","2 10 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0","2 7 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0","14 1 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","2 7 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn2048_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","2 6 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ0_eltwise0","1 16 32 5 1 16 1 1 0 ", -"EU72_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU72_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0","5 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU72_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU72_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M1024_activ0_eltwise0","1 16 32 5 1 16 1 1 0 ", -"EU72_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M512_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU72_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M2048_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise1","1 16 32 5 1 16 1 1 0 ", -"EU72_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU72_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0","2 5 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise1","1 16 32 5 1 16 1 1 0 ", -"EU72_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0","9 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0","14 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","14 1 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0","2 4 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0","14 2 16 2 1 1 16 1 0 ", -"EU72_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0","3 6 16 2 1 1 16 1 0 ", -"EU72_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU72_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M64_activ1_eltwise0","7 3 16 2 1 1 16 1 0 ", -"EU72_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0","7 3 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU72_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0","3 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0","7 4 8 2 1 1 8 1 0 ", -"EU72_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0","14 1 8 2 1 1 8 1 0 ", -"EU72_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0","3 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0","10 2 8 2 1 1 8 1 0 ", -"EU72_k3x3_cn512_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0","2 3 16 2 1 1 16 1 0 ", -"EU72_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M2048_activ1_eltwise1","2 8 32 5 1 8 1 1 0 ", + +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "6 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "2 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ5_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "1 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "1 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "1 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ5_eltwise0_FP32", "12 2 16 2 1 1 16 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ1_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn128_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ5_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "1 3 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "2 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ5_eltwise0_FP32", "2 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "3 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ5_eltwise0_FP32", "2 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ5_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn256_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ5_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn32_g1_s1x1_d1x1_b1_in160x160_p0x0_num1_M64_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn32_g1_s1x1_d1x1_b1_in160x160_p0x0_num1_M64_activ5_eltwise0_FP32", "1 16 32 5 1 16 1 1 0", +"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0_FP32", "7 2 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "8 2 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ5_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "8 2 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "3 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0_FP32", "4 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "3 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M12_activ0_eltwise0_FP32", "6 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M273_activ0_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ5_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M63_activ0_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "8 2 8 2 1 1 8 1 0", +"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU72_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn64_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn64_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ5_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0_FP32", "7 2 8 2 1 1 8 1 0", +"EU72_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU72_k3x3_cn1024_g1024_s1x1_d1x1_b1_in16x16_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn1024_g1024_s1x1_d1x1_b1_in16x16_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn128_g128_s1x1_d1x1_b1_in80x80_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn128_g128_s1x1_d1x1_b1_in80x80_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn128_g128_s2x2_d1x1_b1_in80x80_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn128_g128_s2x2_d1x1_b1_in80x80_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU72_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU72_k3x3_cn128_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M256_activ5_eltwise0_FP32", "3 1 8 2 1 1 8 1 0", +"EU72_k3x3_cn128_g1_s2x2_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP32", "1 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU72_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn256_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ5_eltwise0_FP32", "3 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn256_g1_s2x2_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn256_g256_s1x1_d1x1_b1_in48x48_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn256_g256_s1x1_d1x1_b1_in48x48_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn256_g256_s2x2_d1x1_b1_in48x48_p0x0_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn256_g256_s2x2_d1x1_b1_in48x48_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn32_g32_s1x1_d1x1_b1_in160x160_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn32_g32_s1x1_d1x1_b1_in160x160_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn3_g1_s2x2_d1x1_b1_in256x256_p0x0_num1_M32_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k3x3_cn3_g1_s2x2_d1x1_b1_in256x256_p1x1_num1_M32_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU72_k3x3_cn512_g512_s1x1_d1x1_b1_in32x32_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn512_g512_s1x1_d1x1_b1_in32x32_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn512_g512_s2x2_d1x1_b1_in32x32_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn512_g512_s2x2_d1x1_b1_in32x32_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU72_k3x3_cn64_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M128_activ5_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU72_k3x3_cn64_g1_s2x2_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0_FP32", "1 1 16 2 1 1 16 1 0", +"EU72_k3x3_cn64_g64_s2x2_d1x1_b1_in160x160_p0x0_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn64_g64_s2x2_d1x1_b1_in160x160_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU72_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0_FP32", "7 2 16 2 1 1 16 1 0", +"EU72_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP32", "7 2 16 2 1 1 16 1 0", +"EU72_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0_FP32", "4 2 8 2 1 1 8 1 0", +"EU72_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0_FP32", "6 1 16 2 1 1 16 1 0", +"EU72_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU72_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU72_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP32", "6 1 16 2 1 1 16 1 0", +"EU72_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0_FP32", "7 2 16 2 1 1 16 1 0", +"EU72_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP32", "4 1 16 2 1 1 16 1 0", +"EU72_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0_FP32", "4 3 16 2 1 1 16 1 0", // Below is the information for OpenCL based on which these configurations tuned /******************************************************************************* Number of platforms 1 - Platform Name Intel(R) OpenCL + Platform Name Intel(R) OpenCL HD Graphics Platform Vendor Intel(R) Corporation - Platform Version OpenCL 2.0 + Platform Version OpenCL 2.1 Platform Profile FULL_PROFILE - Platform Extensions cl_intel_accelerator cl_intel_advanced_motion_estimation cl_intel_device_side_avc_motion_estimation cl_intel_driver_diagnostics cl_intel_media_block_io cl_intel_motion_estimation cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_required_subgroup_size cl_intel_subgroups cl_intel_subgroups_short cl_intel_va_api_media_sharing cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_fp16 cl_khr_fp64 cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_spir cl_khr_subgroups + Platform Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_fp64 cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation + Platform Host timer resolution 1ns Platform Extensions function suffix INTEL - Platform Name Intel(R) OpenCL + Platform Name Intel(R) OpenCL HD Graphics Number of devices 1 - Device Name Intel(R) HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO Device Vendor Intel(R) Corporation Device Vendor ID 0x8086 - Device Version OpenCL 2.0 - Driver Version r4.1.61547 + Device Version OpenCL 2.1 NEO + Driver Version 18.21.10858 Device OpenCL C Version OpenCL C 2.0 Device Type GPU Device Profile FULL_PROFILE @@ -235,11 +294,12 @@ Number of devices 1 Max clock frequency 950MHz Device Partition (core) Max number of sub-devices 0 - Supported partition types by (0x7F2200000000) + Supported partition types None Max work item dimensions 3 Max work item sizes 256x256x256 Max work group size 256 Preferred work group size multiple 32 + Max sub-groups per work group 32 Preferred / native vector sizes char 16 / 16 short 8 / 8 @@ -276,9 +336,9 @@ Number of devices 1 Support is emulated in software No Correctly-rounded divide and sqrt operations No Address bits 64, Little-Endian - Global memory size 13361912218 (12.44GiB) + Global memory size 13364170752 (12.45GiB) Error Correction support No - Max memory allocation 4294959103 (4GiB) + Max memory allocation 4294959104 (4GiB) Unified memory for Host and Device Yes Shared Virtual Memory (SVM) capabilities (core) Coarse-grained buffer sharing Yes @@ -292,13 +352,13 @@ Number of devices 1 Global 64 bytes Local 64 bytes Max size for global variable 65536 (64KiB) - Preferred total size of global vars 4294959103 (4GiB) + Preferred total size of global vars 4294959104 (4GiB) Global Memory cache type Read/Write Global Memory cache size 1048576 Global Memory cache line 64 bytes Image support Yes Max number of samplers per kernel 16 - Max size for 1D images from buffer 268434943 pixels + Max size for 1D images from buffer 268434944 pixels Max 1D or 2D image array size 2048 images Base address alignment for 2D image buffers 4 bytes Pitch alignment for 2D image buffers 4 bytes @@ -312,7 +372,7 @@ Number of devices 1 Max pipe packet size 1024 Local memory type Local Local memory size 65536 (64KiB) - Max constant buffer size 4294959103 (4GiB) + Max constant buffer size 4294959104 (4GiB) Max number of constant args 8 Max size of kernel argument 1024 Queue properties (on host) @@ -330,14 +390,16 @@ Number of devices 1 Execution capabilities Run OpenCL kernels Yes Run native kernels No + Sub-group independent forward progress Yes + IL version SPIR-V_1.0 SPIR versions 1.2 printf() buffer size 4194304 (4MiB) - Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel + Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel; Motion Estimation accelerator version (Intel) 2 Device Available Yes Compiler Available Yes Linker Available Yes - Device Extensions cl_intel_accelerator cl_intel_advanced_motion_estimation cl_intel_device_side_avc_motion_estimation cl_intel_driver_diagnostics cl_intel_media_block_io cl_intel_motion_estimation cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_required_subgroup_size cl_intel_subgroups cl_intel_subgroups_short cl_intel_va_api_media_sharing cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_fp16 cl_khr_fp64 cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_spir cl_khr_subgroups + Device Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_fp64 cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation NULL platform behavior clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) No platform @@ -350,106 +412,155 @@ NULL platform behavior clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No platform clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) No platform ********************************************************************************/ -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","13 1 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise1","1 8 32 5 1 8 1 1 0 ", -"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU48_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0","2 5 8 2 1 1 8 1 0 ", -"EU48_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M1024_activ0_eltwise0","1 16 32 5 1 16 1 1 0 ", -"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0","7 4 8 2 1 1 8 1 0 ", -"EU48_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M64_activ1_eltwise0","7 3 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise1","1 16 32 5 1 16 1 1 0 ", -"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k3x3_cn512_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0","14 2 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0","14 2 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M512_activ0_eltwise0","1 16 32 5 1 16 1 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU48_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0","2 10 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU48_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M128_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU48_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0","4 4 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU48_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ1_eltwise1","1 16 32 5 1 16 1 1 0 ", -"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn2048_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0","3 7 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU48_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0","4 3 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU48_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0","2 4 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0","6 2 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0","9 3 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0","7 4 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU48_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0","7 3 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0","5 2 8 2 1 1 8 1 0 ", -"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0","3 2 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU48_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M2048_activ1_eltwise1","2 8 32 5 1 8 1 1 0 ", -"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0","2 10 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0","2 3 16 2 1 1 16 1 0 ", -"EU48_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0","3 5 16 2 1 1 16 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","7 2 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M2048_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","7 3 8 2 1 1 8 1 0 ", -"EU48_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU48_k11x11_cn3_g1_s4x4_d1x1_b1_in240x240_p0x0_num1_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU48_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0","7 3 16 2 1 1 16 1 0 ", -"EU48_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0","3 7 8 2 1 1 8 1 0 ", -"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0","7 4 8 2 1 1 8 1 0 ", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ5_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ5_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "1 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ1_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn128_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "3 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "3 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ5_eltwise0_FP32", "3 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "3 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "2 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ5_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in48x48_p0x0_num1_M256_activ5_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn32_g1_s1x1_d1x1_b1_in160x160_p0x0_num1_M64_activ1_eltwise0_FP32", "1 16 32 5 1 16 1 1 0", +"EU48_k1x1_cn32_g1_s1x1_d1x1_b1_in160x160_p0x0_num1_M64_activ5_eltwise0_FP32", "1 16 32 5 1 16 1 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ5_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M126_activ0_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ5_eltwise0_FP32", "5 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ0_eltwise0_FP32", "4 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "8 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M546_activ0_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M12_activ0_eltwise0_FP32", "9 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M273_activ0_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M63_activ0_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in80x80_p0x0_num1_M128_activ5_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "7 2 8 2 1 1 8 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "4 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0_FP32", "4 1 8 2 1 1 8 1 0", +"EU48_k3x3_cn1024_g1024_s1x1_d1x1_b1_in16x16_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn1024_g1024_s1x1_d1x1_b1_in16x16_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn128_g128_s1x1_d1x1_b1_in80x80_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn128_g128_s1x1_d1x1_b1_in80x80_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn128_g128_s2x2_d1x1_b1_in80x80_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn128_g128_s2x2_d1x1_b1_in80x80_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU48_k3x3_cn128_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M256_activ5_eltwise0_FP32", "2 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn128_g1_s2x2_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP32", "3 1 8 2 1 1 8 1 0", +"EU48_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn256_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ5_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn256_g1_s2x2_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn256_g256_s1x1_d1x1_b1_in48x48_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn256_g256_s1x1_d1x1_b1_in48x48_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn256_g256_s2x2_d1x1_b1_in48x48_p0x0_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn256_g256_s2x2_d1x1_b1_in48x48_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn32_g32_s1x1_d1x1_b1_in160x160_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn32_g32_s1x1_d1x1_b1_in160x160_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn3_g1_s2x2_d1x1_b1_in256x256_p0x0_num1_M32_activ5_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k3x3_cn3_g1_s2x2_d1x1_b1_in256x256_p1x1_num1_M32_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k3x3_cn512_g512_s1x1_d1x1_b1_in32x32_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn512_g512_s1x1_d1x1_b1_in32x32_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn512_g512_s2x2_d1x1_b1_in32x32_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn512_g512_s2x2_d1x1_b1_in32x32_p1x1_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU48_k3x3_cn64_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M128_activ5_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU48_k3x3_cn64_g1_s2x2_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0_FP32", "1 1 8 2 1 1 8 1 0", +"EU48_k3x3_cn64_g64_s2x2_d1x1_b1_in160x160_p0x0_num1_M1_activ5_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn64_g64_s2x2_d1x1_b1_in160x160_p1x1_num1_M1_activ1_eltwise0_FP32", "1 1 1 6 1 1 1 0 0", +"EU48_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU48_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0_FP32", "4 2 8 2 1 1 8 1 0", +"EU48_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0_FP32", "4 3 8 2 1 1 8 1 0", +"EU48_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP32", "4 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP32", "4 2 8 2 1 1 8 1 0", +"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0_FP32", "4 7 8 2 1 1 8 1 0", +"EU48_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP32", "4 1 16 2 1 1 16 1 0", +"EU48_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0_FP32", "5 4 16 2 1 1 16 1 0", +"EU48_k11x11_cn3_g1_s4x4_d1x1_b1_in240x240_p0x0_num1_M96_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU48_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP32", "13 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0_FP32", "3 9 8 2 1 1 8 1 0", // Below is the information for OpenCL based on which these configurations tuned /******************************************************************************* Number of platforms 1 - Platform Name Intel(R) OpenCL + Platform Name Intel(R) OpenCL HD Graphics Platform Vendor Intel(R) Corporation - Platform Version OpenCL 2.0 + Platform Version OpenCL 2.1 Platform Profile FULL_PROFILE - Platform Extensions cl_intel_accelerator cl_intel_advanced_motion_estimation cl_intel_device_side_avc_motion_estimation cl_intel_driver_diagnostics cl_intel_media_block_io cl_intel_motion_estimation cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_required_subgroup_size cl_intel_subgroups cl_intel_subgroups_short cl_intel_va_api_media_sharing cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_fp16 cl_khr_fp64 cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_spir cl_khr_subgroups + Platform Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_fp64 cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation cl_intel_va_api_media_sharing + Platform Host timer resolution 1ns Platform Extensions function suffix INTEL - Platform Name Intel(R) OpenCL + Platform Name Intel(R) OpenCL HD Graphics Number of devices 1 - Device Name Intel(R) HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO Device Vendor Intel(R) Corporation Device Vendor ID 0x8086 - Device Version OpenCL 2.0 - Driver Version 16.5.59288 + Device Version OpenCL 2.1 NEO + Driver Version 18.23.10915 Device OpenCL C Version OpenCL C 2.0 Device Type GPU Device Profile FULL_PROFILE Max compute units 24 - Max clock frequency 1050MHz + Max clock frequency 1150MHz Device Partition (core) Max number of sub-devices 0 - Supported partition types by (0x7FC300000000) + Supported partition types None Max work item dimensions 3 Max work item sizes 256x256x256 Max work group size 256 Preferred work group size multiple 32 + Max sub-groups per work group 32 Preferred / native vector sizes char 16 / 16 short 8 / 8 @@ -486,9 +597,9 @@ Number of devices 1 Support is emulated in software No Correctly-rounded divide and sqrt operations No Address bits 64, Little-Endian - Global memory size 6588809216 (6.136GiB) + Global memory size 6575288320 (6.124GiB) Error Correction support No - Max memory allocation 3294404608 (3.068GiB) + Max memory allocation 3287644160 (3.062GiB) Unified memory for Host and Device Yes Shared Virtual Memory (SVM) capabilities (core) Coarse-grained buffer sharing Yes @@ -502,13 +613,13 @@ Number of devices 1 Global 64 bytes Local 64 bytes Max size for global variable 65536 (64KiB) - Preferred total size of global vars 3294404608 (3.068GiB) + Preferred total size of global vars 3287644160 (3.062GiB) Global Memory cache type Read/Write Global Memory cache size 524288 Global Memory cache line 64 bytes Image support Yes Max number of samplers per kernel 16 - Max size for 1D images from buffer 205900288 pixels + Max size for 1D images from buffer 205477760 pixels Max 1D or 2D image array size 2048 images Base address alignment for 2D image buffers 4 bytes Pitch alignment for 2D image buffers 4 bytes @@ -522,7 +633,7 @@ Number of devices 1 Max pipe packet size 1024 Local memory type Local Local memory size 65536 (64KiB) - Max constant buffer size 3294404608 (3.068GiB) + Max constant buffer size 3287644160 (3.062GiB) Max number of constant args 8 Max size of kernel argument 1024 Queue properties (on host) @@ -540,14 +651,244 @@ Number of devices 1 Execution capabilities Run OpenCL kernels Yes Run native kernels No + Sub-group independent forward progress Yes + IL version SPIR-V_1.0 SPIR versions 1.2 printf() buffer size 4194304 (4MiB) - Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel + Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel; Motion Estimation accelerator version (Intel) 2 Device Available Yes Compiler Available Yes Linker Available Yes - Device Extensions cl_intel_accelerator cl_intel_advanced_motion_estimation cl_intel_device_side_avc_motion_estimation cl_intel_driver_diagnostics cl_intel_media_block_io cl_intel_motion_estimation cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_required_subgroup_size cl_intel_subgroups cl_intel_subgroups_short cl_intel_va_api_media_sharing cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_fp16 cl_khr_fp64 cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_spir cl_khr_subgroups + Device Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_fp64 cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation cl_intel_va_api_media_sharing + +NULL platform behavior + clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) Intel(R) OpenCL HD Graphics + clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...) Success [INTEL] + clCreateContext(NULL, ...) [default] Success [INTEL] + clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU) Success (1) + Platform Name Intel(R) OpenCL HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO + clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) Success (1) + Platform Name Intel(R) OpenCL HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO + +ICD loader properties + ICD loader Name OpenCL ICD Loader + ICD loader Vendor OCL Icd free software + ICD loader Version 2.2.8 + ICD loader Profile OpenCL 1.2 + NOTE: your OpenCL library declares to support OpenCL 1.2, + but it seems to support up to OpenCL 2.1 too. +********************************************************************************/ +"EU24_k11x11_cn3_g1_s4x4_d1x1_b1_in240x240_p0x0_num1_M96_activ1_eltwise0_FP32", "2 5 16 2 1 1 16 1 0", +"EU24_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M2048_activ0_eltwise0_FP32", "7 4 16 2 1 1 16 1 0", +"EU24_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0_FP32", "7 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn128_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise1_FP32", "2 8 32 5 1 8 1 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP32", "10 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn2048_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise1_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP32", "10 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M128_activ1_eltwise0_FP32", "1 8 32 5 1 8 1 1 0", +"EU24_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M512_activ0_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "8 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M2048_activ1_eltwise1_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M1024_activ0_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU24_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M256_activ1_eltwise0_FP32", "7 3 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ0_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ1_eltwise1_FP32", "1 16 32 5 1 16 1 1 0", +"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP32", "2 8 32 5 1 8 1 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP32", "7 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP32", "7 1 8 2 1 1 8 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0_FP32", "4 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP32", "13 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0_FP32", "13 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0_FP32", "13 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn512_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M64_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0_FP32", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP32", "14 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0_FP32", "4 3 8 2 1 1 8 1 0", +"EU24_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP32", "5 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP32", "4 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP32", "7 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0_FP32", "7 2 16 2 1 1 16 1 0", +"EU24_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP32", "3 7 8 2 1 1 8 1 0", +"EU24_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0_FP32", "9 3 16 2 1 1 16 1 0", +"EU24_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0_FP32", "4 4 16 2 1 1 16 1 0", +}; + +const char *default_kernel_config_intel_fp16[] = { +// Below is the information for OpenCL based on which these configurations tuned +/******************************************************************************* +Number of platforms 1 + Platform Name Intel(R) OpenCL HD Graphics + Platform Vendor Intel(R) Corporation + Platform Version OpenCL 2.1 + Platform Profile FULL_PROFILE + Platform Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_fp64 cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation + Platform Host timer resolution 1ns + Platform Extensions function suffix INTEL + + Platform Name Intel(R) OpenCL HD Graphics +Number of devices 1 + Device Name Intel(R) Gen9 HD Graphics NEO + Device Vendor Intel(R) Corporation + Device Vendor ID 0x8086 + Device Version OpenCL 2.1 NEO + Driver Version 18.21.10858 + Device OpenCL C Version OpenCL C 2.0 + Device Type GPU + Device Profile FULL_PROFILE + Max compute units 48 + Max clock frequency 950MHz + Device Partition (core) + Max number of sub-devices 0 + Supported partition types None + Max work item dimensions 3 + Max work item sizes 256x256x256 + Max work group size 256 + Preferred work group size multiple 32 + Max sub-groups per work group 32 + Preferred / native vector sizes + char 16 / 16 + short 8 / 8 + int 4 / 4 + long 1 / 1 + half 8 / 8 (cl_khr_fp16) + float 1 / 1 + double 1 / 1 (cl_khr_fp64) + Half-precision Floating-point support (cl_khr_fp16) + Denormals Yes + Infinity and NANs Yes + Round to nearest Yes + Round to zero Yes + Round to infinity Yes + IEEE754-2008 fused multiply-add Yes + Support is emulated in software No + Correctly-rounded divide and sqrt operations No + Single-precision Floating-point support (core) + Denormals Yes + Infinity and NANs Yes + Round to nearest Yes + Round to zero Yes + Round to infinity Yes + IEEE754-2008 fused multiply-add Yes + Support is emulated in software No + Correctly-rounded divide and sqrt operations Yes + Double-precision Floating-point support (cl_khr_fp64) + Denormals Yes + Infinity and NANs Yes + Round to nearest Yes + Round to zero Yes + Round to infinity Yes + IEEE754-2008 fused multiply-add Yes + Support is emulated in software No + Correctly-rounded divide and sqrt operations No + Address bits 64, Little-Endian + Global memory size 13364170752 (12.45GiB) + Error Correction support No + Max memory allocation 4294959104 (4GiB) + Unified memory for Host and Device Yes + Shared Virtual Memory (SVM) capabilities (core) + Coarse-grained buffer sharing Yes + Fine-grained buffer sharing No + Fine-grained system sharing No + Atomics No + Minimum alignment for any data type 128 bytes + Alignment of base address 1024 bits (128 bytes) + Preferred alignment for atomics + SVM 64 bytes + Global 64 bytes + Local 64 bytes + Max size for global variable 65536 (64KiB) + Preferred total size of global vars 4294959104 (4GiB) + Global Memory cache type Read/Write + Global Memory cache size 1048576 + Global Memory cache line 64 bytes + Image support Yes + Max number of samplers per kernel 16 + Max size for 1D images from buffer 268434944 pixels + Max 1D or 2D image array size 2048 images + Base address alignment for 2D image buffers 4 bytes + Pitch alignment for 2D image buffers 4 bytes + Max 2D image size 16384x16384 pixels + Max 3D image size 16384x16384x2048 pixels + Max number of read image args 128 + Max number of write image args 128 + Max number of read/write image args 128 + Max number of pipe args 16 + Max active pipe reservations 1 + Max pipe packet size 1024 + Local memory type Local + Local memory size 65536 (64KiB) + Max constant buffer size 4294959104 (4GiB) + Max number of constant args 8 + Max size of kernel argument 1024 + Queue properties (on host) + Out-of-order execution Yes + Profiling Yes + Queue properties (on device) + Out-of-order execution Yes + Profiling Yes + Preferred size 131072 (128KiB) + Max size 67108864 (64MiB) + Max queues on device 1 + Max events on device 1024 + Prefer user sync for interop Yes + Profiling timer resolution 83ns + Execution capabilities + Run OpenCL kernels Yes + Run native kernels No + Sub-group independent forward progress Yes + IL version SPIR-V_1.0 + SPIR versions 1.2 + printf() buffer size 4194304 (4MiB) + Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel; + Motion Estimation accelerator version (Intel) 2 + Device Available Yes + Compiler Available Yes + Linker Available Yes + Device Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_khr_fp64 cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation NULL platform behavior clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) No platform @@ -560,153 +901,282 @@ NULL platform behavior clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No platform clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) No platform ********************************************************************************/ -"EU24_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num2_M384_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M256_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num2_M128_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M112_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M144_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M192_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x5_cn32_g1_s1x1_d1x1_b1_in64x64_p0x2_num1_M32_activ2_eltwise0","8 3 16 2 1 1 16 1 0 ", -"EU24_k2x2_cn16_g1_s2x2_d1x1_b1_in256x256_p0x0_num1_M16_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num2_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn128_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M16_activ2_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn3_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M5_activ0_eltwise0","2 4 8 2 1 1 8 1 0 ", -"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num2_M96_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn32_g1_s1x1_d2x2_b1_in64x64_p2x2_num1_M32_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn32_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M32_activ2_eltwise0","10 2 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0","12 2 8 2 1 1 8 1 0 ", -"EU24_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M192_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn4_g1_s1x1_d1x1_b1_in256x256_p1x1_num1_M4_activ2_eltwise0","2 8 16 2 1 1 16 1 0 ", -"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k2x2_cn64_g1_s2x2_d1x1_b1_in128x128_p0x0_num1_M32_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise1","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn2048_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0","4 6 8 2 1 1 8 1 0 ", -"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num2_M256_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn32_g1_s1x1_d16x16_b1_in64x64_p16x16_num1_M32_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M384_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn4_g1_s1x1_d1x1_b1_in256x256_p0x0_num1_M16_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","8 2 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M16_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in128x128_p0x0_num1_M16_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M32_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k5x4_cn6_g3_s3x2_d1x1_b1_in128x80_p1x0_num2_M4_activ0_eltwise0","1 1 1 4 1 1 1 0 1 ", -"EU24_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num2_M64_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn16_g1_s1x1_d1x1_b1_in128x128_p1x1_num1_M16_activ2_eltwise0","2 4 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num2_M288_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0","2 6 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in128x128_p0x0_num1_M4_activ2_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num2_M64_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU24_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn3_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M4_activ0_eltwise0","4 4 8 2 1 1 8 1 0 ", -"EU24_k11x7_cn3_g1_s3x4_d1x1_b1_in64x64_p3x2_num1_M64_activ0_eltwise0","4 1 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in128x128_p0x0_num1_M16_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0","12 2 8 2 1 1 8 1 0 ", -"EU24_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M32_activ1_eltwise0","4 7 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num2_M48_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn16_g1_s1x1_d1x1_b1_in128x128_p0x0_num1_M64_activ3_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num2_M192_activ1_eltwise0","14 2 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0","12 2 8 2 1 1 8 1 0 ", -"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0","14 2 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M16_activ1_eltwise0","8 3 8 2 1 1 8 1 0 ", -"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num2_M128_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M64_activ1_eltwise0","2 8 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn128_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise1","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M48_activ1_eltwise0","4 6 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","4 6 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M32_activ1_eltwise0","4 6 8 2 1 1 8 1 0 ", -"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num2_M192_activ1_eltwise0","14 2 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn32_g1_s1x1_d8x8_b1_in64x64_p8x8_num1_M32_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M24_activ1_eltwise0","12 2 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0","4 6 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M1024_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M32_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn16_g1_s1x1_d1x1_b1_in256x256_p0x0_num1_M4_activ2_eltwise0","12 2 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn128_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M32_activ2_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn32_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M128_activ3_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn16_g1_s1x1_d1x1_b1_in128x128_p0x0_num1_M64_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn512_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num2_M208_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k11x11_cn3_g1_s4x4_d1x1_b1_in224x224_p0x0_num1_M96_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0","4 3 16 2 1 1 16 1 0 ", -"EU24_k5x1_cn32_g1_s1x1_d1x1_b0_in64x64_p2x0_num1_M32_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k4x4_cn3_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M2_activ0_eltwise0","1 3 8 2 1 1 8 1 0 ", -"EU24_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num2_M224_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M2048_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn3_g1_s2x2_d1x1_b1_in256x256_p1x1_num1_M13_activ0_eltwise0","1 1 1 4 1 1 1 0 1 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num2_M64_activ1_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0","12 2 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn128_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ0_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num2_M128_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num2_M256_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ1_eltwise1","1 16 32 5 1 16 1 1 0 ", -"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num2_M32_activ1_eltwise0","4 2 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M64_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0","4 3 8 2 1 1 8 1 0 ", -"EU24_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M512_activ0_eltwise0","2 8 32 5 1 8 1 1 0 ", -"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0","4 4 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num2_M320_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", -"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num2_M32_activ1_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k3x3_cn32_g1_s1x1_d4x4_b1_in64x64_p4x4_num1_M32_activ2_eltwise0","1 8 32 5 1 8 1 1 0 ", -"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M2048_activ1_eltwise1","4 7 16 2 1 1 16 1 0 ", -"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0","2 7 16 2 1 1 16 1 0 ", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0_FP16", "11 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0_FP16", "8 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0_FP16", "7 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP16", "8 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP16", "6 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP16", "1 16 32 5 1 16 1 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP16", "4 1 8 2 1 1 8 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0_FP16", "7 1 8 2 1 1 8 1 0", +"EU48_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU48_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU48_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU48_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0_FP16", "5 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP16", "5 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP16", "8 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0_FP16", "10 2 16 2 1 1 16 1 0", +"EU48_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP16", "5 1 16 2 1 1 16 1 0", +"EU48_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0_FP16", "5 6 16 2 1 1 16 1 0", +"EU48_k11x11_cn3_g1_s4x4_d1x1_b1_in240x240_p0x0_num1_M96_activ1_eltwise0_FP16", "2 8 16 2 1 1 16 1 0", +"EU48_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP16", "13 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0_FP16", "13 1 16 2 1 1 16 1 0", +"EU48_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0_FP16", "13 1 16 2 1 1 16 1 0", +"EU48_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0_FP16", "9 2 16 2 1 1 16 1 0", +// Below is the information for OpenCL based on which these configurations tuned +/******************************************************************************* +Number of platforms 1 + Platform Name Intel(R) OpenCL HD Graphics + Platform Vendor Intel(R) Corporation + Platform Version OpenCL 2.1 + Platform Profile FULL_PROFILE + Platform Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_fp64 cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation cl_intel_va_api_media_sharing + Platform Host timer resolution 1ns + Platform Extensions function suffix INTEL + + Platform Name Intel(R) OpenCL HD Graphics +Number of devices 1 + Device Name Intel(R) Gen9 HD Graphics NEO + Device Vendor Intel(R) Corporation + Device Vendor ID 0x8086 + Device Version OpenCL 2.1 NEO + Driver Version 18.23.10915 + Device OpenCL C Version OpenCL C 2.0 + Device Type GPU + Device Profile FULL_PROFILE + Max compute units 24 + Max clock frequency 1150MHz + Device Partition (core) + Max number of sub-devices 0 + Supported partition types None + Max work item dimensions 3 + Max work item sizes 256x256x256 + Max work group size 256 + Preferred work group size multiple 32 + Max sub-groups per work group 32 + Preferred / native vector sizes + char 16 / 16 + short 8 / 8 + int 4 / 4 + long 1 / 1 + half 8 / 8 (cl_khr_fp16) + float 1 / 1 + double 1 / 1 (cl_khr_fp64) + Half-precision Floating-point support (cl_khr_fp16) + Denormals Yes + Infinity and NANs Yes + Round to nearest Yes + Round to zero Yes + Round to infinity Yes + IEEE754-2008 fused multiply-add Yes + Support is emulated in software No + Correctly-rounded divide and sqrt operations No + Single-precision Floating-point support (core) + Denormals Yes + Infinity and NANs Yes + Round to nearest Yes + Round to zero Yes + Round to infinity Yes + IEEE754-2008 fused multiply-add Yes + Support is emulated in software No + Correctly-rounded divide and sqrt operations Yes + Double-precision Floating-point support (cl_khr_fp64) + Denormals Yes + Infinity and NANs Yes + Round to nearest Yes + Round to zero Yes + Round to infinity Yes + IEEE754-2008 fused multiply-add Yes + Support is emulated in software No + Correctly-rounded divide and sqrt operations No + Address bits 64, Little-Endian + Global memory size 6575288320 (6.124GiB) + Error Correction support No + Max memory allocation 3287644160 (3.062GiB) + Unified memory for Host and Device Yes + Shared Virtual Memory (SVM) capabilities (core) + Coarse-grained buffer sharing Yes + Fine-grained buffer sharing No + Fine-grained system sharing No + Atomics No + Minimum alignment for any data type 128 bytes + Alignment of base address 1024 bits (128 bytes) + Preferred alignment for atomics + SVM 64 bytes + Global 64 bytes + Local 64 bytes + Max size for global variable 65536 (64KiB) + Preferred total size of global vars 3287644160 (3.062GiB) + Global Memory cache type Read/Write + Global Memory cache size 524288 + Global Memory cache line 64 bytes + Image support Yes + Max number of samplers per kernel 16 + Max size for 1D images from buffer 205477760 pixels + Max 1D or 2D image array size 2048 images + Base address alignment for 2D image buffers 4 bytes + Pitch alignment for 2D image buffers 4 bytes + Max 2D image size 16384x16384 pixels + Max 3D image size 16384x16384x2048 pixels + Max number of read image args 128 + Max number of write image args 128 + Max number of read/write image args 128 + Max number of pipe args 16 + Max active pipe reservations 1 + Max pipe packet size 1024 + Local memory type Local + Local memory size 65536 (64KiB) + Max constant buffer size 3287644160 (3.062GiB) + Max number of constant args 8 + Max size of kernel argument 1024 + Queue properties (on host) + Out-of-order execution Yes + Profiling Yes + Queue properties (on device) + Out-of-order execution Yes + Profiling Yes + Preferred size 131072 (128KiB) + Max size 67108864 (64MiB) + Max queues on device 1 + Max events on device 1024 + Prefer user sync for interop Yes + Profiling timer resolution 83ns + Execution capabilities + Run OpenCL kernels Yes + Run native kernels No + Sub-group independent forward progress Yes + IL version SPIR-V_1.0 + SPIR versions 1.2 + printf() buffer size 4194304 (4MiB) + Built-in kernels block_motion_estimate_intel;block_advanced_motion_estimate_check_intel;block_advanced_motion_estimate_bidirectional_check_intel; + Motion Estimation accelerator version (Intel) 2 + Device Available Yes + Compiler Available Yes + Linker Available Yes + Device Extensions cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_fp16 cl_khr_depth_images cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_icd cl_khr_image2d_from_buffer cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_intel_subgroups cl_intel_required_subgroup_size cl_intel_subgroups_short cl_khr_spir cl_intel_accelerator cl_intel_media_block_io cl_intel_driver_diagnostics cl_intel_device_side_avc_motion_estimation cl_khr_priority_hints cl_khr_throttle_hints cl_khr_create_command_queue cl_khr_fp64 cl_khr_subgroups cl_khr_il_program cl_khr_mipmap_image cl_khr_mipmap_image_writes cl_intel_planar_yuv cl_intel_packed_yuv cl_intel_motion_estimation cl_intel_advanced_motion_estimation cl_intel_va_api_media_sharing + +NULL platform behavior + clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...) Intel(R) OpenCL HD Graphics + clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...) Success [INTEL] + clCreateContext(NULL, ...) [default] Success [INTEL] + clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU) Success (1) + Platform Name Intel(R) OpenCL HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO + clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM) No devices found in platform + clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL) Success (1) + Platform Name Intel(R) OpenCL HD Graphics + Device Name Intel(R) Gen9 HD Graphics NEO + +ICD loader properties + ICD loader Name OpenCL ICD Loader + ICD loader Vendor OCL Icd free software + ICD loader Version 2.2.8 + ICD loader Profile OpenCL 1.2 + NOTE: your OpenCL library declares to support OpenCL 1.2, + but it seems to support up to OpenCL 2.1 too. +********************************************************************************/ +"EU24_k11x11_cn3_g1_s4x4_d1x1_b1_in240x240_p0x0_num1_M96_activ1_eltwise0_FP16", "2 7 16 2 1 1 16 1 0", +"EU24_k1x1_cn1024_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M2048_activ0_eltwise0_FP16", "7 4 16 2 1 1 16 1 0", +"EU24_k1x1_cn1024_g1_s2x2_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn128_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M512_activ1_eltwise1_FP16", "1 16 32 5 1 16 1 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M16_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP16", "10 3 16 2 1 1 16 1 0", +"EU24_k1x1_cn192_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M96_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn2048_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M512_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M1024_activ1_eltwise1_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M32_activ1_eltwise0_FP16", "10 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M64_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M128_activ1_eltwise0_FP16", "8 4 16 2 1 1 16 1 0", +"EU24_k1x1_cn256_g1_s2x2_d1x1_b1_in64x64_p0x0_num1_M512_activ0_eltwise0_FP16", "1 16 32 5 1 16 1 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M16_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn480_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M96_activ1_eltwise0_FP16", "7 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M112_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M144_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M2048_activ1_eltwise1_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M24_activ1_eltwise0_FP16", "10 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP16", "9 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M64_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s1x1_d1x1_b1_in32x32_p0x0_num1_M128_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M1024_activ0_eltwise0_FP16", "8 3 16 2 1 1 16 1 0", +"EU24_k1x1_cn512_g1_s2x2_d1x1_b1_in32x32_p0x0_num1_M256_activ1_eltwise0_FP16", "7 3 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k1x1_cn528_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP16", "8 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ0_eltwise0_FP16", "1 16 32 5 1 16 1 1 0", +"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M256_activ1_eltwise1_FP16", "1 16 32 5 1 16 1 1 0", +"EU24_k1x1_cn64_g1_s1x1_d1x1_b1_in64x64_p0x0_num1_M64_activ1_eltwise0_FP16", "1 16 32 5 1 16 1 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M128_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M160_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M192_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M256_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M32_activ1_eltwise0_FP16", "6 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M384_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k1x1_cn832_g1_s1x1_d1x1_b1_in16x16_p0x0_num1_M48_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn112_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M224_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP16", "10 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn128_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M192_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn144_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M288_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn160_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M320_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn192_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M256_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn256_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M384_activ1_eltwise0_FP16", "13 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M128_activ1_eltwise0_FP16", "13 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn384_g2_s1x1_d1x1_b1_in16x16_p1x1_num1_M192_activ1_eltwise0_FP16", "13 1 16 2 1 1 16 1 0", +"EU24_k3x3_cn512_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M512_activ1_eltwise0_FP16", "7 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M192_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn64_g1_s1x1_d1x1_b1_in64x64_p1x1_num1_M64_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in16x16_p1x1_num1_M208_activ1_eltwise0_FP16", "14 2 16 2 1 1 16 1 0", +"EU24_k3x3_cn96_g1_s1x1_d1x1_b1_in32x32_p1x1_num1_M128_activ1_eltwise0_FP16", "14 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M48_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn16_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M32_activ1_eltwise0_FP16", "7 2 16 2 1 1 16 1 0", +"EU24_k5x5_cn24_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP16", "7 2 16 2 1 1 16 1 0", +"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M64_activ1_eltwise0_FP16", "7 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn32_g1_s1x1_d1x1_b1_in32x32_p2x2_num1_M96_activ1_eltwise0_FP16", "7 2 16 2 1 1 16 1 0", +"EU24_k5x5_cn48_g1_s1x1_d1x1_b1_in16x16_p2x2_num1_M128_activ1_eltwise0_FP16", "4 1 16 2 1 1 16 1 0", +"EU24_k5x5_cn96_g2_s1x1_d1x1_b1_in32x32_p2x2_num1_M128_activ1_eltwise0_FP16", "7 3 16 2 1 1 16 1 0", +"EU24_k7x7_cn3_g1_s2x2_d1x1_b1_in224x224_p3x3_num1_M64_activ1_eltwise0_FP16", "4 7 16 2 1 1 16 1 0", }; #endif diff --git a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp index e0ce77e27a..e0ca5ca98c 100644 --- a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp +++ b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp @@ -306,6 +306,7 @@ class OCL4DNNConvSpatial std::string kernel_name_; std::string cache_path_; bool use_cache_path_; // true if cache_path_ directory exists + bool run_auto_tuning_; bool force_auto_tuning_; int32_t kernel_index_; std::vector< cv::Ptr > kernelQueue; @@ -351,6 +352,7 @@ struct OCL4DNNPoolConfig pool_method(LIBDNN_POOLING_METHOD_MAX), global_pooling(false), avePoolPaddedArea(true), + computeMaxIdx(true), use_half(false) {} MatShape in_shape; @@ -364,6 +366,7 @@ struct OCL4DNNPoolConfig ocl4dnnPoolingMethod_t pool_method; // = LIBDNN_POOLING_METHOD_MAX; bool global_pooling; // = false; bool avePoolPaddedArea; + bool computeMaxIdx; bool use_half; }; @@ -398,6 +401,7 @@ class OCL4DNNPool int32_t pooled_height_; int32_t pooled_width_; bool avePoolPaddedArea; + bool computeMaxIdx; bool use_half; }; diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp index 159319425e..034f8d3e7d 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp @@ -55,6 +55,7 @@ #include "../include/math_functions.hpp" #include "../include/default_kernel_config.hpp" #include "opencv2/dnn/shape_utils.hpp" +#include "opencv2/core/utils/logger.hpp" #if defined WIN32 || defined _WIN32 #include @@ -67,6 +68,69 @@ typedef std::map kernel_hash_t; static kernel_hash_t kernelConfigMap; static bool defaultConfigLoaded = false; +static std::string sanitize(const std::string& s) +{ + std::string s_ = s; + for (size_t i = 0; i < s_.size(); i++) + { + char c = s_[i]; + if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) + { + s_[i] = '_'; + } + } + // TODO add hash? + // s_ = s_ + cv::format("_%08llx", crc64((uchar*)s.c_str(), s.size())); + return s_; +} + +static void initializeGlobalBuiltinConfigurations(const std::string& cache_path) +{ + CV_Assert(defaultConfigLoaded == false); + CV_Assert(kernelConfigMap.empty()); + + /* fp32 config */ + size_t numConfigs = sizeof(default_kernel_config_intel_fp32) / + sizeof(default_kernel_config_intel_fp32[0]) / 2; + for (size_t i = 0; i < numConfigs; i++) + { + std::string key = std::string("Intel(R) Corporation_") + default_kernel_config_intel_fp32[2 * i]; + if (!cache_path.empty()) + { + std::string cacheFile = cache_path + sanitize(key); + std::ifstream cachedKernel(cacheFile.c_str()); + if (cachedKernel) + continue; // external configuration found, skip builtin + } + std::pair entry( + key, + default_kernel_config_intel_fp32[2 * i + 1]); + kernelConfigMap.insert(entry); + } + + /* fp16 config */ + numConfigs = sizeof(default_kernel_config_intel_fp16) / + sizeof(default_kernel_config_intel_fp16[0]) / 2; + for (size_t i = 0; i < numConfigs; i++) + { + std::string key = std::string("Intel(R) Corporation_") + default_kernel_config_intel_fp16[2 * i]; + if (!cache_path.empty()) + { + std::string cacheFile = cache_path + sanitize(key); + std::ifstream cachedKernel(cacheFile.c_str()); + if (cachedKernel) + continue; // external configuration found, skip builtin + } + std::pair entry( + key, + default_kernel_config_intel_fp16[2 * i + 1]); + kernelConfigMap.insert(entry); + } + + defaultConfigLoaded = true; +} + + template OCL4DNNConvSpatial::OCL4DNNConvSpatial(OCL4DNNConvConfig config) { @@ -139,9 +203,8 @@ OCL4DNNConvSpatial::OCL4DNNConvSpatial(OCL4DNNConvConfig config) } } - force_auto_tuning_ = - (use_cache_path_ && !utils::getConfigurationParameterBool("OPENCV_OCL4DNN_DISABLE_AUTO_TUNING", false)) - || utils::getConfigurationParameterBool("OPENCV_OCL4DNN_FORCE_AUTO_TUNING", false); + run_auto_tuning_ = use_cache_path_ && !utils::getConfigurationParameterBool("OPENCV_OCL4DNN_DISABLE_AUTO_TUNING", false); + force_auto_tuning_ = utils::getConfigurationParameterBool("OPENCV_OCL4DNN_FORCE_AUTO_TUNING", false); } template @@ -272,40 +335,38 @@ void OCL4DNNConvSpatial::setupKernelDetails(int32_t kernelType, // options options_ << " -cl-fast-relaxed-math -D KERNEL_IDLF -D convolve_simd=" << kernel_name_; + options_ << " -cl-mad-enable"; if (clOptionSupport("-cl-no-subgroup-ifp")) options_ << " -cl-no-subgroup-ifp "; // defs - int32_t output_width = output_w_; - int32_t output_height = output_h_; int32_t output_block_width = blockM; int32_t output_block_height = blockK; - const int32_t last_block_width = (output_width % output_block_width == 0) ? - output_block_width : output_width % output_block_width; - const int32_t last_block_height = (output_height % output_block_height == 0) ? - output_block_height : output_height % output_block_height; - int tile_x = alignSize((output_block_width - 1) * stride_w_ + kernel_w_ * dilation_w_, 4); - int tile_y = (output_block_height -1) * stride_h_ + kernel_h_ * dilation_h_; - int tile_y_stride = (4 * simd_size) / tile_x; - int invec_size = divUp(tile_y, tile_y_stride); + int tile_x = (output_block_width - 1) * stride_w_ + kernel_w_ * dilation_w_; + int tile_y = (output_block_height - 1) * stride_h_ + kernel_h_ * dilation_h_; + int invec_size = tile_y; addDef("SIMD_SIZE", simd_size); - addDef("filter_qualifier", "__global"); addDef("OUT_BLOCK_WIDTH", output_block_width); addDef("OUT_BLOCK_HEIGHT", output_block_height); - addDef("LAST_BLOCK_WIDTH", last_block_width); - addDef("LAST_BLOCK_HEIGHT", last_block_height); addDef("INPUT_DEPTH", channels_ / group_); addDef("TOTAL_INPUT_DEPTH_SIZE", channels_); addDef("TOTAL_OUTPUT_DEPTH", num_output_); addDef("NUM_FILTERS", M_); addDef("TILE_X", tile_x); addDef("TILE_Y", tile_y); - addDef("TILE_Y_STRIDE", tile_y_stride); addDef("INVEC_SIZE", invec_size); addDef("ALIGNED_NUM_FILTERS", (int)alignSize(M_, simd_size)); addDef("OUT_BLOCK_SIZE", (output_block_width*output_block_height)); addDef("APPLY_BIAS", bias_term_); + addDef("WEIGHT_PREF", ((kernel_w_ * kernel_h_) == 1) ? 1 : 8); + addDef("INPUT_PITCH", (width_ * height_)); + addDef("OUTPUT_PITCH", (output_w_ * output_h_)); + addDef("LEFT_FILTERS", ((int)alignSize(M_, simd_size) - M_)); + addDef("INPUT_WIDTH", width_); + addDef("INPUT_HEIGHT", height_); + addDef("FILTERS_IN_GROUP", ((int)alignSize(M_, simd_size) / simd_size)); + setFusionDefine(fused_activ_, fused_eltwise_); src_ = cv::ocl::dnn::conv_layer_spatial_oclsrc; @@ -528,13 +589,6 @@ void OCL4DNNConvSpatial::calculateBenchmark(const UMat &bottom, UMat &ver return; } -#define dbg -#ifdef dbg -#define dbgPrint(x) (x) -#else -#define dbgPrint(x) -#endif - // For large enough input size, we do not need to tune kernels for different // size. The reason is with large input size, there will be enough work items // to feed al the EUs. @@ -545,6 +599,7 @@ void OCL4DNNConvSpatial::calculateBenchmark(const UMat &bottom, UMat &ver template void OCL4DNNConvSpatial::generateKey() { + std::string precision = (use_half_) ? "FP16" : "FP32"; std::stringstream keyBuilder; // FIXME: to support fuse? keyBuilder << "k" << kernel_w_ << "x" << kernel_h_ << "_" @@ -558,21 +613,12 @@ void OCL4DNNConvSpatial::generateKey() << "num" << num_ << "_" << "M" << M_ << "_" << "activ" << fused_activ_ << "_" - << "eltwise" << fused_eltwise_; + << "eltwise" << fused_eltwise_ << "_" + << precision; key_ = ocl::Device::getDefault().vendorName() + "_EU" + cv::format("%d", ocl::Device::getDefault().maxComputeUnits()) + "_" + keyBuilder.str(); - key_sanitized_ = key_; - for (size_t i = 0; i < key_sanitized_.size(); i++) - { - char c = key_sanitized_[i]; - if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) - { - key_sanitized_[i] = '_'; - } - } - // TODO add hash? - // key_sanitized_ = key_sanitized_ + cv::format("_%08llx", crc64((uchar*)key_.c_str(), key_.size())); + key_sanitized_ = sanitize(key_); short_key_ = keyBuilder.str(); } @@ -587,11 +633,6 @@ std::string OCL4DNNConvSpatial::generateSpecificKey(int32_t type, int32_t << "_" << blockHeight << "_" << blockDepth; - if (!use_half_) - keyBuilder << "_float"; - else - keyBuilder << "_half"; - return keyBuilder.str(); } @@ -1135,7 +1176,7 @@ float OCL4DNNConvSpatial::timedConvolve(const UMat &bottom, UMat &top, cv::ocl::Timer timer(queue); timer.start(); bool res = true;; - dbgPrint(std::cout << "Benchmarking kernel: " << config->kernelName << std::endl); + CV_LOG_INFO(NULL, "Benchmarking kernel: " << config->kernelName); tuned_ = true; int loop_cnt = 4; for (int i = 0; i < loop_cnt; i++) { @@ -1152,7 +1193,6 @@ float OCL4DNNConvSpatial::timedConvolve(const UMat &bottom, UMat &top, } float elapsedTime = timer.durationNS() * 1e-6 / loop_cnt; - #ifdef dbg double out_w = output_w_; double out_h = output_h_; double out_z = M_; @@ -1160,16 +1200,8 @@ float OCL4DNNConvSpatial::timedConvolve(const UMat &bottom, UMat &top, double k_h = kernel_h_; double k_z = channels_; double totalFlops = ((k_w*k_h*k_z -1)*2)*(out_w*out_h*out_z)*num_; - std::cout << "\tEstimated Gflops:" << (totalFlops * 1e-9) - << std::endl; - std::cout << "\tEstimated GFLOPS/S: " << ((totalFlops * 1e-9)*(1000.0/elapsedTime)) - << std::endl; - #if 0 - std::cout << "Estimated utilization: " << - ((((totalFlops/1000)/1000)/1000)*(1000.0/elapsedTime))/880.0 - << std::endl; - #endif - #endif + CV_LOG_INFO(NULL, "\tEstimated Gflops:" << (totalFlops * 1e-9)); + CV_LOG_INFO(NULL, "\tEstimated GFLOPS/S: " << ((totalFlops * 1e-9)*(1000.0/elapsedTime))); return elapsedTime; } @@ -1225,18 +1257,18 @@ bool OCL4DNNConvSpatial::verifyResult(const UMat &bottom, if (use_half_ && error_factor > 0.1 * fabs(verify_data[offset]) && error_factor > 0.04 && !(fabs(verify_data[offset]) < 1.e-3 && error_factor < 1.e-4)) { - dbgPrint(printf("test verification failed @ image %d group %d" - "out_ch %d h %d w %d got %G expected %G\n", - n, g, out_ch, h, w, data[offset], verify_data[offset])); + CV_LOG_ERROR(NULL, "test verification failed @ image " << n << " group " << g + << " out_ch " << out_ch << " h " << h << " w " << w + << " got " << data[offset] << " expected " << verify_data[offset]); verificationFail = 1; goto out; } else if (!use_half_ && error_factor > 0.1 * fabs(verify_data[offset]) && !(fabs(verify_data[offset]) < 1.e-3 && error_factor < 1.e-4)) { - dbgPrint(printf("test verification failed @ image %d group %d" - "out_ch %d h %d w %d got %G expected %G\n", - n, g, out_ch, h, w, data[offset], verify_data[offset])); + CV_LOG_ERROR(NULL, "test verification failed @ image " << n << " group " << g + << " out_ch " << out_ch << " h " << h << " w " << w + << " got " << data[offset] << " expected " << verify_data[offset]); verificationFail = 1; goto out; } @@ -1517,17 +1549,11 @@ void OCL4DNNConvSpatial::generate_idlf_tuneritems(std::vector< cv::Ptr (4 * simd_size)) + int tile_x = alignSize(actual_tile_x, simd_size); + if (tile_x > simd_size) return; - if ((blockM * blockK + divUp(tile_x * tile_y, simd_size)) > block_size_max) - return; - - int tile_y_stride = (4 * simd_size) / tile_x; - int invec_size = divUp(tile_y, tile_y_stride); - if (invec_size > 4) + if (blockM * blockK > block_size_max) return; tunerItems.push_back(makePtr(KERNEL_TYPE_INTEL_IDLF, blockM, blockK, simd_size)); @@ -1570,11 +1596,7 @@ void OCL4DNNConvSpatial::generateTunerItems(std::vector< cv::Ptr 0; height--) { generate_idlf_tuneritems(tunerItems, width, height, simd_size); - if (tunerItems.size() >= 8 && height == 2) - break; } - if (tunerItems.size() >= 12 && width == 2) - break; } } } @@ -1661,35 +1683,31 @@ void OCL4DNNConvSpatial::setupConvolution(const UMat &bottom, if (kernelQueue[x]->tested == false) { bool verified = verifyResult(bottom, top, weight, bias, numImages, kernelQueue[x], verifyTop); if (verified == false) { - dbgPrint(std::cout << "Kernel " - << kernelQueue[x]->kernelName - << " failed verification" << std::endl); - dbgPrint(std::cout << "kernelQueue[x]->workItem_output[0]: " - << kernelQueue[x]->workItem_output[0] << " " - << "kernelQueue[x]->workItem_output[1]: " - << kernelQueue[x]->workItem_output[1] << " " - << "kernelQueue[x]->workItem_output[2]: " - << kernelQueue[x]->workItem_output[2] << " " - << "kernelQueue[x]->kernelType: " - << kernelQueue[x]->kernelType << " " - << "kernelQueue[x]->global_work_size[0]: " - << kernelQueue[x]->global_work_size[0] << " " - << "kernelQueue[x]->global_work_size[1]: " - << kernelQueue[x]->global_work_size[1] << " " - << "kernelQueue[x]->global_work_size[2]: " - << kernelQueue[x]->global_work_size[2] << " " - << "kernelQueue[x]->local_work_size[0]: " - << kernelQueue[x]->local_work_size[0] << " " - << "kernelQueue[x]->local_work_size[1]: " - << kernelQueue[x]->local_work_size[1] << " " - << "kernelQueue[x]->local_work_size[2]: " - << kernelQueue[x]->local_work_size[2] << " " - << kernelQueue[x]->swizzle_weights << " " - << kernelQueue[x]->use_null_local << std::endl); + CV_LOG_ERROR(NULL, "Kernel " << kernelQueue[x]->kernelName << " failed verification"); + CV_LOG_ERROR(NULL, "kernelQueue[x]->workItem_output[0]: " + << kernelQueue[x]->workItem_output[0] << " " + << "kernelQueue[x]->workItem_output[1]: " + << kernelQueue[x]->workItem_output[1] << " " + << "kernelQueue[x]->workItem_output[2]: " + << kernelQueue[x]->workItem_output[2] << " " + << "kernelQueue[x]->kernelType: " + << kernelQueue[x]->kernelType << " " + << "kernelQueue[x]->global_work_size[0]: " + << kernelQueue[x]->global_work_size[0] << " " + << "kernelQueue[x]->global_work_size[1]: " + << kernelQueue[x]->global_work_size[1] << " " + << "kernelQueue[x]->global_work_size[2]: " + << kernelQueue[x]->global_work_size[2] << " " + << "kernelQueue[x]->local_work_size[0]: " + << kernelQueue[x]->local_work_size[0] << " " + << "kernelQueue[x]->local_work_size[1]: " + << kernelQueue[x]->local_work_size[1] << " " + << "kernelQueue[x]->local_work_size[2]: " + << kernelQueue[x]->local_work_size[2] << " " + << kernelQueue[x]->swizzle_weights << " " + << kernelQueue[x]->use_null_local); } else { - dbgPrint(std::cout << "Kernel " - << kernelQueue[x]->kernelName - << " pass verification" << std::endl); + CV_LOG_INFO(NULL, "Kernel " << kernelQueue[x]->kernelName << " pass verification"); } } #endif @@ -1718,19 +1736,28 @@ void OCL4DNNConvSpatial::setupConvolution(const UMat &bottom, break; } else { kernelQueue[fastestKernel]->tested = true; - dbgPrint(std::cout << "Kernel " << - kernelQueue[fastestKernel]->kernelName << - " failed verification" << std::endl); + CV_LOG_ERROR(NULL, "Kernel " << kernelQueue[fastestKernel]->kernelName << + " failed verification"); failures++; } } } if (verification) { - dbgPrint(std::cout << "Kernel <" << kernelQueue[kernel_index_]->kernelName << - "> passed verification" << std::endl); - dbgPrint(std::cout << "Convolution Time:" << kernelQueue[kernel_index_]->executionTime << std::endl); + CV_LOG_INFO(NULL, "Kernel <" << kernelQueue[kernel_index_]->kernelName << + "> passed verification"); + CV_LOG_INFO(NULL, "Convolution Time:" << kernelQueue[kernel_index_]->executionTime); + double out_w = output_w_; + double out_h = output_h_; + double out_z = M_; + double k_w = kernel_w_; + double k_h = kernel_h_; + double k_z = channels_; + float elapsedTime = kernelQueue[kernel_index_]->executionTime; + double totalFlops = ((k_w*k_h*k_z -1)*2)*(out_w*out_h*out_z)*num_; + CV_LOG_INFO(NULL, "\tEstimated Gflops:" << (totalFlops * 1e-9)); + CV_LOG_INFO(NULL, "\tEstimated GFLOPS/S: " << ((totalFlops * 1e-9)*(1000.0/elapsedTime))); } else { - dbgPrint(std::cout << "fallback to basic kernel" << std::endl); + CV_LOG_INFO(NULL, "fallback to basic kernel"); options_.str(""); options_.clear(); // clear contents and state flags createBasicKernel(1, 1, 1); kernel_index_ = kernelQueue.size() - 1; @@ -1798,14 +1825,14 @@ void OCL4DNNConvSpatial::prepareKernel(const UMat &bottom, UMat &top, if (loadCachedConfig()) // check in-memory cache return; - if (loadTunedConfig()) // check external storage + if (loadTunedConfig()) // check external storage return; UMat benchData(1, numImages * top_dim_, (use_half_) ? CV_16SC1 : CV_32FC1); calculateBenchmark(bottom, benchData, (use_half_) ? weights_half : weight, bias, numImages); - if (force_auto_tuning_) + if (run_auto_tuning_ || force_auto_tuning_) { setupConvolution(bottom, top, weight, bias, numImages, benchData); } @@ -1820,18 +1847,8 @@ template bool OCL4DNNConvSpatial::loadCachedConfig() { cv::AutoLock lock(kernelConfigMutex); - if (!defaultConfigLoaded) - { - const size_t numConfigs = sizeof(default_kernel_config_intel)/sizeof(default_kernel_config_intel[0])/2; - for (size_t i = 0; i < numConfigs; i++) - { - std::pair entry( - std::string("Intel(R) Corporation_") + default_kernel_config_intel[2 * i], - default_kernel_config_intel[2 * i + 1]); - kernelConfigMap.insert(entry); - } - defaultConfigLoaded = true; - } + if (!defaultConfigLoaded && !force_auto_tuning_) + initializeGlobalBuiltinConfigurations((use_cache_path_ && !cache_path_.empty()) ? (cache_path_ + '/') : std::string()); kernel_hash_t::iterator it = kernelConfigMap.find(key_); if (it != kernelConfigMap.end()) @@ -1904,9 +1921,12 @@ bool OCL4DNNConvSpatial::setupKernelByConfig(int x, int y, int z, int typ template bool OCL4DNNConvSpatial::loadTunedConfig() { + if (force_auto_tuning_) + return false; // don't load results from external storage + if (!use_cache_path_) { - if (cache_path_.empty() && !force_auto_tuning_) + if (cache_path_.empty()) { static int warn_ = 0; if (!warn_) diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp index 81238e9f3e..b74bf4d8e8 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_pool.cpp @@ -56,6 +56,7 @@ OCL4DNNPool::OCL4DNNPool(OCL4DNNPoolConfig config) channels_ = config.channels; pool_method_ = config.pool_method; avePoolPaddedArea = config.avePoolPaddedArea; + computeMaxIdx = config.computeMaxIdx; use_half = config.use_half; for (int i = 0; i < spatial_dims; ++i) @@ -97,7 +98,7 @@ bool OCL4DNNPool::Forward(const UMat& bottom, UMat& top_mask) { bool ret = true; - size_t global[] = { 128 * 128 }; + size_t global[] = { (size_t)count_ }; size_t local[] = { 128 }; // support 2D case @@ -105,8 +106,7 @@ bool OCL4DNNPool::Forward(const UMat& bottom, { case LIBDNN_POOLING_METHOD_MAX: { - bool haveMask = !top_mask.empty(); - String kname = haveMask ? "max_pool_forward_mask" : "max_pool_forward"; + String kname = computeMaxIdx ? "max_pool_forward_mask" : "max_pool_forward"; kname += (use_half) ? "_half" : "_float"; ocl::Kernel oclk_max_pool_forward( kname.c_str(), @@ -118,7 +118,7 @@ bool OCL4DNNPool::Forward(const UMat& bottom, kernel_w_, kernel_h_, stride_w_, stride_h_, pad_w_, pad_h_, - haveMask ? " -D HAVE_MASK=1" : "" + computeMaxIdx ? " -D HAVE_MASK=1" : "" )); if (oclk_max_pool_forward.empty()) diff --git a/modules/dnn/src/opencl/conv_layer_spatial.cl b/modules/dnn/src/opencl/conv_layer_spatial.cl index 621ab6f620..dc7b047fe5 100644 --- a/modules/dnn/src/opencl/conv_layer_spatial.cl +++ b/modules/dnn/src/opencl/conv_layer_spatial.cl @@ -206,8 +206,6 @@ __kernel void ConvolveBasic( #elif defined KERNEL_IDLF -#define VLOAD4(_v, _p) do { _v = vload4(0, _p); } while(0) - // Each work-item computes a OUT_BLOCK_WIDTH * OUT_BLOCK_HEIGHT region of one output map. // Each work-group (which will be mapped to 1 SIMD16/SIMD8 EU thread) will compute 16/8 different feature maps, but each feature map is for the same region of the input image. // NDRange: (output_width+pad)/ OUT_BLOCK_WIDTH, (output_height+pad)/OUT_BLOCK_HEIGHT, NUM_FILTERS/OUT_BLOCK_DEPTH @@ -219,190 +217,123 @@ __kernel void convolve_simd( ELTWISE_DATA_ARG FUSED_ARG - __global Dtype* inputs_base, - filter_qualifier Dtype* weights_base, + __global Dtype* inputs, + __global Dtype* weights, BIAS_KERNEL_ARG - __global Dtype* outputs_base, + __global Dtype* outputs, const ushort input_width, const ushort input_height, const ushort output_width, const ushort output_height) { - __global Dtype* outputs = outputs_base; - __global Dtype* inputs = inputs_base; - filter_qualifier Dtype* weights = weights_base; unsigned int oc = get_global_id(0) * OUT_BLOCK_WIDTH; // oc = Output Column - unsigned int or = get_global_id(1) * OUT_BLOCK_HEIGHT;// or = Output Row - unsigned int fm = get_global_id(2);// fm = Feature Map = od = Output Depth + unsigned int or = get_global_id(1) * OUT_BLOCK_HEIGHT; // or = Output Row + unsigned int fm = get_global_id(2); // fm = Feature Map = od = Output Depth unsigned int fmg = get_group_id(2); unsigned int lid = get_local_id(2); - Dtype out[OUT_BLOCK_WIDTH * OUT_BLOCK_HEIGHT]; - - int in_addr; + Dtype out[OUT_BLOCK_WIDTH * OUT_BLOCK_HEIGHT] = { 0.0f }; // find weights address of given neuron (lid is index) - unsigned int weight_addr = (fmg % (ALIGNED_NUM_FILTERS/SIMD_SIZE)) * INPUT_DEPTH * KERNEL_WIDTH * KERNEL_HEIGHT * SIMD_SIZE + lid; + unsigned int weight_addr = (fmg % FILTERS_IN_GROUP) * + INPUT_DEPTH * KERNEL_WIDTH * KERNEL_HEIGHT * SIMD_SIZE + lid; - for(int i=0;i= INPUT_PAD_H && curr_y < input_height + INPUT_PAD_H && curr_x + 3 >= INPUT_PAD_W && curr_x < input_width + INPUT_PAD_W) { - if (curr_x < INPUT_PAD_W) { - in_buf.in_vec[reg].s0 = 0; - if (curr_x + 1 >= INPUT_PAD_W && curr_x + 1 < input_width + INPUT_PAD_W) - in_buf.in_vec[reg].s1 = *(inputs + in_offset + 1); - else - in_buf.in_vec[reg].s1 = 0; - if (curr_x + 2 >= INPUT_PAD_W && curr_x + 2 < input_width + INPUT_PAD_W) - in_buf.in_vec[reg].s2 = *(inputs + in_offset + 2); - else - in_buf.in_vec[reg].s2 = 0; - if (curr_x + 3 < input_width + INPUT_PAD_W) - in_buf.in_vec[reg].s3 = *(inputs + in_offset + 3); - else - in_buf.in_vec[reg].s3 = 0; - } else { - VLOAD4(in_buf.in_vec[reg], inputs + in_offset); - if (curr_x + 1 >= input_width + INPUT_PAD_W) - in_buf.in_vec[reg].s1 = 0; - if (curr_x + 2 >= input_width + INPUT_PAD_W) - in_buf.in_vec[reg].s2 = 0; - if (curr_x + 3 >= input_width + INPUT_PAD_W) - in_buf.in_vec[reg].s3 = 0; - } - } else { - in_buf.in_vec[reg] = 0; + if (!(curr_y >= INPUT_PAD_H && curr_y < INPUT_HEIGHT + INPUT_PAD_H && + curr_x >= INPUT_PAD_W && curr_x < INPUT_WIDTH + INPUT_PAD_W)) + { + in_buf[reg] = 0; } - curr_y += TILE_Y_STRIDE; -#else - VLOAD4(in_buf.in_vec[reg], inputs + in_offset); #endif - } - in_offset += input_width * TILE_Y_STRIDE; - }); - in_addr += input_height * input_width; + curr_y += 1; + in_offset += INPUT_WIDTH; + } + + in_addr += INPUT_PITCH; + #if INPUT_PAD_W != 0 || INPUT_PAD_H != 0 || INPUT_PAD_BOTTOM != 0 || INPUT_PAD_RIGHT != 0 curr_y = saved_y; #endif -#if KERNEL_WIDTH * KERNEL_HEIGHT != 1 -#define WEIGHT_PREF 8 -#else -#define WEIGHT_PREF 1 -#endif - union { - Dtype w[WEIGHT_PREF]; -#if KERNEL_WIDTH * KERNEL_HEIGHT != 1 - INT_TYPE8 ui8; -#endif - } weight_buf; + Dtype weight_buf[WEIGHT_PREF]; int w_idx=0; - unsigned int orig_weight_addr = weight_addr; -#if KERNEL_WIDTH * KERNEL_HEIGHT != 1 - weight_buf.ui8 = SUB_GROUP_BLOCK_READ8((__global INT_TYPE *)&weights[weight_addr]); - weight_addr += SIMD_SIZE * WEIGHT_PREF; -#else - weight_buf.w[0] = as_Dtype(SUB_GROUP_BLOCK_READ((__global INT_TYPE *)&weights[weight_addr])); - weight_addr += SIMD_SIZE * 1; -#endif + for (int i = 0; i < WEIGHT_PREF; i++) + { + weight_buf[i] = weights[weight_addr]; + weight_addr += SIMD_SIZE; + } -#define BLOCK_IN(n) sub_group_broadcast( in_buf.in_array[((n)%4) + ((n) / (TILE_Y_STRIDE * TILE_X)) * 4], (((n) % (TILE_Y_STRIDE * TILE_X))/4)) +#define BLOCK_IN(n, c) intel_sub_group_shuffle(in_buf[n], (c)) int kr = 0; // kr = Kernel Row LOOP(KERNEL_HEIGHT, kr,// LOOP is a macro that unrolls the loop. + { + int kc = 0; // kc = Kernel Column + LOOP(KERNEL_WIDTH, kc, { - int kc = 0; // kc = Kernel Column - LOOP(KERNEL_WIDTH, kc, - { - for(int br=0; br < OUT_BLOCK_HEIGHT; br++) { - for(int bc=0; bc < OUT_BLOCK_WIDTH; bc++) { - Dtype input = BLOCK_IN((br * STRIDE_Y + kr * DILATION_Y) * TILE_X + bc * STRIDE_X + kc * DILATION_X); - out[br * OUT_BLOCK_WIDTH + bc] = mad(weight_buf.w[w_idx % WEIGHT_PREF], input, out[br * OUT_BLOCK_WIDTH + bc]); - } + for (int br=0; br < OUT_BLOCK_HEIGHT; br++) + { + for(int bc=0; bc < OUT_BLOCK_WIDTH; bc++) + { + Dtype input = BLOCK_IN((br * STRIDE_Y + kr * DILATION_Y), bc * STRIDE_X + kc * DILATION_X); + out[br * OUT_BLOCK_WIDTH + bc] = mad(weight_buf[w_idx % WEIGHT_PREF], input, out[br * OUT_BLOCK_WIDTH + bc]); } -#if KERNEL_WIDTH * KERNEL_HEIGHT > WEIGHT_PREF - // We assume KERNEL_W is equal to KERNEL_H here. - if ((w_idx + 1) % WEIGHT_PREF == 0 - #if KERNEL_WIDTH * KERNEL_HEIGHT % 8 != 0 - && ((w_idx + 1) <= (KERNEL_WIDTH * KERNEL_HEIGHT - WEIGHT_PREF)) - #endif - ) { - weight_buf.ui8 = SUB_GROUP_BLOCK_READ8((__global INT_TYPE *)&weights[weight_addr]); - weight_addr += SIMD_SIZE * WEIGHT_PREF; // weights must be stored in just the right SIMD swizzled format for this to work, see host code for details. - } - #if KERNEL_WIDTH*KERNEL_HEIGHT % 8 == 0 - // need to do nothing - #else - else if ((w_idx + 1) % WEIGHT_PREF == 0 && ((w_idx + 1) > (KERNEL_WIDTH * KERNEL_HEIGHT - WEIGHT_PREF))) - #if KERNEL_WIDTH * KERNEL_HEIGHT % 8 == 1 - weight_buf.w[0] = weights[weight_addr]; - #elif KERNEL_WIDTH * KERNEL_HEIGHT % 8 == 2 - weight_buf.ui8.s01 = SUB_GROUP_BLOCK_READ2((__global INT_TYPE *)&weights[weight_addr]); - #elif KERNEL_WIDTH * KERNEL_HEIGHT % 8 <= 4 - weight_buf.ui8.s0123 = SUB_GROUP_BLOCK_READ4((__global INT_TYPE *)&weights[weight_addr]); - #else - weight_buf.ui8 = SUB_GROUP_BLOCK_READ8((__global INT_TYPE *)&weights[weight_addr]); - #endif - #endif -#endif - ++w_idx; - }); + } + weight_buf[w_idx % WEIGHT_PREF] = weights[weight_addr]; + weight_addr += SIMD_SIZE; + ++w_idx; }); - weight_addr = orig_weight_addr + KERNEL_WIDTH * KERNEL_HEIGHT * SIMD_SIZE; + }); + weight_addr -= WEIGHT_PREF * SIMD_SIZE; + } - } - // dead code to work around possible compiler bug. - if (ALIGNED_NUM_FILTERS != NUM_FILTERS && fm > 0xfffffffeul) { - outputs[0] = BLOCK_IN(fm % SIMD_SIZE); - } fm = fm % ALIGNED_NUM_FILTERS; - if ((ALIGNED_NUM_FILTERS == NUM_FILTERS || fm < NUM_FILTERS)) { - unsigned int out_addr = ( num_in_batch * TOTAL_OUTPUT_DEPTH + fm ) * output_width * output_height; - out_addr += or * output_width + oc; - // we need this address calculation for biases because we support views and batching -#if APPLY_BIAS - Dtype bias = biases_base[fm]; -#else - Dtype bias = 0; +#if LEFT_FILTERS > 0 + if (fm < NUM_FILTERS) +#endif + { + unsigned int out_addr = (num_in_batch * TOTAL_OUTPUT_DEPTH + fm) * OUTPUT_PITCH; + out_addr += or * output_width + oc; + // we need this address calculation for biases because we support views and batching +#if APPLY_BIAS + Dtype bias = biases_base[fm]; +#else + Dtype bias = 0; #endif - for(unsigned int r = 0; r < OUT_BLOCK_HEIGHT; r++) { - if (r + or >= output_height) break; - for(unsigned int c = 0; c < OUT_BLOCK_WIDTH; c++) { - if (c + oc >= output_width) break; - // this does a scattered write to SIMD_SIZE different feature maps, so that data within one map is contiguous, thus ready for input to next layer. - ACTIVATION_FUNCTION(outputs, out_addr + r * output_width + c, bias + out[r * OUT_BLOCK_WIDTH + c], fm); + for(unsigned int r = 0; r < OUT_BLOCK_HEIGHT; r++) + { + if (r + or >= output_height) break; + for(unsigned int c = 0; c < OUT_BLOCK_WIDTH; c++) + { + if (c + oc >= output_width) break; + // this does a scattered write to SIMD_SIZE different feature maps, + // so that data within one map is contiguous, thus ready for input to next layer. + ACTIVATION_FUNCTION(outputs, out_addr + r * output_width + c, bias + out[r * OUT_BLOCK_WIDTH + c], fm); } } } diff --git a/modules/dnn/src/opencl/ocl4dnn_pooling.cl b/modules/dnn/src/opencl/ocl4dnn_pooling.cl index e9d1d26f0f..501f5a5e87 100644 --- a/modules/dnn/src/opencl/ocl4dnn_pooling.cl +++ b/modules/dnn/src/opencl/ocl4dnn_pooling.cl @@ -65,36 +65,40 @@ __kernel void #endif ) { - for (int index = get_global_id(0); index < nthreads; - index += get_global_size(0)) + int index = get_global_id(0); + if (index >= nthreads) + return; + + const int pw = index % pooled_width; + const int xx = index / pooled_width; + const int ph = xx % pooled_height; + const int ch = xx / pooled_height; + int hstart = ph * STRIDE_H - PAD_H; + int wstart = pw * STRIDE_W - PAD_W; + Dtype maxval = -FLT_MAX; + int maxidx = -1; + int in_offset = ch * height * width; + for (int h = 0; h < KERNEL_H; ++h) { - const int pw = index % pooled_width; - const int ph = (index / pooled_width) % pooled_height; - const int c = (index / pooled_width / pooled_height) % channels; - const int n = index / pooled_width / pooled_height / channels; - int hstart = ph * STRIDE_H - PAD_H; - int wstart = pw * STRIDE_W - PAD_W; - const int hend = min(hstart + KERNEL_H, height); - const int wend = min(wstart + KERNEL_W, width); - hstart = max(hstart, (int)0); - wstart = max(wstart, (int)0); - Dtype maxval = -FLT_MAX; - int maxidx = -1; - __global const Dtype* bottom_slice = bottom_data - + (n * channels + c) * height * width; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { - if (bottom_slice[h * width + w] > maxval) { - maxidx = h * width + w; - maxval = bottom_slice[maxidx]; + int off_y = hstart + h; + if (off_y >= 0 && off_y < height) + { + for (int w = 0; w < KERNEL_W; ++w) + { + int off_x = wstart + w; + if (off_x >= 0 && off_x < width) + { + Dtype val = bottom_data[in_offset + off_y * width + off_x]; + maxidx = (val > maxval) ? (off_y * width + off_x) : maxidx; + maxval = fmax(val, maxval); } } } - top_data[index] = maxval; -#ifdef HAVE_MASK - mask[index] = maxidx; -#endif } + top_data[index] = maxval; +#ifdef HAVE_MASK + mask[index] = maxidx; +#endif } #elif defined KERNEL_AVE_POOL @@ -105,43 +109,42 @@ __kernel void TEMPLATE(ave_pool_forward, Dtype)( const int pooled_height, const int pooled_width, __global Dtype* top_data) { - for (int index = get_global_id(0); index < nthreads; - index += get_global_size(0)) - { - { - const int pw = index % pooled_width; - const int ph = (index / pooled_width) % pooled_height; - const int c = (index / pooled_width / pooled_height) % channels; - const int n = index / pooled_width / pooled_height / channels; - int hstart = ph * STRIDE_H - PAD_H; - int wstart = pw * STRIDE_W - PAD_W; - int hend = min(hstart + KERNEL_H, height + PAD_H); - int wend = min(wstart + KERNEL_W, width + PAD_W); - int pool_size; + int index = get_global_id(0); + if (index >= nthreads) + return; + + const int pw = index % pooled_width; + const int xx = index / pooled_width; + const int ph = xx % pooled_height; + const int ch = xx / pooled_height; + int hstart = ph * STRIDE_H - PAD_H; + int wstart = pw * STRIDE_W - PAD_W; + int hend = min(hstart + KERNEL_H, height + PAD_H); + int wend = min(wstart + KERNEL_W, width + PAD_W); + int pool_size; #ifdef AVE_POOL_PADDING_AREA - pool_size = (hend - hstart) * (wend - wstart); - hstart = max(hstart, (int)0); - wstart = max(wstart, (int)0); - hend = min(hend, height); - wend = min(wend, width); + pool_size = (hend - hstart) * (wend - wstart); + hstart = max(hstart, (int)0); + wstart = max(wstart, (int)0); + hend = min(hend, height); + wend = min(wend, width); #else - hstart = max(hstart, (int)0); - wstart = max(wstart, (int)0); - hend = min(hend, height); - wend = min(wend, width); - pool_size = (hend - hstart) * (wend - wstart); + hstart = max(hstart, (int)0); + wstart = max(wstart, (int)0); + hend = min(hend, height); + wend = min(wend, width); + pool_size = (hend - hstart) * (wend - wstart); #endif - Dtype aveval = 0; - __global const Dtype* bottom_slice = bottom_data - + (n * channels + c) * height * width; - for (int h = hstart; h < hend; ++h) { - for (int w = wstart; w < wend; ++w) { - aveval += bottom_slice[h * width + w]; - } - } - top_data[index] = aveval / pool_size; + Dtype aveval = 0; + int in_offset = ch * height * width; + for (int h = hstart; h < hend; ++h) + { + for (int w = wstart; w < wend; ++w) + { + aveval += bottom_data[in_offset + h * width + w]; } } + top_data[index] = aveval / pool_size; } #elif defined KERNEL_STO_POOL diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp index 4bff84175d..7d7d300386 100644 --- a/modules/dnn/src/tensorflow/tf_importer.cpp +++ b/modules/dnn/src/tensorflow/tf_importer.cpp @@ -18,6 +18,7 @@ Implementation of Tensorflow models parser #include #include #include +#include #include "tf_graph_simplifier.hpp" #endif @@ -50,7 +51,8 @@ enum DataLayout { DATA_LAYOUT_NHWC, DATA_LAYOUT_NCHW, - DATA_LAYOUT_UNKNOWN + DATA_LAYOUT_UNKNOWN, + DATA_LAYOUT_PLANAR // 2-dimensional outputs (matmul, flatten, reshape to 2d) }; typedef std::vector > StrIntVector; @@ -245,16 +247,53 @@ const tensorflow::AttrValue& getLayerAttr(const tensorflow::NodeDef &layer, cons return layer.attr().at(name); } +static int getDataLayout(const tensorflow::NodeDef& layer) +{ + if (hasLayerAttr(layer, "data_format")) + { + std::string format = getLayerAttr(layer, "data_format").s(); + if (format == "NHWC" || format == "channels_last") + return DATA_LAYOUT_NHWC; + else if (format == "NCHW" || format == "channels_first") + return DATA_LAYOUT_NCHW; + else + CV_Error(Error::StsParseError, "Unknown data_format value: " + format); + } + return DATA_LAYOUT_UNKNOWN; +} + +static inline std::string getNodeName(const std::string& tensorName) +{ + return tensorName.substr(0, tensorName.rfind(':')); +} + +static inline int getDataLayout(const std::string& layerName, + const std::map& data_layouts) +{ + std::map::const_iterator it = data_layouts.find(getNodeName(layerName)); + return it != data_layouts.end() ? it->second : DATA_LAYOUT_UNKNOWN; +} + void setStrides(LayerParams &layerParams, const tensorflow::NodeDef &layer) { if (hasLayerAttr(layer, "strides")) { const tensorflow::AttrValue& val = getLayerAttr(layer, "strides"); + int dimX, dimY, dimC; + int layout = getDataLayout(layer); + if (layout == DATA_LAYOUT_NCHW) + { + dimC = 1; dimY = 2; dimX = 3; + } + else + { + dimY = 1; dimX = 2; dimC = 3; + } if (val.list().i_size() != 4 || - val.list().i(0) != 1 || val.list().i(3) != 1) + val.list().i(0) != 1 || val.list().i(dimC) != 1) CV_Error(Error::StsError, "Unsupported strides"); - layerParams.set("stride_h", static_cast(val.list().i(1))); - layerParams.set("stride_w", static_cast(val.list().i(2))); + layerParams.set("stride_h", static_cast(val.list().i(dimY))); + layerParams.set("stride_w", static_cast(val.list().i(dimX))); } } @@ -277,11 +316,21 @@ void setKSize(LayerParams &layerParams, const tensorflow::NodeDef &layer) if (hasLayerAttr(layer, "ksize")) { const tensorflow::AttrValue& val = getLayerAttr(layer, "ksize"); + int dimX, dimY, dimC; + int layout = getDataLayout(layer); + if (layout == DATA_LAYOUT_NCHW) + { + dimC = 1; dimY = 2; dimX = 3; + } + else + { + dimY = 1; dimX = 2; dimC = 3; + } if (val.list().i_size() != 4 || - val.list().i(0) != 1 || val.list().i(3) != 1) + val.list().i(0) != 1 || val.list().i(dimC) != 1) CV_Error(Error::StsError, "Unsupported ksize"); - layerParams.set("kernel_h", static_cast(val.list().i(1))); - layerParams.set("kernel_w", static_cast(val.list().i(2))); + layerParams.set("kernel_h", static_cast(val.list().i(dimY))); + layerParams.set("kernel_w", static_cast(val.list().i(dimX))); } else { @@ -375,6 +424,8 @@ private: // and may be used to build the network using binary format only as a weights storage. // This approach is similar to Caffe's `.prorotxt` and `.caffemodel`. tensorflow::GraphDef netTxt; + + std::vector netInputsNames; }; TFImporter::TFImporter(const char *model, const char *config) @@ -442,7 +493,14 @@ void TFImporter::connect(const std::map& layers_name_id_map, Net& n std::map::const_iterator it = layers_name_id_map.find(outPin.name); if (it == layers_name_id_map.end()) CV_Error(Error::StsError, "Input layer not found: " + outPin.name); - network.connect(it->second, outPin.blobIndex, input_layer_id, input_blob_id); + + std::vector::iterator inpNameIt = std::find(netInputsNames.begin(), netInputsNames.end(), outPin.name); + int blobIndex; + if (inpNameIt == netInputsNames.end()) + blobIndex = outPin.blobIndex; + else + blobIndex = inpNameIt - netInputsNames.begin(); + network.connect(it->second, blobIndex, input_layer_id, input_blob_id); } void TFImporter::connectToAllBlobs(const std::map& layer_id, Net& network, const Pin& outPin, @@ -560,39 +618,38 @@ static void addConstNodes(tensorflow::GraphDef& net, std::map& cons // If all inputs of specific layer have the same data layout we can say that // this layer's output has this data layout too. Returns DATA_LAYOUT_UNKNOWN otherwise. -static int predictOutputDataLayout(const tensorflow::NodeDef& layer, const std::map& data_layouts) +static int predictOutputDataLayout(const tensorflow::GraphDef& net, + const tensorflow::NodeDef& layer, + const std::map& data_layouts) { - if (hasLayerAttr(layer, "data_format")) - { - std::string format = getLayerAttr(layer, "data_format").s(); - if (format == "NHWC" || format == "channels_last") - return DATA_LAYOUT_NHWC; - else if (format == "NCHW" || format == "channels_first") - return DATA_LAYOUT_NCHW; - else - CV_Error(Error::StsParseError, "Unknown data_format value: " + format); - } + int layout = getDataLayout(layer); + if (layout != DATA_LAYOUT_UNKNOWN) + return layout; // Determine layout by layer's inputs - int layout = DATA_LAYOUT_UNKNOWN; std::map::const_iterator it; for (int i = 0, n = layer.input_size(); i < n; ++i) { - it = data_layouts.find(layer.input(i).substr(0, layer.input(i).rfind(':'))); + it = data_layouts.find(getNodeName(layer.input(i))); if (it != data_layouts.end()) { - if (it->second == DATA_LAYOUT_UNKNOWN) - return DATA_LAYOUT_UNKNOWN; - else if (it->second != layout) + if (layout != DATA_LAYOUT_UNKNOWN) { - if (layout == DATA_LAYOUT_UNKNOWN) - layout = it->second; - else + if (it->second != layout && it->second != DATA_LAYOUT_UNKNOWN) return DATA_LAYOUT_UNKNOWN; } + else + layout = it->second; } } - return layout; + + if (layout != DATA_LAYOUT_UNKNOWN) + return layout; + + // Determine layout by layer's consumers recursively. + it = data_layouts.find(layer.name()); + CV_Assert(it != data_layouts.end()); + return it->second; } void TFImporter::populateNet(Net dstNet) @@ -610,6 +667,52 @@ void TFImporter::populateNet(Net dstNet) int layersSize = net.node_size(); std::map data_layouts; + // Pre-fill data layouts where they are set explicitly. + // Assuming that nodes are in topological order + for (int i = net.node_size() - 1; i >= 0; --i) + { + const tensorflow::NodeDef& layer = net.node(i); + std::string name = layer.name(); + + int layout = getDataLayout(layer); + std::map::iterator it = data_layouts.find(name); + if (it != data_layouts.end()) + { + if (layout != DATA_LAYOUT_UNKNOWN) + { + if (it->second == DATA_LAYOUT_UNKNOWN) + it->second = layout; + else if (it->second != layout) + { + it->second = DATA_LAYOUT_UNKNOWN; + layout = DATA_LAYOUT_UNKNOWN; + } + } + else + layout = it->second; + } + else + data_layouts[name] = layout; + + // Specify input layers to have the same data layout. + for (int j = 0; j < layer.input_size(); ++j) + { + name = getNodeName(layer.input(j)); + it = data_layouts.find(name); + if (it != data_layouts.end()) + { + if (layout != DATA_LAYOUT_UNKNOWN) + { + if (it->second == DATA_LAYOUT_UNKNOWN) + it->second = layout; + else if (it->second != layout) + it->second = DATA_LAYOUT_UNKNOWN; + } + } + else + data_layouts[name] = layout; + } + } // find all Const layers for params std::map value_id; @@ -628,7 +731,8 @@ void TFImporter::populateNet(Net dstNet) if(layers_to_ignore.find(name) != layers_to_ignore.end()) continue; - data_layouts[name] = predictOutputDataLayout(layer, data_layouts); + int predictedLayout = predictOutputDataLayout(net, layer, data_layouts); + data_layouts[name] = predictedLayout; if (type == "Conv2D" || type == "SpaceToBatchND" || type == "DepthwiseConv2dNative") { @@ -733,7 +837,8 @@ void TFImporter::populateNet(Net dstNet) // one input only connect(layer_id, dstNet, parsePin(input), id, 0); - if (data_layouts[name] == DATA_LAYOUT_UNKNOWN) + + if (getDataLayout(name, data_layouts) == DATA_LAYOUT_UNKNOWN) data_layouts[name] = DATA_LAYOUT_NHWC; } else if (type == "BiasAdd" || type == "Add") @@ -778,7 +883,7 @@ void TFImporter::populateNet(Net dstNet) Pin inp = parsePin(layer.input(ii)); if (layer_id.find(inp.name) == layer_id.end()) CV_Error(Error::StsError, "Input layer not found: " + inp.name); - dstNet.connect(layer_id.at(inp.name), inp.blobIndex, id, ii); + connect(layer_id, dstNet, inp, id, ii); } } } @@ -852,14 +957,15 @@ void TFImporter::populateNet(Net dstNet) // one input only int input_blob_index = kernel_blob_index == 0 ? 1 : 0; connect(layer_id, dstNet, parsePin(layer.input(input_blob_index)), id, 0); - data_layouts[name] = DATA_LAYOUT_UNKNOWN; + data_layouts[name] = DATA_LAYOUT_PLANAR; } else if (type == "Reshape") { Pin inpId = parsePin(layer.input(0)); Mat newShape = getTensorContent(getConstBlob(layer, value_id, 1)); - if (newShape.total() != 4 && data_layouts[layer.input(0)] == DATA_LAYOUT_NHWC) + int inpLayout = getDataLayout(layer.input(0), data_layouts); + if (newShape.total() != 4 && inpLayout == DATA_LAYOUT_NHWC) { LayerParams permLP; int order[] = {0, 2, 3, 1}; // From OpenCV's NCHW to NHWC. @@ -872,7 +978,7 @@ void TFImporter::populateNet(Net dstNet) connect(layer_id, dstNet, inpId, permId, 0); inpId = Pin(permName); } - else if (newShape.total() == 4 && data_layouts[layer.input(0)] == DATA_LAYOUT_NHWC) + else if (newShape.total() == 4 && inpLayout == DATA_LAYOUT_NHWC) { // NHWC->NCHW std::swap(*newShape.ptr(0, 2), *newShape.ptr(0, 3)); @@ -885,11 +991,12 @@ void TFImporter::populateNet(Net dstNet) // one input only connect(layer_id, dstNet, inpId, id, 0); + data_layouts[name] = newShape.total() == 2 ? DATA_LAYOUT_PLANAR : DATA_LAYOUT_UNKNOWN; } else if (type == "Flatten" || type == "Squeeze") { Pin inpId = parsePin(layer.input(0)); - int inpLayout = data_layouts[layer.input(0)]; + int inpLayout = getDataLayout(layer.input(0), data_layouts); if (type == "Squeeze") { CV_Assert(hasLayerAttr(layer, "squeeze_dims")); @@ -923,7 +1030,7 @@ void TFImporter::populateNet(Net dstNet) int id = dstNet.addLayer(name, "Flatten", layerParams); layer_id[name] = id; connect(layer_id, dstNet, inpId, id, 0); - data_layouts[name] = DATA_LAYOUT_UNKNOWN; + data_layouts[name] = DATA_LAYOUT_PLANAR; } else if (type == "Transpose") { @@ -934,7 +1041,8 @@ void TFImporter::populateNet(Net dstNet) { // Only NHWC <-> NCHW permutations are allowed. OpenCV is always // keep NCHW layout this way. - if (data_layouts[layer.input(0)] == DATA_LAYOUT_NHWC) + int inpLayout = getDataLayout(layer.input(0), data_layouts); + if (inpLayout == DATA_LAYOUT_NHWC) { if (permData[0] == 0 && permData[1] == 3 && permData[2] == 1 && permData[3] == 2) { @@ -951,7 +1059,7 @@ void TFImporter::populateNet(Net dstNet) else CV_Error(Error::StsParseError, "Only NHWC <-> NCHW permutations are allowed."); } - else if (data_layouts[layer.input(0)] == DATA_LAYOUT_NCHW) + else if (inpLayout == DATA_LAYOUT_NCHW) { if (permData[0] == 0 && permData[1] == 2 && permData[2] == 3 && permData[3] == 1) { @@ -1013,7 +1121,10 @@ void TFImporter::populateNet(Net dstNet) { int axisId = (type == "Concat" ? 0 : layer.input_size() - 1); int axis = getConstBlob(layer, value_id, axisId).int_val().Get(0); - layerParams.set("axis", 0 <= axis && axis < 4 ? toNCHW(axis) : axis); + + if (getDataLayout(name, data_layouts) == DATA_LAYOUT_NHWC) + axis = toNCHW(axis); + layerParams.set("axis", axis); int id = dstNet.addLayer(name, "Concat", layerParams); layer_id[name] = id; @@ -1028,7 +1139,7 @@ void TFImporter::populateNet(Net dstNet) Pin inp = parsePin(layer.input(ii)); if (layer_id.find(inp.name) == layer_id.end()) CV_Error(Error::StsError, "Input layer not found: " + inp.name); - dstNet.connect(layer_id.at(inp.name), inp.blobIndex, id, ii - from); + connect(layer_id, dstNet, inp, id, ii - from); } } else if (type == "MaxPool") @@ -1060,10 +1171,12 @@ void TFImporter::populateNet(Net dstNet) } else if (type == "Placeholder") { - std::vector netInputs(1); - netInputs[0] = name; - layer_id[name] = 0; - dstNet.setInputsNames(netInputs); + if (!hasLayerAttr(layer, "dtype") || + getLayerAttr(layer, "dtype").type() != tensorflow::DT_BOOL) // If input is not a train/test flag. + { + netInputsNames.push_back(name); + layer_id[name] = 0; + } } else if (type == "Split") { // TODO: determining axis index remapping by input dimensions order of input blob @@ -1094,7 +1207,7 @@ void TFImporter::populateNet(Net dstNet) CV_Assert(!begins.empty(), !sizes.empty(), begins.type() == CV_32SC1, sizes.type() == CV_32SC1); - if (begins.total() == 4 && data_layouts[name] == DATA_LAYOUT_NHWC) + if (begins.total() == 4 && getDataLayout(name, data_layouts) == DATA_LAYOUT_NHWC) { // Swap NHWC parameters' order to NCHW. std::swap(*begins.ptr(0, 2), *begins.ptr(0, 3)); @@ -1201,7 +1314,7 @@ void TFImporter::populateNet(Net dstNet) Pin inp = parsePin(layer.input(ii)); if (layer_id.find(inp.name) == layer_id.end()) CV_Error(Error::StsError, "Input layer not found: " + inp.name); - dstNet.connect(layer_id.at(inp.name), inp.blobIndex, id, ii); + connect(layer_id, dstNet, inp, id, ii); } } } @@ -1494,7 +1607,7 @@ void TFImporter::populateNet(Net dstNet) CV_Assert(reductionIndices.type() == CV_32SC1); const int numAxes = reductionIndices.total(); - if (data_layouts[name] == DATA_LAYOUT_NHWC) + if (getDataLayout(name, data_layouts) == DATA_LAYOUT_NHWC) for (int i = 0; i < numAxes; ++i) reductionIndices.at(i) = toNCHW(reductionIndices.at(i)); @@ -1641,6 +1754,27 @@ void TFImporter::populateNet(Net dstNet) connect(layer_id, dstNet, Pin(name), flattenId, 0); } } + else if (type == "ClipByValue") + { + // op: "ClipByValue" + // input: "input" + // input: "mix" + // input: "max" + CV_Assert(layer.input_size() == 3); + + Mat minValue = getTensorContent(getConstBlob(layer, value_id, 1)); + Mat maxValue = getTensorContent(getConstBlob(layer, value_id, 2)); + CV_Assert(minValue.total() == 1, minValue.type() == CV_32F, + maxValue.total() == 1, maxValue.type() == CV_32F); + + layerParams.set("min_value", minValue.at(0)); + layerParams.set("max_value", maxValue.at(0)); + + int id = dstNet.addLayer(name, "ReLU6", layerParams); + layer_id[name] = id; + + connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0); + } else if (type == "Abs" || type == "Tanh" || type == "Sigmoid" || type == "Relu" || type == "Elu" || type == "Identity" || type == "Relu6") @@ -1698,6 +1832,7 @@ void TFImporter::populateNet(Net dstNet) } } } + dstNet.setInputsNames(netInputsNames); } } // namespace diff --git a/modules/dnn/src/torch/torch_importer.cpp b/modules/dnn/src/torch/torch_importer.cpp index 3607e6c08e..88779e9977 100644 --- a/modules/dnn/src/torch/torch_importer.cpp +++ b/modules/dnn/src/torch/torch_importer.cpp @@ -592,8 +592,8 @@ struct TorchImporter DictValue dimParam = scalarParams.get("size"); layerParams.set("dim", dimParam); - if (scalarParams.has("batchMode") && scalarParams.get("batchMode")) - layerParams.set("axis", 1); + int axis = (int)scalarParams.get("batchMode", true); + layerParams.set("axis", axis); curModule->modules.push_back(newModule); } diff --git a/modules/dnn/test/test_backends.cpp b/modules/dnn/test/test_backends.cpp index f6563cb3cb..48fe765224 100644 --- a/modules/dnn/test/test_backends.cpp +++ b/modules/dnn/test/test_backends.cpp @@ -182,11 +182,9 @@ TEST_P(DNNTestNetwork, MobileNet_SSD_Caffe) throw SkipTestException(""); Mat sample = imread(findDataFile("dnn/street.png", false)); Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false); - float l1 = (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) ? 0.0007 : 0.0; - float lInf = (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) ? 0.011 : 0.0; - + float diffScores = (target == DNN_TARGET_OPENCL_FP16) ? 6e-3 : 0.0; processNet("dnn/MobileNetSSD_deploy.caffemodel", "dnn/MobileNetSSD_deploy.prototxt", - inp, "detection_out", "", l1, lInf); + inp, "detection_out", "", diffScores); } TEST_P(DNNTestNetwork, MobileNet_SSD_v1_TensorFlow) @@ -256,7 +254,8 @@ TEST_P(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages) TEST_P(DNNTestNetwork, OpenFace) { if (backend == DNN_BACKEND_HALIDE || - backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU) + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16) || + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)) throw SkipTestException(""); processNet("dnn/openface_nn4.small2.v1.t7", "", Size(96, 96), ""); } @@ -296,6 +295,20 @@ TEST_P(DNNTestNetwork, DenseNet_121) processNet("dnn/DenseNet_121.caffemodel", "dnn/DenseNet_121.prototxt", Size(224, 224), "", "caffe"); } +TEST_P(DNNTestNetwork, FastNeuralStyle_eccv16) +{ + if (backend == DNN_BACKEND_HALIDE || + (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) || + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)) + throw SkipTestException(""); + Mat img = imread(findDataFile("dnn/googlenet_1.png", false)); + Mat inp = blobFromImage(img, 1.0, Size(320, 240), Scalar(103.939, 116.779, 123.68), false, false); + // Output image has values in range [-143.526, 148.539]. + float l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.3 : 4e-5; + float lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 7.0 : 2e-3; + processNet("dnn/fast_neural_style_eccv16_starry_night.t7", "", inp, "", "", l1, lInf); +} + const tuple testCases[] = { #ifdef HAVE_HALIDE tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU), diff --git a/modules/dnn/test/test_common.hpp b/modules/dnn/test/test_common.hpp index 519bf7131c..ec43f3e046 100644 --- a/modules/dnn/test/test_common.hpp +++ b/modules/dnn/test/test_common.hpp @@ -157,7 +157,8 @@ static inline bool checkMyriadTarget() net.addLayerToPrev("testLayer", "Identity", lp); net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE); net.setPreferableTarget(cv::dnn::DNN_TARGET_MYRIAD); - net.setInput(cv::Mat::zeros(1, 1, CV_32FC1)); + static int inpDims[] = {1, 2, 3, 4}; + net.setInput(cv::Mat(4, &inpDims[0], CV_32FC1, cv::Scalar(0))); try { net.forward(); diff --git a/modules/dnn/test/test_darknet_importer.cpp b/modules/dnn/test/test_darknet_importer.cpp index 3b6ca2a9b8..2232aa4ff3 100644 --- a/modules/dnn/test/test_darknet_importer.cpp +++ b/modules/dnn/test/test_darknet_importer.cpp @@ -135,8 +135,6 @@ TEST_P(Test_Darknet_nets, YoloVoc) { int backendId = get<0>(GetParam()); int targetId = get<1>(GetParam()); - if (backendId == DNN_BACKEND_INFERENCE_ENGINE && targetId == DNN_TARGET_MYRIAD) - throw SkipTestException(""); std::vector outNames(1, "detection_out"); std::vector classIds(3); @@ -145,7 +143,7 @@ TEST_P(Test_Darknet_nets, YoloVoc) classIds[0] = 6; confidences[0] = 0.750469f; boxes[0] = Rect2d(0.577374, 0.127391, 0.325575, 0.173418); // a car classIds[1] = 1; confidences[1] = 0.780879f; boxes[1] = Rect2d(0.270762, 0.264102, 0.461713, 0.48131); // a bicycle classIds[2] = 11; confidences[2] = 0.901615f; boxes[2] = Rect2d(0.1386, 0.338509, 0.282737, 0.60028); // a dog - double scoreDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 7e-3 : 8e-5; + double scoreDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 1e-2 : 8e-5; double iouDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.013 : 3e-5; testDarknetModel("yolo-voc.cfg", "yolo-voc.weights", outNames, classIds, confidences, boxes, backendId, targetId, scoreDiff, iouDiff); @@ -230,4 +228,9 @@ TEST(Test_Darknet, upsample) testDarknetLayer("upsample"); } +TEST(Test_Darknet, avgpool_softmax) +{ + testDarknetLayer("avgpool_softmax"); +} + }} // namespace diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 111f354fe4..963206bd73 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -201,6 +201,13 @@ TEST(Layer_Test_Reshape, Accuracy) testReshape(MatShape(inp, inp + 4), MatShape(out, out + 2), 0, -1, MatShape(mask, mask + 2)); } + { + int inp[] = {1, 2, 3}; + int out[] = {3, 1, 2}; + int mask[] = {3, 1, 2}; + testReshape(MatShape(inp, inp + 3), MatShape(out, out + 3), 0, -1, + MatShape(mask, mask + 3)); + } } TEST(Layer_Test_BatchNorm, Accuracy) @@ -925,6 +932,10 @@ TEST(Layer_Test_Convolution_DLDT, Accuracy) Mat out = net.forward(); normAssert(outDefault, out); + + std::vector outLayers = net.getUnconnectedOutLayers(); + ASSERT_EQ(net.getLayer(outLayers[0])->name, "output_merge"); + ASSERT_EQ(net.getLayer(outLayers[0])->type, "Concat"); } // 1. Create a .prototxt file with the following network: @@ -1137,11 +1148,96 @@ private: int outWidth, outHeight, zoomFactor; }; -TEST(Layer_Test_Interp, Accuracy) +TEST(Layer_Test_Interp_custom, Accuracy) { CV_DNN_REGISTER_LAYER_CLASS(Interp, InterpLayer); testLayerUsingCaffeModels("layer_interp", DNN_TARGET_CPU, false, false); LayerFactory::unregisterLayer("Interp"); } +TEST(Layer_Test_Interp, Accuracy) +{ + testLayerUsingCaffeModels("layer_interp", DNN_TARGET_CPU, false, false); +} + +TEST(Layer_Test_PoolingIndices, Accuracy) +{ + Net net; + + LayerParams lp; + lp.set("pool", "max"); + lp.set("kernel_w", 2); + lp.set("kernel_h", 2); + lp.set("stride_w", 2); + lp.set("stride_h", 2); + lp.set("pad_w", 0); + lp.set("pad_h", 0); + lp.name = "testLayer.name"; // This test also checks that OpenCV lets use names with dots. + lp.type = "Pooling"; + net.addLayerToPrev(lp.name, lp.type, lp); + + Mat inp(10, 10, CV_8U); + randu(inp, 0, 255); + + Mat maxValues(5, 5, CV_32F, Scalar(-1)), indices(5, 5, CV_32F, Scalar(-1)); + for (int y = 0; y < 10; ++y) + { + int dstY = y / 2; + for (int x = 0; x < 10; ++x) + { + int dstX = x / 2; + uint8_t val = inp.at(y, x); + if ((float)inp.at(y, x) > maxValues.at(dstY, dstX)) + { + maxValues.at(dstY, dstX) = val; + indices.at(dstY, dstX) = y * 10 + x; + } + } + } + net.setPreferableBackend(DNN_BACKEND_OPENCV); + net.setInput(blobFromImage(inp)); + + std::vector outputs; + net.forward(outputs, lp.name); + normAssert(maxValues, outputs[0].reshape(1, 5)); + normAssert(indices, outputs[1].reshape(1, 5)); +} + +typedef testing::TestWithParam > Layer_Test_ShuffleChannel; +TEST_P(Layer_Test_ShuffleChannel, Accuracy) +{ + Vec4i inpShapeVec = get<0>(GetParam()); + int group = get<1>(GetParam()); + ASSERT_EQ(inpShapeVec[1] % group, 0); + const int groupSize = inpShapeVec[1] / group; + + Net net; + LayerParams lp; + lp.set("group", group); + lp.type = "ShuffleChannel"; + lp.name = "testLayer"; + net.addLayerToPrev(lp.name, lp.type, lp); + + const int inpShape[] = {inpShapeVec[0], inpShapeVec[1], inpShapeVec[2], inpShapeVec[3]}; + Mat inp(4, inpShape, CV_32F); + randu(inp, 0, 255); + + net.setInput(inp); + Mat out = net.forward(); + + for (int n = 0; n < inpShapeVec[0]; ++n) + { + for (int c = 0; c < inpShapeVec[1]; ++c) + { + Mat outChannel = getPlane(out, n, c); + Mat inpChannel = getPlane(inp, n, groupSize * (c % group) + c / group); + normAssert(outChannel, inpChannel); + } + } +} +INSTANTIATE_TEST_CASE_P(/**/, Layer_Test_ShuffleChannel, Combine( +/*input shape*/ Values(Vec4i(1, 6, 5, 7), Vec4i(3, 12, 1, 4)), +/*group*/ Values(1, 2, 3, 6) +)); + }} // namespace diff --git a/modules/dnn/test/test_tf_importer.cpp b/modules/dnn/test/test_tf_importer.cpp index 4f024114ef..408782233c 100644 --- a/modules/dnn/test/test_tf_importer.cpp +++ b/modules/dnn/test/test_tf_importer.cpp @@ -127,6 +127,7 @@ TEST_P(Test_TensorFlow_layers, conv) runTensorFlowNet("atrous_conv2d_same", targetId); runTensorFlowNet("depthwise_conv2d", targetId); runTensorFlowNet("keras_atrous_conv2d_same", targetId); + runTensorFlowNet("conv_pool_nchw", targetId); } TEST_P(Test_TensorFlow_layers, padding) @@ -142,9 +143,10 @@ TEST_P(Test_TensorFlow_layers, eltwise_add_mul) runTensorFlowNet("eltwise_add_mul", GetParam()); } -TEST_P(Test_TensorFlow_layers, pad_and_concat) +TEST_P(Test_TensorFlow_layers, concat) { runTensorFlowNet("pad_and_concat", GetParam()); + runTensorFlowNet("concat_axis_1", GetParam()); } TEST_P(Test_TensorFlow_layers, batch_norm) @@ -196,6 +198,7 @@ TEST_P(Test_TensorFlow_layers, reshape) { int targetId = GetParam(); runTensorFlowNet("shift_reshape_no_reorder", targetId); + runTensorFlowNet("reshape_no_reorder", targetId); runTensorFlowNet("reshape_reduce", targetId); runTensorFlowNet("flatten", targetId, true); runTensorFlowNet("unfused_flatten", targetId); @@ -415,6 +418,7 @@ TEST(Test_TensorFlow, softmax) TEST(Test_TensorFlow, relu6) { runTensorFlowNet("keras_relu6"); + runTensorFlowNet("keras_relu6", DNN_TARGET_CPU, /*hasText*/ true); } TEST(Test_TensorFlow, keras_mobilenet_head) @@ -439,4 +443,20 @@ TEST(Test_TensorFlow, resize_bilinear) runTensorFlowNet("resize_bilinear_factor"); } +TEST(Test_TensorFlow, two_inputs) +{ + Net net = readNet(path("two_inputs_net.pbtxt")); + net.setPreferableBackend(DNN_BACKEND_OPENCV); + + Mat firstInput(2, 3, CV_32FC1), secondInput(2, 3, CV_32FC1); + randu(firstInput, -1, 1); + randu(secondInput, -1, 1); + + net.setInput(firstInput, "first_input"); + net.setInput(secondInput, "second_input"); + Mat out = net.forward(); + + normAssert(out, firstInput + secondInput); +} + } diff --git a/modules/dnn/test/test_torch_importer.cpp b/modules/dnn/test/test_torch_importer.cpp index cbff3cae37..5fe3fe121b 100644 --- a/modules/dnn/test/test_torch_importer.cpp +++ b/modules/dnn/test/test_torch_importer.cpp @@ -87,7 +87,7 @@ static void runTorchNet(String prefix, int targetId = DNN_TARGET_CPU, String out if (outLayerName.empty()) outLayerName = net.getLayerNames().back(); - net.setInput(inp, "0"); + net.setInput(inp); std::vector outBlobs; net.forward(outBlobs, outLayerName); normAssert(outRef, outBlobs[0]); @@ -296,6 +296,7 @@ TEST_P(Test_Torch_nets, FastNeuralStyle_accuracy) Mat inputBlob = blobFromImage(img, 1.0, Size(), Scalar(103.939, 116.779, 123.68), false); net.setInput(inputBlob); + net.setPreferableBackend(DNN_BACKEND_OPENCV); Mat out = net.forward(); // Deprocessing. diff --git a/modules/imgcodecs/src/grfmt_sunras.cpp b/modules/imgcodecs/src/grfmt_sunras.cpp index 6398db567f..b419b7795a 100644 --- a/modules/imgcodecs/src/grfmt_sunras.cpp +++ b/modules/imgcodecs/src/grfmt_sunras.cpp @@ -175,8 +175,6 @@ bool SunRasterDecoder::readData( Mat& img ) AutoBuffer _src(src_pitch + 32); uchar* src = _src; - AutoBuffer _bgr(m_width*3 + 32); - uchar* bgr = _bgr; if( !color && m_maptype == RMT_EQUAL_RGB ) CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp ); @@ -340,16 +338,18 @@ bad_decoding_end: case 24: for( y = 0; y < m_height; y++, data += step ) { - m_strm.getBytes( color ? data : bgr, src_pitch ); + m_strm.getBytes(src, src_pitch ); if( color ) { if( m_type == RAS_FORMAT_RGB ) - icvCvt_RGB2BGR_8u_C3R( data, 0, data, 0, cvSize(m_width,1) ); + icvCvt_RGB2BGR_8u_C3R(src, 0, data, 0, cvSize(m_width,1) ); + else + memcpy(data, src, std::min(step, (size_t)src_pitch)); } else { - icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1), + icvCvt_BGR2Gray_8u_C3C1R(src, 0, data, 0, cvSize(m_width,1), m_type == RAS_FORMAT_RGB ? 2 : 0 ); } } diff --git a/modules/objdetect/include/opencv2/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect.hpp index 8db0789e6c..7c36baccb9 100644 --- a/modules/objdetect/include/opencv2/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect.hpp @@ -670,6 +670,14 @@ public: void groupRectangles(std::vector& rectList, std::vector& weights, int groupThreshold, double eps) const; }; +/** @brief Detect QR code in image and return minimum area of quadrangle that describes QR code. + @param in Matrix of the type CV_8UC1 containing an image where QR code are detected. + @param points Output vector of vertices of a quadrangle of minimal area that describes QR code. + @param eps_x Epsilon neighborhood, which allows you to determine the horizontal pattern of the scheme 1:1:3:1:1 according to QR code standard. + @param eps_y Epsilon neighborhood, which allows you to determine the vertical pattern of the scheme 1:1:3:1:1 according to QR code standard. + */ +CV_EXPORTS bool detectQRCode(InputArray in, std::vector &points, double eps_x = 0.2, double eps_y = 0.1); + //! @} objdetect } diff --git a/modules/objdetect/src/qrcode.cpp b/modules/objdetect/src/qrcode.cpp new file mode 100644 index 0000000000..f7c40a744f --- /dev/null +++ b/modules/objdetect/src/qrcode.cpp @@ -0,0 +1,775 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Copyright (C) 2018, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. + +#include "precomp.hpp" +#include "opencv2/objdetect.hpp" +// #include "opencv2/calib3d.hpp" + +#include +#include +#include + +namespace cv +{ +class QRDecode +{ + public: + void init(Mat src, double eps_vertical_ = 0.19, double eps_horizontal_ = 0.09); + void binarization(); + bool localization(); + bool transformation(); + Mat getBinBarcode() { return bin_barcode; } + Mat getLocalizationBarcode() { return local_barcode; } + Mat getTransformationBarcode() { return transform_barcode; } + std::vector getTransformationPoints() { return transformation_points; } + Mat getStraightBarcode() { return straight_barcode; } + protected: + std::vector searchVerticalLines(); + std::vector separateHorizontalLines(std::vector list_lines); + std::vector pointClustering(std::vector list_lines); + void fixationPoints(std::vector &local_point, std::vector &local_len); + Point getTransformationPoint(Point left, Point center, double cos_angle_rotation, + bool right_rotate = true); + Point intersectionLines(Point a1, Point a2, Point b1, Point b2); + std::vector getQuadrilateral(std::vector angle_list); + double getQuadrilateralArea(Point a, Point b, Point c, Point d); + double getCosVectors(Point a, Point b, Point c); + + Mat barcode, bin_barcode, local_barcode, transform_barcode, straight_barcode; + std::vector localization_points, transformation_points; + std::vector localization_length; + double experimental_area; + + double eps_vertical, eps_horizontal; + std::vector result; + std::vector test_lines; + uint8_t next_pixel, future_pixel; + double length, weight; +}; + +void QRDecode::init(Mat src, double eps_vertical_, double eps_horizontal_) +{ + barcode = src; + eps_vertical = eps_vertical_; + eps_horizontal = eps_horizontal_; +} + +void QRDecode::binarization() +{ + Mat filter_barcode; + GaussianBlur(barcode, filter_barcode, Size(3, 3), 0); + threshold(filter_barcode, bin_barcode, 0, 255, THRESH_BINARY + THRESH_OTSU); +} + +bool QRDecode::localization() +{ + cvtColor(bin_barcode, local_barcode, COLOR_GRAY2RGB); + Point begin, end; + + std::vector list_lines_x = searchVerticalLines(); + std::vector list_lines_y = separateHorizontalLines(list_lines_x); + std::vector result_point = pointClustering(list_lines_y); + for (int i = 0; i < 3; i++) + { + localization_points.push_back( + Point(static_cast(result_point[i][0]), + static_cast(result_point[i][1] + result_point[i][2]))); + localization_length.push_back(result_point[i][2]); + } + + fixationPoints(localization_points, localization_length); + + + if (localization_points.size() != 3) { return false; } + return true; + +} + +std::vector QRDecode::searchVerticalLines() +{ + result.clear(); + int temp_length = 0; + + for (int x = 0; x < bin_barcode.rows; x++) + { + for (int y = 0; y < bin_barcode.cols; y++) + { + if (bin_barcode.at(x, y) > 0) { continue; } + + // --------------- Search vertical lines --------------- // + + test_lines.clear(); + future_pixel = 255; + + for (int i = x; i < bin_barcode.rows - 1; i++) + { + next_pixel = bin_barcode.at(i + 1, y); + temp_length++; + if (next_pixel == future_pixel) + { + future_pixel = 255 - future_pixel; + test_lines.push_back(temp_length); + temp_length = 0; + if (test_lines.size() == 5) { break; } + } + } + + // --------------- Compute vertical lines --------------- // + + if (test_lines.size() == 5) + { + length = 0.0; weight = 0.0; + + for (size_t i = 0; i < test_lines.size(); i++) { length += test_lines[i]; } + + for (size_t i = 0; i < test_lines.size(); i++) + { + if (i == 2) { weight += abs((test_lines[i] / length) - 3.0/7.0); } + else { weight += abs((test_lines[i] / length) - 1.0/7.0); } + } + + if (weight < eps_vertical) + { + Vec3d line; + line[0] = x; line[1] = y, line[2] = length; + result.push_back(line); + } + } + } + } + return result; +} + +std::vector QRDecode::separateHorizontalLines(std::vector list_lines) +{ + result.clear(); + int temp_length = 0; + int x, y; + + for (size_t pnt = 0; pnt < list_lines.size(); pnt++) + { + x = static_cast(list_lines[pnt][0] + list_lines[pnt][2] / 2); + y = static_cast(list_lines[pnt][1]); + + // --------------- Search horizontal up-lines --------------- // + test_lines.clear(); + future_pixel = 255; + + for (int j = y; j < bin_barcode.cols - 1; j++) + { + next_pixel = bin_barcode.at(x, j + 1); + temp_length++; + if (next_pixel == future_pixel) + { + future_pixel = 255 - future_pixel; + test_lines.push_back(temp_length); + temp_length = 0; + if (test_lines.size() == 3) { break; } + } + } + + // --------------- Search horizontal down-lines --------------- // + future_pixel = 255; + + for (int j = y; j >= 1; j--) + { + next_pixel = bin_barcode.at(x, j - 1); + temp_length++; + if (next_pixel == future_pixel) + { + future_pixel = 255 - future_pixel; + test_lines.push_back(temp_length); + temp_length = 0; + if (test_lines.size() == 6) { break; } + } + } + + // --------------- Compute horizontal lines --------------- // + + if (test_lines.size() == 6) + { + length = 0.0; weight = 0.0; + + for (size_t i = 0; i < test_lines.size(); i++) { length += test_lines[i]; } + + for (size_t i = 0; i < test_lines.size(); i++) + { + if (i % 3 == 0) { weight += abs((test_lines[i] / length) - 3.0/14.0); } + else { weight += abs((test_lines[i] / length) - 1.0/ 7.0); } + } + } + + if(weight < eps_horizontal) + { + result.push_back(list_lines[pnt]); + } + } + return result; +} + +std::vector QRDecode::pointClustering(std::vector list_lines) +{ + std::vector centers; + std::vector clusters[3]; + double weight_clusters[3] = {0.0, 0.0, 0.0}; + Point basis[3], temp_pnt; + double temp_norm = 0.0, temp_compute_norm, distance[3]; + + basis[0] = Point(static_cast(list_lines[0][1]), static_cast(list_lines[0][0])); + for (size_t i = 1; i < list_lines.size(); i++) + { + temp_pnt = Point(static_cast(list_lines[i][1]), static_cast(list_lines[i][0])); + temp_compute_norm = norm(basis[0] - temp_pnt); + if (temp_norm < temp_compute_norm) + { + basis[1] = temp_pnt; + temp_norm = temp_compute_norm; + } + } + + for (size_t i = 1; i < list_lines.size(); i++) + { + temp_pnt = Point(static_cast(list_lines[i][1]), static_cast(list_lines[i][0])); + temp_compute_norm = norm(basis[0] - temp_pnt) + norm(basis[1] - temp_pnt); + if (temp_norm < temp_compute_norm) + { + basis[2] = temp_pnt; + temp_norm = temp_compute_norm; + } + } + + for (size_t i = 0; i < list_lines.size(); i++) + { + temp_pnt = Point(static_cast(list_lines[i][1]), static_cast(list_lines[i][0])); + distance[0] = norm(basis[0] - temp_pnt); + distance[1] = norm(basis[1] - temp_pnt); + distance[2] = norm(basis[2] - temp_pnt); + if (distance[0] < distance[1] && distance[0] < distance[2]) + { + clusters[0].push_back(temp_pnt); + weight_clusters[0] += list_lines[i][2]; + } + else if (distance[1] < distance[0] && distance[1] < distance[2]) + { + clusters[1].push_back(temp_pnt); + weight_clusters[1] += list_lines[i][2]; + } + else + { + clusters[2].push_back(temp_pnt); + weight_clusters[2] += list_lines[i][2]; + } + } + + for (int i = 0; i < 3; i++) + { + basis[i] = Point(0, 0); + for (size_t j = 0; j < clusters[i].size(); j++) { basis[i] += clusters[i][j]; } + basis[i] = basis[i] / static_cast(clusters[i].size()); + weight = weight_clusters[i] / (2 * clusters[i].size()); + centers.push_back(Vec3d(basis[i].x, basis[i].y, weight)); + } + + return centers; +} + +void QRDecode::fixationPoints(std::vector &local_point, std::vector &local_len) +{ + double cos_angles[3], norm_triangl[3]; + + norm_triangl[0] = norm(local_point[1] - local_point[2]); + norm_triangl[1] = norm(local_point[0] - local_point[2]); + norm_triangl[2] = norm(local_point[1] - local_point[0]); + + cos_angles[0] = (pow(norm_triangl[1], 2) + pow(norm_triangl[2], 2) - pow(norm_triangl[0], 2)) + / (2 * norm_triangl[1] * norm_triangl[2]); + cos_angles[1] = (pow(norm_triangl[0], 2) + pow(norm_triangl[2], 2) - pow(norm_triangl[1], 2)) + / (2 * norm_triangl[0] * norm_triangl[2]); + cos_angles[2] = (pow(norm_triangl[0], 2) + pow(norm_triangl[1], 2) - pow(norm_triangl[2], 2)) + / (2 * norm_triangl[0] * norm_triangl[1]); + + int i_min_cos = + (cos_angles[0] < cos_angles[1] && cos_angles[0] < cos_angles[2]) ? 0 : + (cos_angles[1] < cos_angles[0] && cos_angles[1] < cos_angles[2]) ? 1 : 2; + + Point temp_pnt; + double tmp_len; + temp_pnt = local_point[0]; + tmp_len = local_len[0]; + local_point[0] = local_point[i_min_cos]; + local_len[0] = local_len[i_min_cos]; + local_point[i_min_cos] = temp_pnt; + local_len[i_min_cos] = tmp_len; + + Mat vector_mult(Size(3, 3), CV_32FC1); + vector_mult.at(0, 0) = 1; + vector_mult.at(1, 0) = 1; + vector_mult.at(2, 0) = 1; + vector_mult.at(0, 1) = static_cast((local_point[1] - local_point[0]).x); + vector_mult.at(1, 1) = static_cast((local_point[1] - local_point[0]).y); + vector_mult.at(0, 2) = static_cast((local_point[2] - local_point[0]).x); + vector_mult.at(1, 2) = static_cast((local_point[2] - local_point[0]).y); + double res_vect_mult = determinant(vector_mult); + if (res_vect_mult < 0) + { + temp_pnt = local_point[1]; + tmp_len = local_len[1]; + local_point[1] = local_point[2]; + local_len[1] = local_len[2]; + local_point[2] = temp_pnt; + local_len[2] = tmp_len; + } +} + +bool QRDecode::transformation() +{ + cvtColor(bin_barcode, transform_barcode, COLOR_GRAY2RGB); + if (localization_points.size() != 3) { return false; } + + Point red = localization_points[0]; + Point green = localization_points[1]; + Point blue = localization_points[2]; + Point adj_b_r_pnt, adj_r_b_pnt, adj_g_r_pnt, adj_r_g_pnt; + Point line_r_b_pnt, line_r_g_pnt, norm_r_b_pnt, norm_r_g_pnt; + adj_b_r_pnt = getTransformationPoint(blue, red, -1); + adj_r_b_pnt = getTransformationPoint(red, blue, -1); + adj_g_r_pnt = getTransformationPoint(green, red, -1); + adj_r_g_pnt = getTransformationPoint(red, green, -1); + line_r_b_pnt = getTransformationPoint(red, blue, -0.91); + line_r_g_pnt = getTransformationPoint(red, green, -0.91); + norm_r_b_pnt = getTransformationPoint(red, blue, 0.0, true); + norm_r_g_pnt = getTransformationPoint(red, green, 0.0, false); + + transformation_points.push_back(intersectionLines( + adj_r_g_pnt, line_r_g_pnt, adj_r_b_pnt, line_r_b_pnt)); + transformation_points.push_back(intersectionLines( + adj_b_r_pnt, norm_r_g_pnt, adj_r_g_pnt, line_r_g_pnt)); + transformation_points.push_back(intersectionLines( + norm_r_b_pnt, adj_g_r_pnt, adj_b_r_pnt, norm_r_g_pnt)); + transformation_points.push_back(intersectionLines( + norm_r_b_pnt, adj_g_r_pnt, adj_r_b_pnt, line_r_b_pnt)); + + experimental_area = getQuadrilateralArea(transformation_points[0], + transformation_points[1], + transformation_points[2], + transformation_points[3]); + std::vector quadrilateral = getQuadrilateral(transformation_points); + transformation_points = quadrilateral; + + int max_length_norm = -1; + size_t transform_size = transformation_points.size(); + for (size_t i = 0; i < transform_size; i++) + { + int len_norm = static_cast(norm(transformation_points[i % transform_size] - + transformation_points[(i + 1) % transform_size])); + if (max_length_norm < len_norm) { max_length_norm = len_norm; } + } + + std::vector perspective_points; + perspective_points.push_back(Point(0, 0)); + perspective_points.push_back(Point(0, max_length_norm)); + perspective_points.push_back(Point(max_length_norm, max_length_norm)); + perspective_points.push_back(Point(max_length_norm, 0)); + + // warpPerspective(bin_barcode, straight_barcode, + // findHomography(transformation_points, perspective_points), + // Size(max_length_norm, max_length_norm)); + return true; +} + +Point QRDecode::getTransformationPoint(Point left, Point center, double cos_angle_rotation, + bool right_rotate) +{ + Point temp_pnt, prev_pnt(0, 0), next_pnt, start_pnt(center); + double temp_delta, min_delta; + int steps = 0; + + future_pixel = 255; + while(true) + { + min_delta = std::numeric_limits::max(); + for (int i = -1; i < 2; i++) + { + for (int j = -1; j < 2; j++) + { + if (i == 0 && j == 0) { continue; } + temp_pnt = Point(start_pnt.x + i, start_pnt.y + j); + temp_delta = abs(getCosVectors(left, center, temp_pnt) - cos_angle_rotation); + if (temp_delta < min_delta && prev_pnt != temp_pnt) + { + next_pnt = temp_pnt; + min_delta = temp_delta; + } + } + } + prev_pnt = start_pnt; + start_pnt = next_pnt; + next_pixel = bin_barcode.at(start_pnt.y, start_pnt.x); + if (next_pixel == future_pixel) + { + future_pixel = 255 - future_pixel; + steps++; + if (steps == 3) { break; } + } + } + + if (cos_angle_rotation == 0.0) + { + Mat vector_mult(Size(3, 3), CV_32FC1); + vector_mult.at(0, 0) = 1; + vector_mult.at(1, 0) = 1; + vector_mult.at(2, 0) = 1; + vector_mult.at(0, 1) = static_cast((left - center).x); + vector_mult.at(1, 1) = static_cast((left - center).y); + vector_mult.at(0, 2) = static_cast((left - start_pnt).x); + vector_mult.at(1, 2) = static_cast((left - start_pnt).y); + double res_vect_mult = determinant(vector_mult); + if (( right_rotate && res_vect_mult < 0) || + (!right_rotate && res_vect_mult > 0)) + { + start_pnt = getTransformationPoint(start_pnt, center, -1); + } + } + + return start_pnt; +} + +Point QRDecode::intersectionLines(Point a1, Point a2, Point b1, Point b2) +{ + Point result_square_angle( + static_cast( + static_cast + ((a1.x * a2.y - a1.y * a2.x) * (b1.x - b2.x) - + (b1.x * b2.y - b1.y * b2.x) * (a1.x - a2.x)) / + ((a1.x - a2.x) * (b1.y - b2.y) - + (a1.y - a2.y) * (b1.x - b2.x))), + static_cast( + static_cast + ((a1.x * a2.y - a1.y * a2.x) * (b1.y - b2.y) - + (b1.x * b2.y - b1.y * b2.x) * (a1.y - a2.y)) / + ((a1.x - a2.x) * (b1.y - b2.y) - + (a1.y - a2.y) * (b1.x - b2.x))) + ); + return result_square_angle; +} + +std::vector QRDecode::getQuadrilateral(std::vector angle_list) +{ + size_t angle_size = angle_list.size(); + uint8_t value, mask_value; + Mat mask(bin_barcode.rows + 2, bin_barcode.cols + 2, CV_8UC1); + for (size_t i = 0; i < angle_size; i++) + { + LineIterator line_iter(bin_barcode, angle_list[ i % angle_size], + angle_list[(i + 1) % angle_size]); + for(int j = 0; j < line_iter.count; j++, ++line_iter) + { + value = bin_barcode.at(line_iter.pos()); + mask_value = mask.at(line_iter.pos() + Point(1, 1)); + if (value == 0 && mask_value == 0) + { + floodFill(bin_barcode, mask, line_iter.pos(), 255); + } + } + } + std::vector locations; + Mat mask_roi = mask(Range(1, bin_barcode.rows - 1), + Range(1, bin_barcode.cols - 1)); + + cv::findNonZero(mask_roi, locations); + + for (size_t i = 0; i < angle_list.size(); i++) + { + locations.push_back(angle_list[i]); + } + + std::vector< std::vector > hull(1), approx_hull(1); + convexHull(Mat(locations), hull[0]); + int hull_size = static_cast(hull[0].size()); + + Point min_pnt; + + std::vector min_abc; + double min_abs_cos_abc, abs_cos_abc; + for (int count = 0; count < 4; count++) + { + min_abs_cos_abc = std::numeric_limits::max(); + for (int i = 0; i < hull_size; i++) + { + Point a = hull[0][ i % hull_size]; + Point b = hull[0][(i + 1) % hull_size]; + Point c = hull[0][(i + 2) % hull_size]; + abs_cos_abc = abs(getCosVectors(a, b, c)); + + bool flag_detect = true; + for (size_t j = 0; j < min_abc.size(); j++) + { + if (min_abc[j] == b) { flag_detect = false; break; } + } + + if (flag_detect && (abs_cos_abc < min_abs_cos_abc)) + { + min_pnt = b; + min_abs_cos_abc = abs_cos_abc; + } + } + min_abc.push_back(min_pnt); + } + + + int min_abc_size = static_cast(min_abc.size()); + std::vector index_min_abc(min_abc_size); + for (int i = 0; i < min_abc_size; i++) + { + for (int j = 0; j < hull_size; j++) + { + if (hull[0][j] == min_abc[i]) { index_min_abc[i] = j; break; } + } + } + + std::vector result_hull_point(angle_size); + double min_norm, temp_norm; + for (size_t i = 0; i < angle_size; i++) + { + min_norm = std::numeric_limits::max(); + Point closest_pnt; + for (int j = 0; j < min_abc_size; j++) + { + if (min_norm > norm(hull[0][index_min_abc[j]] - angle_list[i])) + { + min_norm = norm(hull[0][index_min_abc[j]] - angle_list[i]); + closest_pnt = hull[0][index_min_abc[j]]; + } + } + result_hull_point[i] = closest_pnt; + } + + int start_line[2] = {0, 0}, finish_line[2] = {0, 0}, unstable_pnt = 0; + for (int i = 0; i < hull_size; i++) + { + if (result_hull_point[3] == hull[0][i]) { start_line[0] = i; } + if (result_hull_point[2] == hull[0][i]) { finish_line[0] = start_line[1] = i; } + if (result_hull_point[1] == hull[0][i]) { finish_line[1] = i; } + if (result_hull_point[0] == hull[0][i]) { unstable_pnt = i; } + } + + int index_hull, extra_index_hull, next_index_hull, extra_next_index_hull, count_points; + Point result_side_begin[4], result_side_end[4]; + + min_norm = std::numeric_limits::max(); + index_hull = start_line[0]; + count_points = abs(start_line[0] - finish_line[0]); + do + { + if (count_points > hull_size / 2) { next_index_hull = index_hull + 1; } + else { next_index_hull = index_hull - 1; } + + if (next_index_hull == hull_size) { next_index_hull = 0; } + if (next_index_hull == -1) { next_index_hull = hull_size - 1; } + + Point angle_closest_pnt = norm(hull[0][index_hull] - angle_list[2]) > + norm(hull[0][index_hull] - angle_list[3]) ? angle_list[3] : angle_list[2]; + + Point intrsc_line_hull = + intersectionLines(hull[0][index_hull], hull[0][next_index_hull], + angle_list[2], angle_list[3]); + temp_norm = getCosVectors(hull[0][index_hull], intrsc_line_hull, angle_closest_pnt); + if (min_norm > temp_norm && + norm(hull[0][index_hull] - hull[0][next_index_hull]) > + norm(angle_list[2] - angle_list[3]) / 10) + { + min_norm = temp_norm; + result_side_begin[0] = hull[0][index_hull]; + result_side_end[0] = hull[0][next_index_hull]; + } + + + index_hull = next_index_hull; + } + while(index_hull != finish_line[0]); + + if (min_norm == std::numeric_limits::max()) + { + result_side_begin[0] = angle_list[2]; + result_side_end[0] = angle_list[3]; + } + + min_norm = std::numeric_limits::max(); + index_hull = start_line[1]; + count_points = abs(start_line[1] - finish_line[1]); + do + { + if (count_points > hull_size / 2) { next_index_hull = index_hull + 1; } + else { next_index_hull = index_hull - 1; } + + if (next_index_hull == hull_size) { next_index_hull = 0; } + if (next_index_hull == -1) { next_index_hull = hull_size - 1; } + + Point angle_closest_pnt = norm(hull[0][index_hull] - angle_list[1]) > + norm(hull[0][index_hull] - angle_list[2]) ? angle_list[2] : angle_list[1]; + + Point intrsc_line_hull = + intersectionLines(hull[0][index_hull], hull[0][next_index_hull], + angle_list[1], angle_list[2]); + temp_norm = getCosVectors(hull[0][index_hull], intrsc_line_hull, angle_closest_pnt); + if (min_norm > temp_norm && + norm(hull[0][index_hull] - hull[0][next_index_hull]) > + norm(angle_list[1] - angle_list[2]) / 20) + { + min_norm = temp_norm; + result_side_begin[1] = hull[0][index_hull]; + result_side_end[1] = hull[0][next_index_hull]; + } + + + index_hull = next_index_hull; + } + while(index_hull != finish_line[1]); + + if (min_norm == std::numeric_limits::max()) + { + result_side_begin[1] = angle_list[1]; + result_side_end[1] = angle_list[2]; + } + + double test_norm[4] = { 0.0, 0.0, 0.0, 0.0 }; + int test_index[4]; + for (int i = 0; i < 4; i++) + { + test_index[i] = (i < 2) ? static_cast(start_line[0]) + : static_cast(finish_line[1]); + do + { + next_index_hull = ((i + 1) % 2 != 0) ? test_index[i] + 1 : test_index[i] - 1; + if (next_index_hull == hull_size) { next_index_hull = 0; } + if (next_index_hull == -1) { next_index_hull = hull_size - 1; } + test_norm[i] += norm(hull[0][next_index_hull] - hull[0][unstable_pnt]); + test_index[i] = next_index_hull; + } + while(test_index[i] != unstable_pnt); + } + + std::vector result_angle_list(4), test_result_angle_list(4); + double min_area = std::numeric_limits::max(), test_area; + index_hull = start_line[0]; + do + { + if (test_norm[0] < test_norm[1]) { next_index_hull = index_hull + 1; } + else { next_index_hull = index_hull - 1; } + + if (next_index_hull == hull_size) { next_index_hull = 0; } + if (next_index_hull == -1) { next_index_hull = hull_size - 1; } + + extra_index_hull = finish_line[1]; + do + { + if (test_norm[2] < test_norm[3]) { extra_next_index_hull = extra_index_hull + 1; } + else { extra_next_index_hull = extra_index_hull - 1; } + + if (extra_next_index_hull == hull_size) { extra_next_index_hull = 0; } + if (extra_next_index_hull == -1) { extra_next_index_hull = hull_size - 1; } + + test_result_angle_list[0] + = intersectionLines(result_side_begin[0], result_side_end[0], + result_side_begin[1], result_side_end[1]); + test_result_angle_list[1] + = intersectionLines(result_side_begin[1], result_side_end[1], + hull[0][extra_index_hull], hull[0][extra_next_index_hull]); + test_result_angle_list[2] + = intersectionLines(hull[0][extra_index_hull], hull[0][extra_next_index_hull], + hull[0][index_hull], hull[0][next_index_hull]); + test_result_angle_list[3] + = intersectionLines(hull[0][index_hull], hull[0][next_index_hull], + result_side_begin[0], result_side_end[0]); + test_area = getQuadrilateralArea(test_result_angle_list[0], + test_result_angle_list[1], + test_result_angle_list[2], + test_result_angle_list[3]); + if (min_area > test_area) + { + min_area = test_area; + for (size_t i = 0; i < test_result_angle_list.size(); i++) + { + result_angle_list[i] = test_result_angle_list[i]; + } + } + + extra_index_hull = extra_next_index_hull; + } + while(extra_index_hull != unstable_pnt); + + index_hull = next_index_hull; + } + while(index_hull != unstable_pnt); + + if (norm(result_angle_list[0] - angle_list[2]) > + norm(angle_list[2] - angle_list[1]) / 3) { result_angle_list[0] = angle_list[2]; } + + if (norm(result_angle_list[1] - angle_list[1]) > + norm(angle_list[1] - angle_list[0]) / 3) { result_angle_list[1] = angle_list[1]; } + + if (norm(result_angle_list[2] - angle_list[0]) > + norm(angle_list[0] - angle_list[3]) / 3) { result_angle_list[2] = angle_list[0]; } + + if (norm(result_angle_list[3] - angle_list[3]) > + norm(angle_list[3] - angle_list[2]) / 3) { result_angle_list[3] = angle_list[3]; } + + + + return result_angle_list; +} + +// b __________ c +// / | +// / | +// / S | +// / | +// a --------------- d + +double QRDecode::getQuadrilateralArea(Point a, Point b, Point c, Point d) +{ + double length_sides[4], perimeter = 0.0, result_area = 1.0; + length_sides[0] = norm(a - b); length_sides[1] = norm(b - c); + length_sides[2] = norm(c - d); length_sides[3] = norm(d - a); + + for (int i = 0; i < 4; i++) { perimeter += length_sides[i]; } + perimeter /= 2; + + for (int i = 0; i < 4; i++) + { + result_area *= (perimeter - length_sides[i]); + } + + result_area = sqrt(result_area); + + return result_area; +} + +// / | b +// / | +// / | +// a/ | c + +double QRDecode::getCosVectors(Point a, Point b, Point c) +{ + return ((a - b).x * (c - b).x + (a - b).y * (c - b).y) / (norm(a - b) * norm(c - b)); +} + +CV_EXPORTS bool detectQRCode(InputArray in, std::vector &points, double eps_x, double eps_y) +{ + CV_Assert(in.isMat()); + CV_Assert(in.getMat().type() == CV_8UC1); + QRDecode qrdec; + qrdec.init(in.getMat(), eps_x, eps_y); + qrdec.binarization(); + if (!qrdec.localization()) { return false; } + if (!qrdec.transformation()) { return false; } + points = qrdec.getTransformationPoints(); + return true; +} + +} diff --git a/modules/objdetect/test/test_qrcode.cpp b/modules/objdetect/test/test_qrcode.cpp new file mode 100644 index 0000000000..87f5ce525b --- /dev/null +++ b/modules/objdetect/test/test_qrcode.cpp @@ -0,0 +1,74 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" + +namespace opencv_test { namespace { + +TEST(Objdetect_QRCode, regression) +{ + String root = cvtest::TS::ptr()->get_data_path() + "qrcode/"; + // String cascades[] = + // { + // root + "haarcascade_frontalface_alt.xml", + // root + "lbpcascade_frontalface.xml", + // String() + // }; + + // vector objects; + // RNG rng((uint64)-1); + + // for( int i = 0; !cascades[i].empty(); i++ ) + // { + // printf("%d. %s\n", i, cascades[i].c_str()); + // CascadeClassifier cascade(cascades[i]); + // for( int j = 0; j < 100; j++ ) + // { + // int width = rng.uniform(1, 100); + // int height = rng.uniform(1, 100); + // Mat img(height, width, CV_8U); + // randu(img, 0, 256); + // cascade.detectMultiScale(img, objects); + // } + // } +} + +}} // namespace diff --git a/modules/photo/src/seamless_cloning.cpp b/modules/photo/src/seamless_cloning.cpp index 9865d62ab3..16376def62 100644 --- a/modules/photo/src/seamless_cloning.cpp +++ b/modules/photo/src/seamless_cloning.cpp @@ -88,10 +88,6 @@ void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point int minxd = p.x - lenx/2; int minyd = p.y - leny/2; - int maxxd = minxd + lenx; - int maxyd = minyd + leny; - - CV_Assert(minxd >= 0 && minyd >= 0 && maxxd <= dest.rows && maxyd <= dest.cols); Rect roi_d(minxd,minyd,lenx,leny); Rect roi_s(minx,miny,lenx,leny); diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index e16fcbacf2..5a6bf7ef62 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -916,7 +916,7 @@ bool pyopencv_to(PyObject* obj, String& value, const char* name) (void)name; if(!obj || obj == Py_None) return true; - char* str = PyString_AsString(obj); + const char* str = PyString_AsString(obj); if(!str) return false; value = String(str); diff --git a/modules/video/include/opencv2/video/tracking.hpp b/modules/video/include/opencv2/video/tracking.hpp index d397ac7aaf..8e01d1645e 100644 --- a/modules/video/include/opencv2/video/tracking.hpp +++ b/modules/video/include/opencv2/video/tracking.hpp @@ -250,7 +250,9 @@ when fullAffine=false. @sa estimateAffine2D, estimateAffinePartial2D, getAffineTransform, getPerspectiveTransform, findHomography */ -CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine ); +CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine); +CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine, int ransacMaxIters, double ransacGoodRatio, + int ransacSize0); enum diff --git a/modules/video/src/lkpyramid.cpp b/modules/video/src/lkpyramid.cpp index 48f896d4e0..353e356102 100644 --- a/modules/video/src/lkpyramid.cpp +++ b/modules/video/src/lkpyramid.cpp @@ -1412,7 +1412,7 @@ namespace cv { static void -getRTMatrix( const Point2f* a, const Point2f* b, +getRTMatrix( const std::vector a, const std::vector b, int count, Mat& M, bool fullAffine ) { CV_Assert( M.isContinuous() ); @@ -1488,6 +1488,12 @@ getRTMatrix( const Point2f* a, const Point2f* b, } cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullAffine ) +{ + return estimateRigidTransform(src1, src2, fullAffine, 500, 0.5, 3); +} + +cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullAffine, int ransacMaxIters, double ransacGoodRatio, + const int ransacSize0) { CV_INSTRUMENT_REGION() @@ -1495,9 +1501,6 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA const int COUNT = 15; const int WIDTH = 160, HEIGHT = 120; - const int RANSAC_MAX_ITERS = 500; - const int RANSAC_SIZE0 = 3; - const double RANSAC_GOOD_RATIO = 0.5; std::vector pA, pB; std::vector good_idx; @@ -1509,6 +1512,12 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA RNG rng((uint64)-1); int good_count = 0; + if( ransacSize0 < 3 ) + CV_Error( Error::StsBadArg, "ransacSize0 should have value bigger than 2."); + + if( ransacGoodRatio > 1 || ransacGoodRatio < 0) + CV_Error( Error::StsBadArg, "ransacGoodRatio should have value between 0 and 1"); + if( A.size() != B.size() ) CV_Error( Error::StsUnmatchedSizes, "Both input images must have the same size" ); @@ -1597,23 +1606,23 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA good_idx.resize(count); - if( count < RANSAC_SIZE0 ) + if( count < ransacSize0 ) return Mat(); Rect brect = boundingRect(pB); + std::vector a(ransacSize0); + std::vector b(ransacSize0); + // RANSAC stuff: // 1. find the consensus - for( k = 0; k < RANSAC_MAX_ITERS; k++ ) + for( k = 0; k < ransacMaxIters; k++ ) { - int idx[RANSAC_SIZE0]; - Point2f a[RANSAC_SIZE0]; - Point2f b[RANSAC_SIZE0]; - - // choose random 3 non-coplanar points from A & B - for( i = 0; i < RANSAC_SIZE0; i++ ) + std::vector idx(ransacSize0); + // choose random 3 non-complanar points from A & B + for( i = 0; i < ransacSize0; i++ ) { - for( k1 = 0; k1 < RANSAC_MAX_ITERS; k1++ ) + for( k1 = 0; k1 < ransacMaxIters; k1++ ) { idx[i] = rng.uniform(0, count); @@ -1633,7 +1642,7 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA if( j < i ) continue; - if( i+1 == RANSAC_SIZE0 ) + if( i+1 == ransacSize0 ) { // additional check for non-complanar vectors a[0] = pA[idx[0]]; @@ -1657,11 +1666,11 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA break; } - if( k1 >= RANSAC_MAX_ITERS ) + if( k1 >= ransacMaxIters ) break; } - if( i < RANSAC_SIZE0 ) + if( i < ransacSize0 ) continue; // estimate the transformation using 3 points @@ -1675,11 +1684,11 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA good_idx[good_count++] = i; } - if( good_count >= count*RANSAC_GOOD_RATIO ) + if( good_count >= count*ransacGoodRatio ) break; } - if( k >= RANSAC_MAX_ITERS ) + if( k >= ransacMaxIters ) return Mat(); if( good_count < count ) @@ -1692,7 +1701,7 @@ cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullA } } - getRTMatrix( &pA[0], &pB[0], good_count, M, fullAffine ); + getRTMatrix( pA, pB, good_count, M, fullAffine ); M.at(0, 2) /= scale; M.at(1, 2) /= scale; diff --git a/modules/videoio/src/cap_dshow.cpp b/modules/videoio/src/cap_dshow.cpp index f29eb98cc3..3a92a81d49 100644 --- a/modules/videoio/src/cap_dshow.cpp +++ b/modules/videoio/src/cap_dshow.cpp @@ -3220,6 +3220,11 @@ double VideoCapture_DShow::getProperty(int propIdx) const return g_VI.getFourcc(m_index); case CV_CAP_PROP_FPS: return g_VI.getFPS(m_index); + case CV_CAP_PROP_AUTOFOCUS: + // Flags indicate whether or not autofocus is enabled + if (g_VI.getVideoSettingCamera(m_index, CameraControl_Focus, min_value, max_value, stepping_delta, current_value, flags, defaultValue)) + return (double)flags; + return -1; // video filter properties case CV_CAP_PROP_BRIGHTNESS: @@ -3284,6 +3289,7 @@ bool VideoCapture_DShow::setProperty(int propIdx, double propVal) break; case CV_CAP_PROP_FPS: + { int fps = cvRound(propVal); if (fps != g_VI.getFPS(m_index)) { @@ -3297,6 +3303,19 @@ bool VideoCapture_DShow::setProperty(int propIdx, double propVal) return g_VI.isDeviceSetup(m_index); } + case CV_CAP_PROP_AUTOFOCUS: + { + // Flags are required to toggle autofocus or not, but the setProperty interface does not support multiple parameters + bool enabled = cvRound(propVal) == 1; + long minFocus, maxFocus, delta, currentFocus, flags, defaultValue; + if (!g_VI.getVideoSettingCamera(m_index, CameraControl_Focus, minFocus, maxFocus, delta, currentFocus, flags, defaultValue)) + { + return false; + } + return g_VI.setVideoSettingCamera(m_index, CameraControl_Focus, currentFocus, enabled ? CameraControl_Flags_Auto | CameraControl_Flags_Manual : CameraControl_Flags_Manual, enabled ? true : false); + } + } + if (handled) { // a stream setting diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index a0c82ed435..beed7420d3 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -83,6 +83,21 @@ #pragma comment(lib, "Mfreadwrite") #ifdef HAVE_DXVA #pragma comment(lib, "d3d11") +// MFCreateDXGIDeviceManager() is available since Win8 only. +// To avoid OpenCV loading failure on Win7 use dynamic detection of this symbol. +// Details: https://github.com/opencv/opencv/issues/11858 +typedef HRESULT (WINAPI *FN_MFCreateDXGIDeviceManager)(UINT *resetToken, IMFDXGIDeviceManager **ppDeviceManager); +static bool pMFCreateDXGIDeviceManager_initialized = false; +static FN_MFCreateDXGIDeviceManager pMFCreateDXGIDeviceManager = NULL; +static void init_MFCreateDXGIDeviceManager() +{ + HMODULE h = LoadLibraryA("mfplat.dll"); + if (h) + { + pMFCreateDXGIDeviceManager = (FN_MFCreateDXGIDeviceManager)GetProcAddress(h, "MFCreateDXGIDeviceManager"); + } + pMFCreateDXGIDeviceManager_initialized = true; +} #endif #if (WINVER >= 0x0602) // Available since Win 8 #pragma comment(lib, "MinCore_Downlevel") @@ -93,6 +108,8 @@ #include +#include // QISearch + struct IMFMediaType; struct IMFActivate; struct IMFMediaSource; @@ -101,38 +118,6 @@ struct IMFAttributes; namespace { -#ifdef _DEBUG -void DPOprintOut(const wchar_t *format, ...) -{ - int i = 0; - wchar_t *p = NULL; - va_list args; - va_start(args, format); - if (::IsDebuggerPresent()) - { - WCHAR szMsg[512]; - ::StringCchVPrintfW(szMsg, sizeof(szMsg) / sizeof(szMsg[0]), format, args); - ::OutputDebugStringW(szMsg); - } - else - { - if (wcscmp(format, L"%i")) - { - i = va_arg(args, int); - } - if (wcscmp(format, L"%s")) - { - p = va_arg(args, wchar_t *); - } - wprintf(format, i, p); - } - va_end(args); -} -#define DebugPrintOut(...) DPOprintOut(__VA_ARGS__) -#else -#define DebugPrintOut(...) void() -#endif - template class ComPtr { @@ -154,89 +139,36 @@ public: T** operator&() { - assert(p == NULL); + CV_Assert(p == NULL); return p.operator&(); } T* operator->() const { - assert(p != NULL); + CV_Assert(p != NULL); return p.operator->(); } - bool operator!() const - { - return p.operator==(NULL); - } - bool operator==(_In_opt_ T* pT) const - { - return p.operator==(pT); - } - bool operator!=(_In_opt_ T* pT) const - { - return p.operator!=(pT); - } operator bool() { return p.operator!=(NULL); } - T* const* GetAddressOf() const - { - return &p; - } - - T** GetAddressOf() - { - return &p; - } - - T** ReleaseAndGetAddressOf() - { - p.Release(); - return &p; - } - T* Get() const { return p; } - // Attach to an existing interface (does not AddRef) - void Attach(_In_opt_ T* p2) + void Release() { - p.Attach(p2); - } - // Detach the interface (does not Release) - T* Detach() - { - return p.Detach(); - } - _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) - { - assert(ppT != NULL); - if (ppT == NULL) - return E_POINTER; - *ppT = p; - if (p != NULL) - p->AddRef(); - return S_OK; - } - - void Reset() - { - p.Release(); + if (p) + p.Release(); } // query for U interface template - HRESULT As(_Inout_ U** lp) const + HRESULT As(_Out_ ComPtr& lp) const { - return p->QueryInterface(__uuidof(U), reinterpret_cast(lp)); - } - // query for U interface - template - HRESULT As(_Out_ ComPtr* lp) const - { - return p->QueryInterface(__uuidof(U), reinterpret_cast(lp->ReleaseAndGetAddressOf())); + lp.Release(); + return p->QueryInterface(__uuidof(U), reinterpret_cast((T**)&lp)); } private: _COM_SMARTPTR_TYPEDEF(T, __uuidof(T)); @@ -680,6 +612,77 @@ void MediaType::Clear() } +class SourceReaderCB : public IMFSourceReaderCallback +{ +public: + SourceReaderCB() : + m_nRefCount(1), m_hEvent(CreateEvent(NULL, FALSE, FALSE, NULL)), m_bEOS(FALSE), m_hrStatus(S_OK), m_dwStreamIndex(0) + { + } + + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) CV_OVERRIDE + { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4838) +#endif + static const QITAB qit[] = + { + QITABENT(SourceReaderCB, IMFSourceReaderCallback), + { 0 }, + }; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + return QISearch(this, qit, iid, ppv); + } + STDMETHODIMP_(ULONG) AddRef() CV_OVERRIDE + { + return InterlockedIncrement(&m_nRefCount); + } + STDMETHODIMP_(ULONG) Release() CV_OVERRIDE + { + ULONG uCount = InterlockedDecrement(&m_nRefCount); + if (uCount == 0) + { + delete this; + } + return uCount; + } + + STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample) CV_OVERRIDE; + STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) CV_OVERRIDE + { + return S_OK; + } + STDMETHODIMP OnFlush(DWORD) CV_OVERRIDE + { + return S_OK; + } + + HRESULT Wait(DWORD dwMilliseconds, _ComPtr& videoSample, BOOL& pbEOS); + +private: + // Destructor is private. Caller should call Release. + virtual ~SourceReaderCB() + { + CV_LOG_WARNING(NULL, "terminating async callback"); + } + +public: + long m_nRefCount; // Reference count. + cv::Mutex m_mutex; + HANDLE m_hEvent; + BOOL m_bEOS; + HRESULT m_hrStatus; + + _ComPtr m_reader; + DWORD m_dwStreamIndex; + _ComPtr m_lastSample; +}; + + /******* Capturing video from camera or file via Microsoft Media Foundation **********/ class CvCapture_MSMF : public cv::IVideoCapture { @@ -689,8 +692,6 @@ public: MODE_HW = 1 } MSMFCapture_Mode; CvCapture_MSMF(); - CvCapture_MSMF(int); - CvCapture_MSMF(const cv::String&); virtual ~CvCapture_MSMF(); virtual bool open(int); virtual bool open(const cv::String&); @@ -728,6 +729,7 @@ protected: _ComPtr videoSample; LONGLONG sampleTime; bool isOpen; + _ComPtr readCallback; // non-NULL for "live" streams (camera capture) }; CvCapture_MSMF::CvCapture_MSMF(): @@ -752,8 +754,6 @@ CvCapture_MSMF::CvCapture_MSMF(): { configureHW(true); } -CvCapture_MSMF::CvCapture_MSMF(int index) : CvCapture_MSMF() { open(index); } -CvCapture_MSMF::CvCapture_MSMF(const cv::String& _filename) : CvCapture_MSMF() { open(_filename); } CvCapture_MSMF::~CvCapture_MSMF() { @@ -766,13 +766,12 @@ void CvCapture_MSMF::close() if (isOpen) { isOpen = false; - if (videoSample) - videoSample.Reset(); - if (videoFileSource) - videoFileSource.Reset(); + videoSample.Release(); + videoFileSource.Release(); camid = -1; - filename = ""; + filename.clear(); } + readCallback.Release(); } bool CvCapture_MSMF::configureHW(bool enable) @@ -780,6 +779,10 @@ bool CvCapture_MSMF::configureHW(bool enable) #ifdef HAVE_DXVA if ((enable && D3DMgr && D3DDev) || (!enable && !D3DMgr && !D3DDev)) return true; + if (!pMFCreateDXGIDeviceManager_initialized) + init_MFCreateDXGIDeviceManager(); + if (enable && !pMFCreateDXGIDeviceManager) + return false; bool reopen = isOpen; int prevcam = camid; @@ -791,7 +794,7 @@ bool CvCapture_MSMF::configureHW(bool enable) D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; if (SUCCEEDED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT, - levels, sizeof(levels) / sizeof(*levels), D3D11_SDK_VERSION, D3DDev.GetAddressOf(), NULL, NULL))) + levels, sizeof(levels) / sizeof(*levels), D3D11_SDK_VERSION, &D3DDev, NULL, NULL))) { // NOTE: Getting ready for multi-threaded operation _ComPtr D3DDevMT; @@ -799,29 +802,29 @@ bool CvCapture_MSMF::configureHW(bool enable) if (SUCCEEDED(D3DDev->QueryInterface(IID_PPV_ARGS(&D3DDevMT)))) { D3DDevMT->SetMultithreadProtected(TRUE); - D3DDevMT.Reset(); - if (SUCCEEDED(MFCreateDXGIDeviceManager(&mgrRToken, D3DMgr.GetAddressOf()))) + D3DDevMT.Release(); + if (SUCCEEDED(pMFCreateDXGIDeviceManager(&mgrRToken, &D3DMgr))) { if (SUCCEEDED(D3DMgr->ResetDevice(D3DDev.Get(), mgrRToken))) { captureMode = MODE_HW; - return reopen ? camid >= 0 ? open(prevcam) : open(prevfile.c_str()) : true; + return reopen ? (prevcam >= 0 ? open(prevcam) : open(prevfile.c_str())) : true; } - D3DMgr.Reset(); + D3DMgr.Release(); } } - D3DDev.Reset(); + D3DDev.Release(); } return false; } else { if (D3DMgr) - D3DMgr.Reset(); + D3DMgr.Release(); if (D3DDev) - D3DDev.Reset(); + D3DDev.Release(); captureMode = MODE_SW; - return reopen ? camid >= 0 ? open(prevcam) : open(prevfile.c_str()) : true; + return reopen ? (prevcam >= 0 ? open(prevcam) : open(prevfile.c_str())) : true; } #else return !enable; @@ -941,9 +944,10 @@ bool CvCapture_MSMF::configureOutput(UINT32 width, UINT32 height, double prefFra bool CvCapture_MSMF::open(int _index) { close(); - + if (_index < 0) + return false; _ComPtr msAttr = NULL; - if (SUCCEEDED(MFCreateAttributes(msAttr.GetAddressOf(), 1)) && + if (SUCCEEDED(MFCreateAttributes(&msAttr, 1)) && SUCCEEDED(msAttr->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID @@ -955,7 +959,6 @@ bool CvCapture_MSMF::open(int _index) { if (count > 0) { - _index = std::min(std::max(0, _index), (int)count - 1); for (int ind = 0; ind < (int)count; ind++) { if (ind == _index && ppDevices[ind]) @@ -965,15 +968,23 @@ bool CvCapture_MSMF::open(int _index) _ComPtr srAttr; if (SUCCEEDED(ppDevices[ind]->ActivateObject(__uuidof(IMFMediaSource), (void**)&mSrc)) && mSrc && SUCCEEDED(MFCreateAttributes(&srAttr, 10)) && - SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, false)) && - SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, true))) + SUCCEEDED(srAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, FALSE)) && + SUCCEEDED(srAttr->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE))) { #ifdef HAVE_DXVA if (D3DMgr) srAttr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, D3DMgr.Get()); #endif + readCallback = ComPtr(new SourceReaderCB()); + HRESULT hr = srAttr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, (IMFSourceReaderCallback*)readCallback.Get()); + if (FAILED(hr)) + { + readCallback.Release(); + continue; + } + if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(mSrc.Get(), srAttr.Get(), &videoFileSource))) { isOpen = true; @@ -1045,14 +1056,116 @@ bool CvCapture_MSMF::open(const cv::String& _filename) return isOpen; } + +HRESULT SourceReaderCB::Wait(DWORD dwMilliseconds, _ComPtr& videoSample, BOOL& bEOS) +{ + bEOS = FALSE; + + DWORD dwResult = WaitForSingleObject(m_hEvent, dwMilliseconds); + if (dwResult == WAIT_TIMEOUT) + { + return E_PENDING; + } + else if (dwResult != WAIT_OBJECT_0) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + bEOS = m_bEOS; + if (!bEOS) + { + cv::AutoLock lock(m_mutex); + videoSample = m_lastSample; + CV_Assert(videoSample); + m_lastSample.Release(); + ResetEvent(m_hEvent); // event is auto-reset, but we need this forced reset due time gap between wait() and mutex hold. + } + + return m_hrStatus; +} + +STDMETHODIMP SourceReaderCB::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample) +{ + CV_UNUSED(llTimestamp); + + HRESULT hr = 0; + cv::AutoLock lock(m_mutex); + + if (SUCCEEDED(hrStatus)) + { + if (pSample) + { + CV_LOG_DEBUG(NULL, "videoio(MSMF): got frame at " << llTimestamp); + IMFSample* prev = m_lastSample.Get(); + if (prev) + { + CV_LOG_DEBUG(NULL, "videoio(MSMF): drop frame (not processed)"); + } + m_lastSample = pSample; + } + } + else + { + CV_LOG_WARNING(NULL, "videoio(MSMF): OnReadSample() is called with error status: " << hrStatus); + } + + if (MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags) + { + // Reached the end of the stream. + m_bEOS = true; + } + m_hrStatus = hrStatus; + + if (FAILED(hr = m_reader->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL))) + { + CV_LOG_WARNING(NULL, "videoio(MSMF): async ReadSample() call is failed with error status: " << hr); + m_bEOS = true; + } + + if (pSample || m_bEOS) + { + SetEvent(m_hEvent); + } + return S_OK; +} + + bool CvCapture_MSMF::grabFrame() { CV_TRACE_FUNCTION(); - if (isOpen) + if (readCallback) // async "live" capture mode + { + HRESULT hr = 0; + SourceReaderCB* reader = ((SourceReaderCB*)readCallback.Get()); + if (!reader->m_reader) + { + // Initiate capturing with async callback + reader->m_reader = videoFileSource; + reader->m_dwStreamIndex = dwStreamIndex; + if (FAILED(hr = videoFileSource->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL))) + { + CV_LOG_ERROR(NULL, "videoio(MSMF): can't grab frame - initial async ReadSample() call failed: " << hr); + reader->m_reader = NULL; + return false; + } + } + BOOL bEOS = false; + if (FAILED(hr = reader->Wait(10000, videoSample, bEOS))) // 10 sec + { + CV_LOG_WARNING(NULL, "videoio(MSMF): can't grab frame. Error: " << hr); + return false; + } + if (bEOS) + { + CV_LOG_WARNING(NULL, "videoio(MSMF): EOS signal. Capture stream is lost"); + return false; + } + return true; + } + else if (isOpen) { DWORD streamIndex, flags; - if (videoSample) - videoSample.Reset(); + videoSample.Release(); HRESULT hr; for(;;) { @@ -1074,7 +1187,7 @@ bool CvCapture_MSMF::grabFrame() break; if (flags & MF_SOURCE_READERF_STREAMTICK) { - DebugPrintOut(L"\tStream tick detected. Retrying to grab the frame\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream tick detected. Retrying to grab the frame"); } } @@ -1082,38 +1195,38 @@ bool CvCapture_MSMF::grabFrame() { if (streamIndex != dwStreamIndex) { - DebugPrintOut(L"\tWrong stream readed. Abort capturing\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): Wrong stream readed. Abort capturing"); close(); } else if (flags & MF_SOURCE_READERF_ERROR) { - DebugPrintOut(L"\tStream reading error. Abort capturing\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream reading error. Abort capturing"); close(); } else if (flags & MF_SOURCE_READERF_ALLEFFECTSREMOVED) { - DebugPrintOut(L"\tStream decoding error. Abort capturing\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream decoding error. Abort capturing"); close(); } else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { sampleTime += frameStep; - DebugPrintOut(L"\tEnd of stream detected\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): End of stream detected"); } else { sampleTime += frameStep; if (flags & MF_SOURCE_READERF_NEWSTREAM) { - DebugPrintOut(L"\tNew stream detected\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): New stream detected"); } if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) { - DebugPrintOut(L"\tStream native media type changed\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream native media type changed"); } if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) { - DebugPrintOut(L"\tStream current media type changed\n"); + CV_LOG_DEBUG(NULL, "videoio(MSMF): Stream current media type changed"); } return true; } @@ -1155,7 +1268,7 @@ bool CvCapture_MSMF::retrieveFrame(int, cv::OutputArray frame) _ComPtr buffer2d; if (convertFormat) { - if (SUCCEEDED(buf.As(&buffer2d))) + if (SUCCEEDED(buf.As(buffer2d))) { CV_TRACE_REGION_NEXT("lock2d"); if (SUCCEEDED(buffer2d->Lock2D(&ptr, &pitch))) @@ -1236,8 +1349,7 @@ bool CvCapture_MSMF::setTime(double time, bool rough) if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) && var.vt == VT_UI4 && var.ulVal & MFMEDIASOURCE_CAN_SEEK) { - if (videoSample) - videoSample.Reset(); + videoSample.Release(); bool useGrabbing = time > 0 && !rough && !(var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK); PropVariantClear(&var); sampleTime = (useGrabbing && time >= frameStep) ? (LONGLONG)floor(time + 0.5) - frameStep : (LONGLONG)floor(time + 0.5); @@ -1248,7 +1360,7 @@ bool CvCapture_MSMF::setTime(double time, bool rough) if (resOK && useGrabbing) { LONGLONG timeborder = (LONGLONG)floor(time + 0.5) - frameStep / 2; - do { resOK = grabFrame(); videoSample.Reset(); } while (resOK && sampleTime < timeborder); + do { resOK = grabFrame(); videoSample.Release(); } while (resOK && sampleTime < timeborder); } return resOK; } @@ -1801,17 +1913,25 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) cv::Ptr cv::cvCreateCapture_MSMF( int index ) { - cv::Ptr capture = cv::makePtr(index); - if (capture && capture->isOpened()) - return capture; + cv::Ptr capture = cv::makePtr(); + if (capture) + { + capture->open(index); + if (capture->isOpened()) + return capture; + } return cv::Ptr(); } cv::Ptr cv::cvCreateCapture_MSMF (const cv::String& filename) { - cv::Ptr capture = cv::makePtr(filename); - if (capture && capture->isOpened()) - return capture; + cv::Ptr capture = cv::makePtr(); + if (capture) + { + capture->open(filename); + if (capture->isOpened()) + return capture; + } return cv::Ptr(); } @@ -1825,8 +1945,6 @@ class CvVideoWriter_MSMF : public cv::IVideoWriter { public: CvVideoWriter_MSMF(); - CvVideoWriter_MSMF(const cv::String& filename, int fourcc, - double fps, cv::Size frameSize, bool isColor); virtual ~CvVideoWriter_MSMF(); virtual bool open(const cv::String& filename, int fourcc, double fps, cv::Size frameSize, bool isColor); @@ -1863,7 +1981,6 @@ CvVideoWriter_MSMF::CvVideoWriter_MSMF(): initiated(false) { } -CvVideoWriter_MSMF::CvVideoWriter_MSMF(const cv::String& filename, int fourcc, double fps, cv::Size frameSize, bool isColor) : CvVideoWriter_MSMF() { open(filename, fourcc, fps, frameSize, isColor); } CvVideoWriter_MSMF::~CvVideoWriter_MSMF() { @@ -1990,7 +2107,7 @@ void CvVideoWriter_MSMF::close() { initiated = false; sinkWriter->Finalize(); - sinkWriter.Reset(); + sinkWriter.Release(); } } @@ -2034,9 +2151,13 @@ void CvVideoWriter_MSMF::write(cv::InputArray img) cv::Ptr cv::cvCreateVideoWriter_MSMF( const cv::String& filename, int fourcc, double fps, cv::Size frameSize, int isColor ) { - cv::Ptr writer = cv::makePtr(filename, fourcc, fps, frameSize, isColor != 0); - if (writer && writer->isOpened()) - return writer; + cv::Ptr writer = cv::makePtr(); + if (writer) + { + writer->open(filename, fourcc, fps, frameSize, isColor != 0); + if (writer->isOpened()) + return writer; + } return cv::Ptr(); } diff --git a/modules/videoio/src/cap_openni2.cpp b/modules/videoio/src/cap_openni2.cpp index b4a7808363..9a67a417f6 100644 --- a/modules/videoio/src/cap_openni2.cpp +++ b/modules/videoio/src/cap_openni2.cpp @@ -70,6 +70,35 @@ #include "PS1080.h" /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static cv::Mutex initOpenNI2Mutex; + +struct OpenNI2Initializer +{ +public: + static void init() + { + cv::AutoLock al(initOpenNI2Mutex); + static OpenNI2Initializer initializer; + } + +private: + OpenNI2Initializer() + { + // Initialize and configure the context. + openni::Status status = openni::OpenNI::initialize(); + if (status != openni::STATUS_OK) + { + CV_Error(CV_StsError, std::string("Failed to initialize:") + openni::OpenNI::getExtendedError()); + } + } + + ~OpenNI2Initializer() + { + openni::OpenNI::shutdown(); + } +}; + class CvCapture_OpenNI2 : public CvCapture { public: @@ -107,6 +136,8 @@ protected: static openni::VideoMode defaultStreamOutputMode(int stream); + CvCapture_OpenNI2(int index, const char * filename); + IplImage* retrieveDepthMap(); IplImage* retrievePointCloudMap(); IplImage* retrieveDisparityMap(); @@ -116,8 +147,8 @@ protected: IplImage* retrieveGrayImage(); IplImage* retrieveIrImage(); - openni::Status toggleStream(int stream, bool toggle); - bool readCamerasParams(); + void toggleStream(int stream, bool toggle); + void readCamerasParams(); double getDepthGeneratorProperty(int propIdx) const; bool setDepthGeneratorProperty(int propIdx, double propVal); @@ -131,12 +162,11 @@ protected: // OpenNI context openni::Device device; bool isContextOpened; - openni::Recorder recorder; // Data generators with its metadata - openni::VideoStream streams[CV_MAX_NUM_STREAMS]; - openni::VideoFrameRef streamFrames[CV_MAX_NUM_STREAMS]; - cv::Mat streamImages[CV_MAX_NUM_STREAMS]; + std::vector streams; + std::vector streamFrames; + std::vector streamImages; int maxBufferSize, maxTimeDuration; // for approx sync bool isCircleBuffer; @@ -191,80 +221,103 @@ openni::VideoMode CvCapture_OpenNI2::defaultStreamOutputMode(int stream) return mode; } -CvCapture_OpenNI2::CvCapture_OpenNI2( int index ) + +CvCapture_OpenNI2::CvCapture_OpenNI2(int index) : + CvCapture_OpenNI2(index, nullptr) +{ } + +CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename) : + CvCapture_OpenNI2(-1, filename) +{ } + +CvCapture_OpenNI2::CvCapture_OpenNI2(int index, const char * filename) : + device(), + isContextOpened(false), + streams(CV_MAX_NUM_STREAMS), + streamFrames(CV_MAX_NUM_STREAMS), + streamImages(CV_MAX_NUM_STREAMS), + maxBufferSize(DEFAULT_MAX_BUFFER_SIZE), + maxTimeDuration(DEFAULT_MAX_TIME_DURATION), + isCircleBuffer(DEFAULT_IS_CIRCLE_BUFFER), + baseline(0), + depthFocalLength_VGA(0), + shadowValue(0), + noSampleValue(0), + outputMaps(outputMapsTypesCount) { - const char* deviceURI = openni::ANY_DEVICE; - openni::Status status; - int deviceType = DEVICE_DEFAULT; - - noSampleValue = shadowValue = 0; - - isContextOpened = false; - maxBufferSize = DEFAULT_MAX_BUFFER_SIZE; - isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER; - maxTimeDuration = DEFAULT_MAX_TIME_DURATION; - - if( index >= 10 ) - { - deviceType = index / 10; - index %= 10; - } - // Initialize and configure the context. - status = openni::OpenNI::initialize(); + OpenNI2Initializer::init(); - if (status != openni::STATUS_OK) + const char* deviceURI = openni::ANY_DEVICE; + bool needColor = true; + bool needIR = true; + if (index >= 0) { - CV_Error(CV_StsError, cv::format("Failed to initialize:", openni::OpenNI::getExtendedError())); - return; - } - - // find appropriate device URI - openni::Array ldevs; - if (index > 0) - { - openni::OpenNI::enumerateDevices(&ldevs); - deviceURI = ldevs[index].getUri(); + int deviceType = DEVICE_DEFAULT; + if (index >= 10) + { + deviceType = index / 10; + index %= 10; + } + // Asus XTION and Occipital Structure Sensor do not have an image generator + needColor = (deviceType != DEVICE_ASUS_XTION); + + // find appropriate device URI + openni::Array ldevs; + if (index > 0) + { + openni::OpenNI::enumerateDevices(&ldevs); + if (index < ldevs.getSize()) + deviceURI = ldevs[index].getUri(); + else + { + CV_Error(CV_StsError, "OpenCVKinect2: Device index exceeds the number of available OpenNI devices"); + } + } + } + else + { + deviceURI = filename; } + openni::Status status; status = device.open(deviceURI); - if( status != openni::STATUS_OK ) - { - CV_Error(CV_StsError, cv::format("OpenCVKinect: Device open failed see: %s\n", openni::OpenNI::getExtendedError())); - openni::OpenNI::shutdown(); - return; - } - - status = toggleStream(CV_DEPTH_STREAM, true); - // Asus XTION and Occipital Structure Sensor do not have an image generator - if (deviceType != DEVICE_ASUS_XTION) - status = openni::Status(status | toggleStream(CV_COLOR_STREAM, true)); if (status != openni::STATUS_OK) { - openni::OpenNI::shutdown(); - return; + CV_Error(CV_StsError, std::string("OpenCVKinect2: Failed to open device: ") + openni::OpenNI::getExtendedError()); } - if (!readCamerasParams()) - { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n")); - return; - } - - - outputMaps.resize( outputMapsTypesCount ); - - isContextOpened = true; + toggleStream(CV_DEPTH_STREAM, true); + if (needColor) + toggleStream(CV_COLOR_STREAM, true); + if (needIR) + toggleStream(CV_IR_STREAM, true); setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0); + + // default for Kinect2 camera + setProperty(CV_CAP_PROP_OPENNI2_MIRROR, 0.0); + + isContextOpened = true; } -openni::Status CvCapture_OpenNI2::toggleStream(int stream, bool toggle) +CvCapture_OpenNI2::~CvCapture_OpenNI2() +{ + for (size_t i = 0; i < streams.size(); ++i) + { + streamFrames[i].release(); + streams[i].stop(); + streams[i].destroy(); + } + device.close(); +} + +void CvCapture_OpenNI2::toggleStream(int stream, bool toggle) { openni::Status status; // for logging - static const char* stream_names[CV_MAX_NUM_STREAMS] = { + static const std::string stream_names[CV_MAX_NUM_STREAMS] = { "depth", "color", "IR" @@ -280,140 +333,92 @@ openni::Status CvCapture_OpenNI2::toggleStream(int stream, bool toggle) { // already opened if (streams[stream].isValid()) - return openni::STATUS_OK; + return; // open stream status = streams[stream].create(device, stream_sensor_types[stream]); if (status == openni::STATUS_OK) { - // set video mode - status = streams[stream].setVideoMode(defaultStreamOutputMode(stream)); // xn::DepthGenerator supports VGA only! (Jan 2011) - if (status != openni::STATUS_OK) + // try to set up default stream mode (if available) + const openni::Array& vm = streams[stream].getSensorInfo().getSupportedVideoModes(); + openni::VideoMode dm = defaultStreamOutputMode(stream); + for (int i = 0; i < vm.getSize(); i++) { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't set %s stream output mode: %s\n", - stream_names[stream], - openni::OpenNI::getExtendedError())); - streams[stream].destroy(); - return status; + if (vm[i].getPixelFormat() == dm.getPixelFormat() && + vm[i].getResolutionX() == dm.getResolutionX() && + vm[i].getResolutionY() == dm.getResolutionY() && + vm[i].getFps() == dm.getFps()) + { + status = streams[stream].setVideoMode(defaultStreamOutputMode(stream)); + if (status != openni::STATUS_OK) + { + streams[stream].destroy(); + CV_Error(CV_StsError, std::string("OpenCVKinect2 : Couldn't set ") + + stream_names[stream] + std::string(" stream output mode: ") + + std::string(openni::OpenNI::getExtendedError())); + } + } } // start stream status = streams[stream].start(); if (status != openni::STATUS_OK) { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start %s stream: %s\n", - stream_names[stream], - openni::OpenNI::getExtendedError())); streams[stream].destroy(); - return status; + CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start ") + + stream_names[stream] + std::string(" stream: ") + + std::string(openni::OpenNI::getExtendedError())); } } else { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find %s stream:: %s\n", - stream_names[stream], - openni::OpenNI::getExtendedError())); - return status; + CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find ") + + stream_names[stream] + " stream: " + + std::string(openni::OpenNI::getExtendedError())); } } else if (streams[stream].isValid()) // want to close stream { - streams[stream].stop(); - streams[stream].destroy(); - } + //FIX for libfreenect2 + //which stops the whole device when stopping only one stream - return openni::STATUS_OK; + //streams[stream].stop(); + //streams[stream].destroy(); + } } -CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename) -{ - openni::Status status; - isContextOpened = false; - maxBufferSize = DEFAULT_MAX_BUFFER_SIZE; - isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER; - maxTimeDuration = DEFAULT_MAX_TIME_DURATION; - - // Initialize and configure the context. - status = openni::OpenNI::initialize(); - - if (status != openni::STATUS_OK) - { - CV_Error(CV_StsError, cv::format("Failed to initialize:", openni::OpenNI::getExtendedError())); - return; - } - - // Open file - status = device.open(filename); - if( status != openni::STATUS_OK ) - { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Failed to open input file (%s): %s\n", filename, openni::OpenNI::getExtendedError())); - return; - } - - status = openni::Status(toggleStream(CV_DEPTH_STREAM, true) | toggleStream(CV_COLOR_STREAM, true)); - if (status != openni::STATUS_OK) - { - openni::OpenNI::shutdown(); - return; - } - - if( !readCamerasParams() ) - { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n")); - return; - } - - outputMaps.resize( outputMapsTypesCount ); - - isContextOpened = true; -} - -CvCapture_OpenNI2::~CvCapture_OpenNI2() -{ - for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) - { - streamFrames[i].release(); - streams[i].stop(); - streams[i].destroy(); - } - device.close(); - openni::OpenNI::shutdown(); -} - -bool CvCapture_OpenNI2::readCamerasParams() +void CvCapture_OpenNI2::readCamerasParams() { double pixelSize = 0; if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_PIXEL_SIZE, &pixelSize) != openni::STATUS_OK) { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::readCamerasParams : Could not read pixel size!\n")); - return false; + CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read pixel size!" + + std::string(openni::OpenNI::getExtendedError())); } // pixel size @ VGA = pixel size @ SXGA x 2 pixelSize *= 2.0; // in mm // focal length of IR camera in pixels for VGA resolution - int zeroPlanDistance; // in mm - if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlanDistance) != openni::STATUS_OK) + unsigned long long zeroPlaneDistance; // in mm + if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlaneDistance) != openni::STATUS_OK) { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::readCamerasParams : Could not read virtual plane distance!\n")); - return false; + CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read virtual plane distance!" + + std::string(openni::OpenNI::getExtendedError())); } if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_EMITTER_DCMOS_DISTANCE, &baseline) != openni::STATUS_OK) { - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::readCamerasParams : Could not read base line!\n")); - return false; + CV_Error(CV_StsError, "CvCapture_OpenNI2::readCamerasParams : Could not read base line!" + + std::string(openni::OpenNI::getExtendedError())); } // baseline from cm -> mm baseline *= 10; // focal length from mm -> pixels (valid for 640x480) - depthFocalLength_VGA = (int)((double)zeroPlanDistance / (double)pixelSize); - - return true; + depthFocalLength_VGA = (int)((double)zeroPlaneDistance / (double)pixelSize); } double CvCapture_OpenNI2::getProperty( int propIdx ) const @@ -500,7 +505,7 @@ double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const break; } default : - CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for getting.\n", propIdx) ); + CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for getting.", propIdx) ); } return propValue; @@ -525,14 +530,20 @@ bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue ) // There is a set of properties that correspond to depth generator by default // (is they are pass without particular generator flag). case CV_CAP_PROP_OPENNI_REGISTRATION: - isSet = setDepthGeneratorProperty( propIdx, propValue ); + isSet = setDepthGeneratorProperty(propIdx, propValue); break; case CV_CAP_PROP_OPENNI2_SYNC: isSet = device.setDepthColorSyncEnabled(propValue > 0.0) == openni::STATUS_OK; break; + case CV_CAP_PROP_FRAME_WIDTH: + case CV_CAP_PROP_FRAME_HEIGHT: + case CV_CAP_PROP_AUTOFOCUS: + isSet = false; + break; + default: - CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.\n", propIdx) ); + CV_Error(CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.", propIdx)); } return isSet; @@ -565,9 +576,13 @@ double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const propValue = streams[CV_DEPTH_STREAM].getMaxPixelValue(); break; case CV_CAP_PROP_OPENNI_BASELINE : + if(baseline <= 0) + const_cast(this)->readCamerasParams(); propValue = baseline; break; case CV_CAP_PROP_OPENNI_FOCAL_LENGTH : + if(depthFocalLength_VGA <= 0) + const_cast(this)->readCamerasParams(); propValue = (double)depthFocalLength_VGA; break; case CV_CAP_PROP_OPENNI_REGISTRATION : @@ -580,7 +595,7 @@ double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const propValue = streamFrames[CV_DEPTH_STREAM].getFrameIndex(); break; default : - CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.\n", propIdx) ); + CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.", propIdx) ); } return propValue; @@ -594,7 +609,10 @@ bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue { case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: if (isContextOpened) - isSet = toggleStream(CV_DEPTH_STREAM, propValue > 0.0) == openni::STATUS_OK; + { + toggleStream(CV_DEPTH_STREAM, propValue > 0.0); + isSet = true; + } break; case CV_CAP_PROP_OPENNI_REGISTRATION: { @@ -612,12 +630,13 @@ bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue { openni::Status status = device.setImageRegistrationMode(mode); if( status != openni::STATUS_OK ) - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setDepthGeneratorProperty : %s\n", openni::OpenNI::getExtendedError())); + CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") + + std::string(openni::OpenNI::getExtendedError())); else isSet = true; } else - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setDepthGeneratorProperty : Unsupported viewpoint.\n")); + CV_Error(CV_StsError, "CvCapture_OpenNI2::setDepthGeneratorProperty: Unsupported viewpoint."); } else isSet = true; @@ -627,14 +646,15 @@ bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue { openni::Status status = device.setImageRegistrationMode(openni::IMAGE_REGISTRATION_OFF); if( status != openni::STATUS_OK ) - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setDepthGeneratorProperty : %s\n", openni::OpenNI::getExtendedError())); + CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setDepthGeneratorProperty: ") + + std::string(openni::OpenNI::getExtendedError())); else isSet = true; } } break; default: - CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for setting.\n", propIdx) ); + CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for setting.", propIdx) ); } return isSet; @@ -668,7 +688,7 @@ double CvCapture_OpenNI2::getImageGeneratorProperty( int propIdx ) const propValue = (double)streamFrames[CV_COLOR_STREAM].getFrameIndex(); break; default : - CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.\n", propIdx) ); + CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx) ); } return propValue; @@ -682,7 +702,10 @@ bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue) { case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: if (isContextOpened) - isSet = toggleStream(CV_COLOR_STREAM, propValue > 0.0) == openni::STATUS_OK; + { + toggleStream(CV_COLOR_STREAM, propValue > 0.0); + isSet = true; + } break; case CV_CAP_PROP_OPENNI_OUTPUT_MODE : { @@ -713,18 +736,19 @@ bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue) mode.setFps(60); break; default : - CV_Error( CV_StsBadArg, "Unsupported image generator output mode.\n"); + CV_Error( CV_StsBadArg, "Unsupported image generator output mode."); } openni::Status status = streams[CV_COLOR_STREAM].setVideoMode( mode ); if( status != openni::STATUS_OK ) - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setImageGeneratorProperty : %s\n", openni::OpenNI::getExtendedError())); + CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") + + std::string(openni::OpenNI::getExtendedError())); else isSet = true; break; } default: - CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.\n", propIdx) ); + CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx) ); } return isSet; @@ -758,7 +782,7 @@ double CvCapture_OpenNI2::getIrGeneratorProperty(int propIdx) const propValue = (double)streamFrames[CV_IR_STREAM].getFrameIndex(); break; default: - CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.\n", propIdx)); + CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.", propIdx)); } return propValue; @@ -772,7 +796,10 @@ bool CvCapture_OpenNI2::setIrGeneratorProperty(int propIdx, double propValue) { case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT: if (isContextOpened) - isSet = toggleStream(CV_IR_STREAM, propValue > 0.0) == openni::STATUS_OK; + { + toggleStream(CV_IR_STREAM, propValue > 0.0); + isSet = true; + } break; case CV_CAP_PROP_OPENNI_OUTPUT_MODE: { @@ -803,18 +830,19 @@ bool CvCapture_OpenNI2::setIrGeneratorProperty(int propIdx, double propValue) mode.setFps(60); break; default: - CV_Error(CV_StsBadArg, "Unsupported image generator output mode.\n"); + CV_Error(CV_StsBadArg, "Unsupported image generator output mode."); } openni::Status status = streams[CV_IR_STREAM].setVideoMode(mode); if (status != openni::STATUS_OK) - CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setImageGeneratorProperty : %s\n", openni::OpenNI::getExtendedError())); + CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::setImageGeneratorProperty: ") + + std::string(openni::OpenNI::getExtendedError())); else isSet = true; break; } default: - CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.\n", propIdx)); + CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.", propIdx)); } return isSet; @@ -931,10 +959,12 @@ IplImage* CvCapture_OpenNI2::retrieveDisparityMap() if (!streamFrames[CV_DEPTH_STREAM].isValid()) return 0; + readCamerasParams(); + cv::Mat disp32; computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue); - disp32.convertTo( outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1 ); + disp32.convertTo(outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1); return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr(); } @@ -944,6 +974,8 @@ IplImage* CvCapture_OpenNI2::retrieveDisparityMap_32F() if (!streamFrames[CV_DEPTH_STREAM].isValid()) return 0; + readCamerasParams(); + computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue); return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr(); @@ -966,7 +998,7 @@ inline void getBGRImageFromMetaData( const openni::VideoFrameRef& imageMetaData, { cv::Mat bufferImage; if( imageMetaData.getVideoMode().getPixelFormat() != openni::PIXEL_FORMAT_RGB888 ) - CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n" ); + CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image." ); bgrImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3); bufferImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3); @@ -989,7 +1021,7 @@ inline void getGrayImageFromMetaData(const openni::VideoFrameRef& imageMetaData, } else { - CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n"); + CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image."); } } diff --git a/modules/videoio/src/videoio_registry.cpp b/modules/videoio/src/videoio_registry.cpp index 1f990b11c0..9f0abc512b 100644 --- a/modules/videoio/src/videoio_registry.cpp +++ b/modules/videoio/src/videoio_registry.cpp @@ -75,12 +75,12 @@ static const struct VideoBackendInfo builtin_backends[] = #ifdef HAVE_MSMF DECLARE_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER), #endif -#ifdef HAVE_VFW - DECLARE_BACKEND(CAP_VFW, "VFW", MODE_CAPTURE_ALL | MODE_WRITER), -#endif #ifdef HAVE_DSHOW DECLARE_BACKEND(CAP_DSHOW, "DSHOW", MODE_CAPTURE_BY_INDEX), #endif +#ifdef HAVE_VFW + DECLARE_BACKEND(CAP_VFW, "VFW", MODE_CAPTURE_ALL | MODE_WRITER), +#endif // Linux, some Unix #if defined HAVE_CAMV4L2 diff --git a/samples/cpp/gstreamer_pipeline.cpp b/samples/cpp/gstreamer_pipeline.cpp index 0d467754b3..4ad1daa4c2 100644 --- a/samples/cpp/gstreamer_pipeline.cpp +++ b/samples/cpp/gstreamer_pipeline.cpp @@ -4,444 +4,373 @@ #include "opencv2/highgui.hpp" #include #include +#include using namespace std; using namespace cv; -class GStreamerPipeline +//================================================================================ + +template +inline typename M::mapped_type getValue(const M &dict, const typename M::key_type &key, const string & errorMessage) { - public: - // Preprocessing arguments command line - GStreamerPipeline(int argc, char *argv[]) + typename M::const_iterator it = dict.find(key); + if (it == dict.end()) { - const string keys = - "{h help usage ? | | print help messages }" - "{m mode | | coding mode (supported: encode, decode) }" - "{p pipeline |default | pipeline name (supported: 'default', 'gst-basic', 'gst-vaapi', 'gst-libav', 'ffmpeg') }" - "{cd codec |h264 | codec name (supported: 'h264', 'h265', 'mpeg2', 'mpeg4', 'mjpeg', 'vp8') }" - "{f file path | | path to file }" - "{vr resolution |720p | video resolution for encoding (supported: '720p', '1080p', '4k') }" - "{fps |30 | fix frame per second for encoding (supported: fps > 0) }" - "{fm fast | | fast measure fps }"; - cmd_parser = new CommandLineParser(argc, argv, keys); - cmd_parser->about("This program shows how to read a video file with GStreamer pipeline with OpenCV."); - - if (cmd_parser->has("help")) - { - cmd_parser->printMessage(); - CV_Error(Error::StsBadArg, "Called help."); - } - - fast_measure = cmd_parser->has("fast"); // fast measure fps - fix_fps = cmd_parser->get("fps"); // fixed frame per second - pipeline = cmd_parser->get("pipeline"), // gstreamer pipeline type - mode = cmd_parser->get("mode"), // coding mode - codec = cmd_parser->get("codec"), // codec type - file_name = cmd_parser->get("file"), // path to videofile - resolution = cmd_parser->get("resolution"); // video resolution - - size_t found = file_name.rfind("."); - if (found != string::npos) - { - container = file_name.substr(found + 1); // container type - } - else { CV_Error(Error::StsBadArg, "Can not parse container extension."); } - - if (!cmd_parser->check()) - { - cmd_parser->printErrors(); - CV_Error(Error::StsBadArg, "Failed parse arguments."); - } + CV_Error(Error::StsBadArg, errorMessage); } + return it->second; +} - ~GStreamerPipeline() { delete cmd_parser; } +inline map sizeByResolution() +{ + map res; + res["720p"] = Size(1280, 720); + res["1080p"] = Size(1920, 1080); + res["4k"] = Size(3840, 2160); + return res; +} - // Start pipeline - int run() +inline map fourccByCodec() +{ + map res; + res["h264"] = VideoWriter::fourcc('H','2','6','4'); + res["h265"] = VideoWriter::fourcc('H','E','V','C'); + res["mpeg2"] = VideoWriter::fourcc('M','P','E','G'); + res["mpeg4"] = VideoWriter::fourcc('M','P','4','2'); + res["mjpeg"] = VideoWriter::fourcc('M','J','P','G'); + res["vp8"] = VideoWriter::fourcc('V','P','8','0'); + return res; +} + +inline map defaultEncodeElementByCodec() +{ + map res; + res["h264"] = "x264enc"; + res["h265"] = "x265enc"; + res["mpeg2"] = "mpeg2enc"; + res["mjpeg"] = "jpegenc"; + res["vp8"] = "vp8enc"; + return res; +} + +inline map VAAPIEncodeElementByCodec() +{ + map res; + res["h264"] = "parsebin ! vaapih264enc"; + res["h265"] = "parsebin ! vaapih265enc"; + res["mpeg2"] = "parsebin ! vaapimpeg2enc"; + res["mjpeg"] = "parsebin ! vaapijpegenc"; + res["vp8"] = "parsebin ! vaapivp8enc"; + return res; +} + +inline map mfxDecodeElementByCodec() +{ + map res; + res["h264"] = "parsebin ! mfxh264dec"; + res["h265"] = "parsebin ! mfxhevcdec"; + res["mpeg2"] = "parsebin ! mfxmpeg2dec"; + res["mjpeg"] = "parsebin ! mfxjpegdec"; + return res; +} + +inline map mfxEncodeElementByCodec() +{ + map res; + res["h264"] = "mfxh264enc"; + res["h265"] = "mfxhevcenc"; + res["mpeg2"] = "mfxmpeg2enc"; + res["mjpeg"] = "mfxjpegenc"; + return res; +} + +inline map libavDecodeElementByCodec() +{ + map res; + res["h264"] = "parsebin ! avdec_h264"; + res["h265"] = "parsebin ! avdec_h265"; + res["mpeg2"] = "parsebin ! avdec_mpeg2video"; + res["mpeg4"] = "parsebin ! avdec_mpeg4"; + res["mjpeg"] = "parsebin ! avdec_mjpeg"; + res["vp8"] = "parsebin ! avdec_vp8"; + return res; +} + +inline map libavEncodeElementByCodec() +{ + map res; + res["h264"] = "avenc_h264"; + res["h265"] = "avenc_h265"; + res["mpeg2"] = "avenc_mpeg2video"; + res["mpeg4"] = "avenc_mpeg4"; + res["mjpeg"] = "avenc_mjpeg"; + res["vp8"] = "avenc_vp8"; + return res; +} + +inline map demuxPluginByContainer() +{ + map res; + res["avi"] = "avidemux"; + res["mp4"] = "qtdemux"; + res["mov"] = "qtdemux"; + res["mkv"] = "matroskademux"; + return res; +} + +inline map muxPluginByContainer() +{ + map res; + res["avi"] = "avimux"; + res["mp4"] = "qtmux"; + res["mov"] = "qtmux"; + res["mkv"] = "matroskamux"; + return res; +} + +//================================================================================ + +inline string containerByName(const string &name) +{ + size_t found = name.rfind("."); + if (found != string::npos) { - if (mode == "decode") { if (createDecodePipeline() < 0) return -1; } - else if (mode == "encode") { if (createEncodePipeline() < 0) return -1; } - else - { - cout << "Unsupported mode: " << mode << endl; - cmd_parser->printErrors(); - return -1; - } - cout << "_____________________________________" << endl; - cout << "Pipeline " << mode << ":" << endl; - cout << stream_pipeline.str() << endl; - // Choose a show video or only measure fps - cout << "_____________________________________" << endl; - cout << "Start measure frame per seconds (fps)" << endl; - cout << "Loading ..." << endl; - - vector tick_counts; - - cout << "Start " << mode << ": " << file_name; - cout << " (" << pipeline << ")" << endl; - - while(true) - { - int64 temp_count_tick = 0; - if (mode == "decode") - { - Mat frame; - temp_count_tick = getTickCount(); - cap >> frame; - temp_count_tick = getTickCount() - temp_count_tick; - if (frame.empty()) { break; } - } - else if (mode == "encode") - { - Mat element; - while(!cap.grab()); - cap.retrieve(element); - temp_count_tick = getTickCount(); - wrt << element; - temp_count_tick = getTickCount() - temp_count_tick; - } - - tick_counts.push_back(static_cast(temp_count_tick)); - if (((mode == "decode") && fast_measure && (tick_counts.size() > 1e3)) || - ((mode == "encode") && (tick_counts.size() > 3e3)) || - ((mode == "encode") && fast_measure && (tick_counts.size() > 1e2))) - { break; } - - } - double time_fps = sum(tick_counts)[0] / getTickFrequency(); - - if (tick_counts.size() != 0) - { - cout << "Finished: " << tick_counts.size() << " in " << time_fps <<" sec ~ " ; - cout << tick_counts.size() / time_fps <<" fps " << endl; - } - else - { - cout << "Failed " << mode << ": " << file_name; - cout << " (" << pipeline << ")" << endl; - return -1; - } - return 0; + return name.substr(found + 1); // container type } + return string(); +} - // Free video resource - void close() +//================================================================================ + +inline Ptr createCapture(const string &backend, const string &file_name, const string &codec) +{ + if (backend == "gst-default") { - cap.release(); - wrt.release(); + cout << "Created GStreamer capture ( " << file_name << " )" << endl; + return makePtr(file_name, CAP_GSTREAMER); } - - private: - // Choose the constructed GStreamer pipeline for decode - int createDecodePipeline() + else if (backend.find("gst") == 0) { - if (pipeline == "default") { - cap = VideoCapture(file_name, CAP_GSTREAMER); - } - else if (pipeline.find("gst") == 0) - { - stream_pipeline << "filesrc location=\"" << file_name << "\""; - stream_pipeline << " ! " << getGstMuxPlugin(); - - if (pipeline.find("basic") == 4) - { - stream_pipeline << getGstDefaultCodePlugin(); - } - else if (pipeline.find("vaapi1710") == 4) - { - stream_pipeline << getGstVaapiCodePlugin(); - } - else if (pipeline.find("libav") == 4) - { - stream_pipeline << getGstAvCodePlugin(); - } - else - { - cout << "Unsupported pipeline: " << pipeline << endl; - cmd_parser->printErrors(); - return -1; - } - - stream_pipeline << " ! videoconvert n-threads=" << getNumThreads(); - stream_pipeline << " ! appsink sync=false"; - cap = VideoCapture(stream_pipeline.str(), CAP_GSTREAMER); - } - else if (pipeline == "ffmpeg") - { - cap = VideoCapture(file_name, CAP_FFMPEG); - stream_pipeline << "default pipeline for ffmpeg" << endl; - } + ostringstream line; + line << "filesrc location=\"" << file_name << "\""; + line << " ! "; + line << getValue(demuxPluginByContainer(), containerByName(file_name), "Invalid container"); + line << " ! "; + if (backend.find("basic") == 4) + line << "decodebin"; + else if (backend.find("vaapi") == 4) + line << "vaapidecodebin"; + else if (backend.find("libav") == 4) + line << getValue(libavDecodeElementByCodec(), codec, "Invalid codec"); + else if (backend.find("mfx") == 4) + line << getValue(mfxDecodeElementByCodec(), codec, "Invalid or unsupported codec"); else - { - cout << "Unsupported pipeline: " << pipeline << endl; - cmd_parser->printErrors(); - return -1; - } - return 0; + return Ptr(); + line << " ! videoconvert n-threads=" << getNumThreads(); + line << " ! appsink sync=false"; + cout << "Created GStreamer capture ( " << line.str() << " )" << endl; + return makePtr(line.str(), CAP_GSTREAMER); } - - // Choose the constructed GStreamer pipeline for encode - int createEncodePipeline() + else if (backend == "ffmpeg") { - if (checkConfiguration() < 0) return -1; - ostringstream test_pipeline; - test_pipeline << "videotestsrc pattern=smpte"; - test_pipeline << " ! video/x-raw, " << getVideoSettings(); - test_pipeline << " ! appsink sync=false"; - cap = VideoCapture(test_pipeline.str(), CAP_GSTREAMER); - - if (pipeline == "default") { - wrt = VideoWriter(file_name, CAP_GSTREAMER, getFourccCode(), fix_fps, fix_size, true); - } - else if (pipeline.find("gst") == 0) - { - stream_pipeline << "appsrc ! videoconvert n-threads=" << getNumThreads() << " ! "; - - if (pipeline.find("basic") == 4) - { - stream_pipeline << getGstDefaultCodePlugin(); - } - else if (pipeline.find("vaapi1710") == 4) - { - stream_pipeline << getGstVaapiCodePlugin(); - } - else if (pipeline.find("libav") == 4) - { - stream_pipeline << getGstAvCodePlugin(); - } - else - { - cout << "Unsupported pipeline: " << pipeline << endl; - cmd_parser->printErrors(); - return -1; - } - - stream_pipeline << " ! " << getGstMuxPlugin(); - stream_pipeline << " ! filesink location=\"" << file_name << "\""; - wrt = VideoWriter(stream_pipeline.str(), CAP_GSTREAMER, 0, fix_fps, fix_size, true); - } - else if (pipeline == "ffmpeg") - { - wrt = VideoWriter(file_name, CAP_FFMPEG, getFourccCode(), fix_fps, fix_size, true); - stream_pipeline << "default pipeline for ffmpeg" << endl; - } - else - { - cout << "Unsupported pipeline: " << pipeline << endl; - cmd_parser->printErrors(); - return -1; - } - return 0; + cout << "Created FFmpeg capture ( " << file_name << " )" << endl; + return makePtr(file_name, CAP_FFMPEG); } + return Ptr(); +} - // Choose video resolution for encoding - string getVideoSettings() +inline Ptr createSynthSource(Size sz, unsigned fps) +{ + ostringstream line; + line << "videotestsrc pattern=smpte"; + line << " ! video/x-raw"; + line << ",width=" << sz.width << ",height=" << sz.height; + if (fps > 0) + line << ",framerate=" << fps << "/1"; + line << " ! appsink sync=false"; + cout << "Created synthetic video source ( " << line.str() << " )" << endl; + return makePtr(line.str(), CAP_GSTREAMER); +} + +inline Ptr createWriter(const string &backend, const string &file_name, const string &codec, Size sz, unsigned fps) +{ + if (backend == "gst-default") { - ostringstream video_size; - if (fix_fps > 0) { video_size << "framerate=" << fix_fps << "/1, "; } - else - { - cout << "Unsupported fps (< 0): " << fix_fps << endl; - cmd_parser->printErrors(); - return string(); - } - - if (resolution == "720p") { fix_size = Size(1280, 720); } - else if (resolution == "1080p") { fix_size = Size(1920, 1080); } - else if (resolution == "4k") { fix_size = Size(3840, 2160); } - else - { - cout << "Unsupported video resolution: " << resolution << endl; - cmd_parser->printErrors(); - return string(); - } - - video_size << "width=" << fix_size.width << ", height=" << fix_size.height; - return video_size.str(); + cout << "Created GStreamer writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << ")" << endl; + return makePtr(file_name, CAP_GSTREAMER, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true); } - - // Choose a video container - string getGstMuxPlugin() + else if (backend.find("gst") == 0) { - ostringstream plugin; - if (container == "avi") { plugin << "avi"; } - else if (container == "mp4") { plugin << "qt"; } - else if (container == "mov") { plugin << "qt"; } - else if (container == "mkv") { plugin << "matroska"; } + ostringstream line; + line << "appsrc ! videoconvert n-threads=" << getNumThreads() << " ! "; + if (backend.find("basic") == 4) + line << getValue(defaultEncodeElementByCodec(), codec, "Invalid codec"); + else if (backend.find("vaapi") == 4) + line << getValue(VAAPIEncodeElementByCodec(), codec, "Invalid codec"); + else if (backend.find("libav") == 4) + line << getValue(libavEncodeElementByCodec(), codec, "Invalid codec"); + else if (backend.find("mfx") == 4) + line << getValue(mfxEncodeElementByCodec(), codec, "Invalid codec"); else - { - cout << "Unsupported container: " << container << endl; - cmd_parser->printErrors(); - return string(); - } - - if (mode == "decode") { plugin << "demux"; } - else if (mode == "encode") { plugin << "mux"; } - else - { - cout << "Unsupported mode: " << mode << endl; - cmd_parser->printErrors(); - return string(); - } - - return plugin.str(); + return Ptr(); + line << " ! "; + line << getValue(muxPluginByContainer(), containerByName(file_name), "Invalid container"); + line << " ! "; + line << "filesink location=\"" << file_name << "\""; + cout << "Created GStreamer writer ( " << line.str() << " )" << endl; + return makePtr(line.str(), CAP_GSTREAMER, 0, fps, sz, true); } - - // Choose a libav codec - string getGstAvCodePlugin() + else if (backend == "ffmpeg") { - ostringstream plugin; - if (mode == "decode") - { - if (codec == "h264") { plugin << "h264parse ! "; } - else if (codec == "h265") { plugin << "h265parse ! "; } - plugin << "avdec_"; - } - else if (mode == "encode") { plugin << "avenc_"; } - else - { - cout << "Unsupported mode: " << mode << endl; - cmd_parser->printErrors(); - return string(); - } - - if (codec == "h264") { plugin << "h264"; } - else if (codec == "h265") { plugin << "h265"; } - else if (codec == "mpeg2") { plugin << "mpeg2video"; } - else if (codec == "mpeg4") { plugin << "mpeg4"; } - else if (codec == "mjpeg") { plugin << "mjpeg"; } - else if (codec == "vp8") { plugin << "vp8"; } - else - { - cout << "Unsupported libav codec: " << codec << endl; - cmd_parser->printErrors(); - return string(); - } - - return plugin.str(); + cout << "Created FFMpeg writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << " )" << endl; + return makePtr(file_name, CAP_FFMPEG, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true); } + return Ptr(); +} - // Choose a vaapi codec - string getGstVaapiCodePlugin() - { - ostringstream plugin; - if (mode == "decode") - { - plugin << "vaapidecodebin"; - if (container == "mkv") { plugin << " ! autovideoconvert"; } - else { plugin << " ! video/x-raw, format=YV12"; } - } - else if (mode == "encode") - { - if (codec == "h264") { plugin << "vaapih264enc"; } - else if (codec == "h265") { plugin << "vaapih265enc"; } - else if (codec == "mpeg2") { plugin << "vaapimpeg2enc"; } - else if (codec == "mjpeg") { plugin << "vaapijpegenc"; } - else if (codec == "vp8") { plugin << "vaapivp8enc"; } - else - { - cout << "Unsupported vaapi codec: " << codec << endl; - cmd_parser->printErrors(); - return string(); - } - } - else - { - cout << "Unsupported mode: " << resolution << endl; - cmd_parser->printErrors(); - return string(); - } - return plugin.str(); - } - - // Choose a default codec - string getGstDefaultCodePlugin() - { - ostringstream plugin; - if (mode == "decode") - { - plugin << " ! decodebin"; - } - else if (mode == "encode") - { - if (codec == "h264") { plugin << "x264enc"; } - else if (codec == "h265") { plugin << "x265enc"; } - else if (codec == "mpeg2") { plugin << "mpeg2enc"; } - else if (codec == "mjpeg") { plugin << "jpegenc"; } - else if (codec == "vp8") { plugin << "vp8enc"; } - else - { - cout << "Unsupported default codec: " << codec << endl; - cmd_parser->printErrors(); - return string(); - } - } - else - { - cout << "Unsupported mode: " << resolution << endl; - cmd_parser->printErrors(); - return string(); - } - return plugin.str(); - } - // Get fourcc for codec - int getFourccCode() - { - if (codec == "h264") { return VideoWriter::fourcc('H','2','6','4'); } - else if (codec == "h265") { return VideoWriter::fourcc('H','E','V','C'); } - else if (codec == "mpeg2") { return VideoWriter::fourcc('M','P','E','G'); } - else if (codec == "mpeg4") { return VideoWriter::fourcc('M','P','4','2'); } - else if (codec == "mjpeg") { return VideoWriter::fourcc('M','J','P','G'); } - else if (codec == "vp8") { return VideoWriter::fourcc('V','P','8','0'); } - else - { - cout << "Unsupported ffmpeg codec: " << codec << endl; - cmd_parser->printErrors(); - return 0; - } - } - - // Check bad configuration - int checkConfiguration() - { - if ((codec == "mpeg2" && getGstMuxPlugin() == "qtmux") || - (codec == "h265" && getGstMuxPlugin() == "avimux") || - (pipeline == "gst-libav" && (codec == "h264" || codec == "h265")) || - (pipeline == "gst-vaapi1710" && codec=="mpeg2" && resolution=="4k") || - (pipeline == "gst-vaapi1710" && codec=="mpeg2" && resolution=="1080p" && fix_fps > 30)) - { - cout << "Unsupported configuration" << endl; - cmd_parser->printErrors(); - return -1; - } - return 0; - } - - bool fast_measure; // fast measure fps - string pipeline, // gstreamer pipeline type - container, // container type - mode, // coding mode - codec, // codec type - file_name, // path to videofile - resolution; // video resolution - int fix_fps; // fixed frame per second - Size fix_size; // fixed frame size - VideoWriter wrt; - VideoCapture cap; - ostringstream stream_pipeline; - CommandLineParser* cmd_parser; -}; +//================================================================================ int main(int argc, char *argv[]) { + const string keys = + "{h help usage ? | | print help messages }" + "{m mode |decode | coding mode (supported: encode, decode) }" + "{b backend |default | video backend (supported: 'gst-default', 'gst-basic', 'gst-vaapi', 'gst-libav', 'gst-mfx', 'ffmpeg') }" + "{c codec |h264 | codec name (supported: 'h264', 'h265', 'mpeg2', 'mpeg4', 'mjpeg', 'vp8') }" + "{f file path | | path to file }" + "{r resolution |720p | video resolution for encoding (supported: '720p', '1080p', '4k') }" + "{fps |30 | fix frame per second for encoding (supported: fps > 0) }" + "{fast | | fast measure fps }"; + CommandLineParser cmd_parser(argc, argv, keys); + cmd_parser.about("This program measures performance of video encoding and decoding using different backends OpenCV."); + if (cmd_parser.has("help")) + { + cmd_parser.printMessage(); + return 0; + } + bool fast_measure = cmd_parser.has("fast"); // fast measure fps + unsigned fix_fps = cmd_parser.get("fps"); // fixed frame per second + string backend = cmd_parser.get("backend"); // video backend + string mode = cmd_parser.get("mode"); // coding mode + string codec = cmd_parser.get("codec"); // codec type + string file_name = cmd_parser.get("file"); // path to videofile + string resolution = cmd_parser.get("resolution"); // video resolution + if (!cmd_parser.check()) + { + cmd_parser.printErrors(); + return -1; + } + if (mode != "encode" && mode != "decode") + { + cout << "Unsupported mode: " << mode << endl; + return -1; + } + cout << "Mode: " << mode << ", Backend: " << backend << ", File: " << file_name << ", Codec: " << codec << endl; + + TickMeter total; + Ptr cap; + Ptr wrt; try { - GStreamerPipeline pipe(argc, argv); - return pipe.run(); + if (mode == "decode") + { + cap = createCapture(backend, file_name, codec); + if (!cap) + { + cout << "Failed to create video capture" << endl; + return -3; + } + if (!cap->isOpened()) + { + cout << "Capture is not opened" << endl; + return -4; + } + } + else if (mode == "encode") + { + Size sz = getValue(sizeByResolution(), resolution, "Invalid resolution"); + cout << "FPS: " << fix_fps << ", Frame size: " << sz << endl; + cap = createSynthSource(sz, fix_fps); + wrt = createWriter(backend, file_name, codec, sz, fix_fps); + if (!cap || !wrt) + { + cout << "Failed to create synthetic video source or video writer" << endl; + return -3; + } + if (!cap->isOpened() || !wrt->isOpened()) + { + cout << "Synthetic video source or video writer is not opened" << endl; + return -4; + } + } } - catch(const Exception& e) + catch (...) { - cerr << e.what() << endl; - return 1; + cout << "Unsupported parameters" << endl; + return -2; } + + TickMeter tick; + Mat frame; + Mat element; + total.start(); + while(true) + { + if (mode == "decode") + { + tick.start(); + if (!cap->grab()) + { + cout << "No more frames - break" << endl; + break; + } + if (!cap->retrieve(frame)) + { + cout << "Failed to retrieve frame - break" << endl; + break; + } + if (frame.empty()) + { + cout << "Empty frame received - break" << endl; + break; + } + tick.stop(); + } + else if (mode == "encode") + { + int limit = 100; + while (!cap->grab() && --limit != 0) + { + cout << "Skipping empty input frame - " << limit << endl; + } + cap->retrieve(element); + tick.start(); + *wrt << element; + tick.stop(); + } + + if (fast_measure && tick.getCounter() >= 1000) + { + cout << "Fast mode frame limit reached - break" << endl; + break; + } + if (mode == "encode" && tick.getCounter() >= 1000) + { + cout << "Encode frame limit reached - break" << endl; + break; + } + } + total.stop(); + if (tick.getCounter() == 0) + { + cout << "No frames have been processed" << endl; + return -10; + } + else + { + double res_fps = tick.getCounter() / tick.getTimeSec(); + cout << tick.getCounter() << " frames in " << tick.getTimeSec() << " sec ~ " << res_fps << " FPS" << " (total time: " << total.getTimeSec() << " sec)" << endl; + } + return 0; } diff --git a/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp b/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp index 87a5436a6d..d038cbd874 100644 --- a/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp +++ b/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp @@ -1,5 +1,4 @@ /** - * @function Watershed_and_Distance_Transform.cpp * @brief Sample code showing how to segment overlapping objects using Laplacian filtering, in addition to Watershed and Distance Transformation * @author OpenCV Team */ @@ -12,43 +11,47 @@ using namespace std; using namespace cv; -int main() +int main(int argc, char *argv[]) { -//! [load_image] + //! [load_image] // Load the image - Mat src = imread("../data/cards.png"); - - // Check if everything was fine - if (!src.data) + CommandLineParser parser( argc, argv, "{@input | ../data/cards.png | input image}" ); + Mat src = imread( parser.get( "@input" ) ); + if( src.empty() ) + { + cout << "Could not open or find the image!\n" << endl; + cout << "Usage: " << argv[0] << " " << endl; return -1; + } // Show source image imshow("Source Image", src); -//! [load_image] + //! [load_image] -//! [black_bg] + //! [black_bg] // Change the background from white to black, since that will help later to extract // better results during the use of Distance Transform - for( int x = 0; x < src.rows; x++ ) { - for( int y = 0; y < src.cols; y++ ) { - if ( src.at(x, y) == Vec3b(255,255,255) ) { - src.at(x, y)[0] = 0; - src.at(x, y)[1] = 0; - src.at(x, y)[2] = 0; - } + for ( int i = 0; i < src.rows; i++ ) { + for ( int j = 0; j < src.cols; j++ ) { + if ( src.at(i, j) == Vec3b(255,255,255) ) + { + src.at(i, j)[0] = 0; + src.at(i, j)[1] = 0; + src.at(i, j)[2] = 0; + } } } // Show output image imshow("Black Background Image", src); -//! [black_bg] + //! [black_bg] -//! [sharp] - // Create a kernel that we will use for accuting/sharpening our image + //! [sharp] + // Create a kernel that we will use to sharpen our image Mat kernel = (Mat_(3,3) << - 1, 1, 1, - 1, -8, 1, - 1, 1, 1); // an approximation of second derivative, a quite strong kernel + 1, 1, 1, + 1, -8, 1, + 1, 1, 1); // an approximation of second derivative, a quite strong kernel // do the laplacian filtering as it is // well, we need to convert everything in something more deeper then CV_8U @@ -57,8 +60,8 @@ int main() // BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255 // so the possible negative number will be truncated Mat imgLaplacian; - Mat sharp = src; // copy source image to another temporary one - filter2D(sharp, imgLaplacian, CV_32F, kernel); + filter2D(src, imgLaplacian, CV_32F, kernel); + Mat sharp; src.convertTo(sharp, CV_32F); Mat imgResult = sharp - imgLaplacian; @@ -68,41 +71,39 @@ int main() // imshow( "Laplace Filtered Image", imgLaplacian ); imshow( "New Sharped Image", imgResult ); -//! [sharp] + //! [sharp] - src = imgResult; // copy back - -//! [bin] + //! [bin] // Create binary image from source image Mat bw; - cvtColor(src, bw, COLOR_BGR2GRAY); + cvtColor(imgResult, bw, COLOR_BGR2GRAY); threshold(bw, bw, 40, 255, THRESH_BINARY | THRESH_OTSU); imshow("Binary Image", bw); -//! [bin] + //! [bin] -//! [dist] + //! [dist] // Perform the distance transform algorithm Mat dist; distanceTransform(bw, dist, DIST_L2, 3); // Normalize the distance image for range = {0.0, 1.0} // so we can visualize and threshold it - normalize(dist, dist, 0, 1., NORM_MINMAX); + normalize(dist, dist, 0, 1.0, NORM_MINMAX); imshow("Distance Transform Image", dist); -//! [dist] + //! [dist] -//! [peaks] + //! [peaks] // Threshold to obtain the peaks // This will be the markers for the foreground objects - threshold(dist, dist, .4, 1., THRESH_BINARY); + threshold(dist, dist, 0.4, 1.0, THRESH_BINARY); // Dilate a bit the dist image - Mat kernel1 = Mat::ones(3, 3, CV_8UC1); + Mat kernel1 = Mat::ones(3, 3, CV_8U); dilate(dist, dist, kernel1); imshow("Peaks", dist); -//! [peaks] + //! [peaks] -//! [seeds] + //! [seeds] // Create the CV_8U version of the distance image // It is needed for findContours() Mat dist_8u; @@ -113,34 +114,36 @@ int main() findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // Create the marker image for the watershed algorithm - Mat markers = Mat::zeros(dist.size(), CV_32SC1); + Mat markers = Mat::zeros(dist.size(), CV_32S); // Draw the foreground markers for (size_t i = 0; i < contours.size(); i++) - drawContours(markers, contours, static_cast(i), Scalar::all(static_cast(i)+1), -1); + { + drawContours(markers, contours, static_cast(i), Scalar(static_cast(i)+1), -1); + } // Draw the background marker - circle(markers, Point(5,5), 3, CV_RGB(255,255,255), -1); + circle(markers, Point(5,5), 3, Scalar(255), -1); imshow("Markers", markers*10000); -//! [seeds] + //! [seeds] -//! [watershed] + //! [watershed] // Perform the watershed algorithm - watershed(src, markers); + watershed(imgResult, markers); - Mat mark = Mat::zeros(markers.size(), CV_8UC1); - markers.convertTo(mark, CV_8UC1); + Mat mark; + markers.convertTo(mark, CV_8U); bitwise_not(mark, mark); -// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark - // image looks like at that point + // imshow("Markers_v2", mark); // uncomment this if you want to see how the mark + // image looks like at that point // Generate random colors vector colors; for (size_t i = 0; i < contours.size(); i++) { - int b = theRNG().uniform(0, 255); - int g = theRNG().uniform(0, 255); - int r = theRNG().uniform(0, 255); + int b = theRNG().uniform(0, 256); + int g = theRNG().uniform(0, 256); + int r = theRNG().uniform(0, 256); colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r)); } @@ -155,16 +158,16 @@ int main() { int index = markers.at(i,j); if (index > 0 && index <= static_cast(contours.size())) + { dst.at(i,j) = colors[index-1]; - else - dst.at(i,j) = Vec3b(0,0,0); + } } } // Visualize the final image imshow("Final Result", dst); -//! [watershed] + //! [watershed] - waitKey(0); + waitKey(); return 0; } diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp index 233800e901..1083657ead 100644 --- a/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp +++ b/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp @@ -12,9 +12,8 @@ using namespace cv; using namespace std; -Mat src; Mat src_gray; +Mat src_gray; int thresh = 100; -int max_thresh = 255; RNG rng(12345); /// Function header @@ -25,34 +24,31 @@ void thresh_callback(int, void* ); */ int main( int argc, char** argv ) { - /// Load source image - String imageName("../data/happyfish.jpg"); // by default - if (argc > 1) - { - imageName = argv[1]; - } - src = imread(imageName, IMREAD_COLOR); + /// Load source image + CommandLineParser parser( argc, argv, "{@input | ../data/HappyFish.jpg | input image}" ); + Mat src = imread( parser.get( "@input" ) ); + if( src.empty() ) + { + cout << "Could not open or find the image!\n" << endl; + cout << "Usage: " << argv[0] << " " << endl; + return -1; + } - if (src.empty()) - { - cerr << "No image supplied ..." << endl; - return -1; - } + /// Convert image to gray and blur it + cvtColor( src, src_gray, COLOR_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); + /// Create Window + const char* source_window = "Source"; + namedWindow( source_window ); + imshow( source_window, src ); - /// Create Window - const char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); + const int max_thresh = 255; + createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); - createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); - - waitKey(0); - return(0); + waitKey(); + return 0; } /** @@ -60,24 +56,23 @@ int main( int argc, char** argv ) */ void thresh_callback(int, void* ) { - Mat canny_output; - vector > contours; - vector hierarchy; + /// Detect edges using Canny + Mat canny_output; + Canny( src_gray, canny_output, thresh, thresh*2 ); - /// Detect edges using canny - Canny( src_gray, canny_output, thresh, thresh*2, 3 ); - /// Find contours - findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); + /// Find contours + vector > contours; + vector hierarchy; + findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE ); - /// Draw contours - Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); - for( size_t i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, (int)i, color, 2, 8, hierarchy, 0, Point() ); - } + /// Draw contours + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + for( size_t i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); + drawContours( drawing, contours, (int)i, color, 2, LINE_8, hierarchy, 0 ); + } - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); + /// Show in a window + imshow( "Contours", drawing ); } diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp index ea0b2a47ef..f8eb194378 100644 --- a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp +++ b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp @@ -12,9 +12,8 @@ using namespace cv; using namespace std; -Mat src; Mat src_gray; +Mat src_gray; int thresh = 100; -int max_thresh = 255; RNG rng(12345); /// Function header @@ -25,42 +24,37 @@ void thresh_callback(int, void* ); */ int main( int argc, char** argv ) { - //![setup] - /// Load source image - CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); - src = imread( parser.get( "@input" ), IMREAD_COLOR ); - if( src.empty() ) + //! [setup] + /// Load source image + CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); + Mat src = imread( parser.get( "@input" ) ); + if( src.empty() ) { - cout << "Could not open or find the image!\n" << endl; - cout << "usage: " << argv[0] << " " << endl; - return -1; + cout << "Could not open or find the image!\n" << endl; + cout << "usage: " << argv[0] << " " << endl; + return -1; } - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); - //![setup] + /// Convert image to gray and blur it + cvtColor( src, src_gray, COLOR_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); + //! [setup] - //![createWindow] - /// Create Window - const char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); - //![createWindow] + //! [createWindow] + /// Create Window + const char* source_window = "Source"; + namedWindow( source_window ); + imshow( source_window, src ); + //! [createWindow] - //![taskbar] - createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); - //![taskbar] + //! [trackbar] + const int max_thresh = 255; + createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); + //! [trackbar] - //![callback00] - thresh_callback( 0, 0 ); - //![callback00] - - //![waitForIt] - waitKey(0); - //![waitForIt] - - return(0); + waitKey(); + return 0; } /** @@ -68,53 +62,50 @@ int main( int argc, char** argv ) */ void thresh_callback(int, void* ) { - Mat threshold_output; - vector > contours; - vector hierarchy; + //! [Canny] + /// Detect edges using Canny + Mat canny_output; + Canny( src_gray, canny_output, thresh, thresh*2 ); + //! [Canny] - //![threshold] - /// Detect edges using Threshold - threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); - //![threshold] + //! [findContours] + /// Find contours + vector > contours; + findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE ); + //! [findContours] - //![findContours] - /// Find contours - findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - //![findContours] + //! [allthework] + /// Approximate contours to polygons + get bounding rects and circles + vector > contours_poly( contours.size() ); + vector boundRect( contours.size() ); + vectorcenters( contours.size() ); + vectorradius( contours.size() ); - /// Approximate contours to polygons + get bounding rects and circles - vector > contours_poly( contours.size() ); - vector boundRect( contours.size() ); - vectorcenter( contours.size() ); - vectorradius( contours.size() ); + for( size_t i = 0; i < contours.size(); i++ ) + { + approxPolyDP( contours[i], contours_poly[i], 3, true ); + boundRect[i] = boundingRect( contours_poly[i] ); + minEnclosingCircle( contours_poly[i], centers[i], radius[i] ); + } + //! [allthework] - //![allthework] - for( size_t i = 0; i < contours.size(); i++ ) - { - approxPolyDP( contours[i], contours_poly[i], 3, true ); - boundRect[i] = boundingRect( contours_poly[i] ); - minEnclosingCircle( contours_poly[i], center[i], radius[i] ); - } - //![allthework] + //! [zeroMat] + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + //! [zeroMat] - //![zeroMat] - /// Draw polygonal contour + bonding rects + circles - Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); - //![zeroMat] + //! [forContour] + /// Draw polygonal contour + bonding rects + circles + for( size_t i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); + drawContours( drawing, contours_poly, (int)i, color ); + rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2 ); + circle( drawing, centers[i], (int)radius[i], color, 2 ); + } + //! [forContour] - //![forContour] - for( size_t i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours_poly, (int)i, color, 1, 8, vector(), 0, Point() ); - rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 ); - circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 ); - } - //![forContour] - - //![showDrawings] - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); - //![showDrawings] + //! [showDrawings] + /// Show in a window + imshow( "Contours", drawing ); + //! [showDrawings] } diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp index 169f8bf4e5..2018b64bb2 100644 --- a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp +++ b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp @@ -12,9 +12,8 @@ using namespace cv; using namespace std; -Mat src; Mat src_gray; +Mat src_gray; int thresh = 100; -int max_thresh = 255; RNG rng(12345); /// Function header @@ -25,30 +24,31 @@ void thresh_callback(int, void* ); */ int main( int argc, char** argv ) { - /// Load source image and convert it to gray - CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); - src = imread( parser.get( "@input" ), IMREAD_COLOR ); - if( src.empty() ) + /// Load source image and convert it to gray + CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); + Mat src = imread( parser.get( "@input" ) ); + if( src.empty() ) { - cout << "Could not open or find the image!\n" << endl; - cout << "Usage: " << argv[0] << " " << endl; - return -1; + cout << "Could not open or find the image!\n" << endl; + cout << "Usage: " << argv[0] << " " << endl; + return -1; } - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); + /// Convert image to gray and blur it + cvtColor( src, src_gray, COLOR_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); - /// Create Window - const char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); + /// Create Window + const char* source_window = "Source"; + namedWindow( source_window ); + imshow( source_window, src ); - createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); + const int max_thresh = 255; + createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); - waitKey(0); - return(0); + waitKey(); + return 0; } /** @@ -56,41 +56,43 @@ int main( int argc, char** argv ) */ void thresh_callback(int, void* ) { - Mat threshold_output; - vector > contours; - vector hierarchy; + /// Detect edges using Canny + Mat canny_output; + Canny( src_gray, canny_output, thresh, thresh*2 ); + /// Find contours + vector > contours; + findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); - /// Detect edges using Threshold - threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); - /// Find contours - findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); + /// Find the rotated rectangles and ellipses for each contour + vector minRect( contours.size() ); + vector minEllipse( contours.size() ); + for( size_t i = 0; i < contours.size(); i++ ) + { + minRect[i] = minAreaRect( contours[i] ); + if( contours[i].size() > 5 ) + { + minEllipse[i] = fitEllipse( contours[i] ); + } + } - /// Find the rotated rectangles and ellipses for each contour - vector minRect( contours.size() ); - vector minEllipse( contours.size() ); + /// Draw contours + rotated rects + ellipses + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + for( size_t i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); + // contour + drawContours( drawing, contours, (int)i, color ); + // ellipse + ellipse( drawing, minEllipse[i], color, 2 ); + // rotated rectangle + Point2f rect_points[4]; + minRect[i].points( rect_points ); + for ( int j = 0; j < 4; j++ ) + { + line( drawing, rect_points[j], rect_points[(j+1)%4], color ); + } + } - for( size_t i = 0; i < contours.size(); i++ ) - { minRect[i] = minAreaRect( contours[i] ); - if( contours[i].size() > 5 ) - { minEllipse[i] = fitEllipse( contours[i] ); } - } - - /// Draw contours + rotated rects + ellipses - Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); - for( size_t i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - // contour - drawContours( drawing, contours, (int)i, color, 1, 8, vector(), 0, Point() ); - // ellipse - ellipse( drawing, minEllipse[i], color, 2, 8 ); - // rotated rectangle - Point2f rect_points[4]; minRect[i].points( rect_points ); - for( int j = 0; j < 4; j++ ) - line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 ); - } - - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); + /// Show in a window + imshow( "Contours", drawing ); } diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp index c1559088ba..6640286feb 100644 --- a/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp +++ b/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp @@ -12,9 +12,8 @@ using namespace cv; using namespace std; -Mat src; Mat src_gray; +Mat src_gray; int thresh = 100; -int max_thresh = 255; RNG rng(12345); /// Function header @@ -25,30 +24,31 @@ void thresh_callback(int, void* ); */ int main( int argc, char** argv ) { - /// Load source image and convert it to gray - CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); - src = imread( parser.get( "@input" ), IMREAD_COLOR ); - if( src.empty() ) - { - cout << "Could not open or find the image!\n" << endl; - cout << "Usage: " << argv[0] << " " << endl; - return -1; - } + /// Load source image and convert it to gray + CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); + Mat src = imread( parser.get( "@input" ) ); + if( src.empty() ) + { + cout << "Could not open or find the image!\n" << endl; + cout << "Usage: " << argv[0] << " " << endl; + return -1; + } - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); + /// Convert image to gray and blur it + cvtColor( src, src_gray, COLOR_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); - /// Create Window - const char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); + /// Create Window + const char* source_window = "Source"; + namedWindow( source_window ); + imshow( source_window, src ); - createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); + const int max_thresh = 255; + createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); - waitKey(0); - return(0); + waitKey(); + return 0; } /** @@ -56,31 +56,30 @@ int main( int argc, char** argv ) */ void thresh_callback(int, void* ) { - Mat threshold_output; - vector > contours; - vector hierarchy; + /// Detect edges using Canny + Mat canny_output; + Canny( src_gray, canny_output, thresh, thresh*2 ); - /// Detect edges using Threshold - threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY ); + /// Find contours + vector > contours; + findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE ); - /// Find contours - findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) ); + /// Find the convex hull object for each contour + vector >hull( contours.size() ); + for( size_t i = 0; i < contours.size(); i++ ) + { + convexHull( contours[i], hull[i] ); + } - /// Find the convex hull object for each contour - vector >hull( contours.size() ); - for( size_t i = 0; i < contours.size(); i++ ) - { convexHull( contours[i], hull[i], false ); } + /// Draw contours + hull results + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + for( size_t i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); + drawContours( drawing, contours, (int)i, color ); + drawContours( drawing, hull, (int)i, color ); + } - /// Draw contours + hull results - Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 ); - for( size_t i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, (int)i, color, 1, 8, vector(), 0, Point() ); - drawContours( drawing, hull, (int)i, color, 1, 8, vector(), 0, Point() ); - } - - /// Show in a window - namedWindow( "Hull demo", WINDOW_AUTOSIZE ); - imshow( "Hull demo", drawing ); + /// Show in a window + imshow( "Hull demo", drawing ); } diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp index 6741cc61b3..eaccd14e83 100644 --- a/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp +++ b/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp @@ -8,13 +8,13 @@ #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include +#include using namespace cv; using namespace std; -Mat src; Mat src_gray; +Mat src_gray; int thresh = 100; -int max_thresh = 255; RNG rng(12345); /// Function header @@ -25,31 +25,32 @@ void thresh_callback(int, void* ); */ int main( int argc, char** argv ) { - /// Load source image and convert it to gray - CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); - src = imread( parser.get( "@input" ), IMREAD_COLOR ); + /// Load source image + CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" ); + Mat src = imread( parser.get( "@input" ) ); - if( src.empty() ) - { - cout << "Could not open or find the image!\n" << endl; - cout << "usage: " << argv[0] << " " << endl; - exit(0); - } + if( src.empty() ) + { + cout << "Could not open or find the image!\n" << endl; + cout << "usage: " << argv[0] << " " << endl; + return -1; + } - /// Convert image to gray and blur it - cvtColor( src, src_gray, COLOR_BGR2GRAY ); - blur( src_gray, src_gray, Size(3,3) ); + /// Convert image to gray and blur it + cvtColor( src, src_gray, COLOR_BGR2GRAY ); + blur( src_gray, src_gray, Size(3,3) ); - /// Create Window - const char* source_window = "Source"; - namedWindow( source_window, WINDOW_AUTOSIZE ); - imshow( source_window, src ); + /// Create Window + const char* source_window = "Source"; + namedWindow( source_window ); + imshow( source_window, src ); - createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback ); - thresh_callback( 0, 0 ); + const int max_thresh = 255; + createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); + thresh_callback( 0, 0 ); - waitKey(0); - return(0); + waitKey(); + return 0; } /** @@ -57,44 +58,47 @@ int main( int argc, char** argv ) */ void thresh_callback(int, void* ) { - Mat canny_output; - vector > contours; + /// Detect edges using canny + Mat canny_output; + Canny( src_gray, canny_output, thresh, thresh*2, 3 ); + /// Find contours + vector > contours; + findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE ); - /// Detect edges using canny - Canny( src_gray, canny_output, thresh, thresh*2, 3 ); - /// Find contours - findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE ); + /// Get the moments + vector mu(contours.size() ); + for( size_t i = 0; i < contours.size(); i++ ) + { + mu[i] = moments( contours[i] ); + } - /// Get the moments - vector mu(contours.size() ); - for( size_t i = 0; i < contours.size(); i++ ) - { mu[i] = moments( contours[i], false ); } + /// Get the mass centers + vector mc( contours.size() ); + for( size_t i = 0; i < contours.size(); i++ ) + { + //add 1e-5 to avoid division by zero + mc[i] = Point2f( static_cast(mu[i].m10 / (mu[i].m00 + 1e-5)), + static_cast(mu[i].m01 / (mu[i].m00 + 1e-5)) ); + cout << "mc[" << i << "]=" << mc[i] << endl; + } - /// Get the mass centers: - vector mc( contours.size() ); - for( size_t i = 0; i < contours.size(); i++ ) - { mc[i] = Point2f( static_cast(mu[i].m10/mu[i].m00) , static_cast(mu[i].m01/mu[i].m00) ); } + /// Draw contours + Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); + for( size_t i = 0; i< contours.size(); i++ ) + { + Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); + drawContours( drawing, contours, (int)i, color, 2 ); + circle( drawing, mc[i], 4, color, -1 ); + } - /// Draw contours - Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); - for( size_t i = 0; i< contours.size(); i++ ) - { - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, (int)i, color, 2, LINE_8 ); - circle( drawing, mc[i], 4, color, -1, 8, 0 ); - } + /// Show in a window + imshow( "Contours", drawing ); - /// Show in a window - namedWindow( "Contours", WINDOW_AUTOSIZE ); - imshow( "Contours", drawing ); - - /// Calculate the area with the moments 00 and compare with the result of the OpenCV function - printf("\t Info: Area and Contour Length \n"); - for( size_t i = 0; i< contours.size(); i++ ) - { - printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", (int)i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) ); - Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); - drawContours( drawing, contours, (int)i, color, 2, LINE_8 ); - circle( drawing, mc[i], 4, color, -1, 8, 0 ); - } + /// Calculate the area with the moments 00 and compare with the result of the OpenCV function + cout << "\t Info: Area and Contour Length \n"; + for( size_t i = 0; i < contours.size(); i++ ) + { + cout << " * Contour[" << i << "] - Area (M_00) = " << std::fixed << std::setprecision(2) << mu[i].m00 + << " - Area OpenCV: " << contourArea(contours[i]) << " - Length: " << arcLength( contours[i], true ) << endl; + } } diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp index efc481a5b2..da3feedc15 100644 --- a/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp +++ b/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp @@ -16,60 +16,71 @@ using namespace std; */ int main( void ) { - /// Create an image - const int r = 100; - Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8UC1 ); + /// Create an image + const int r = 100; + Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U ); - /// Create a sequence of points to make a contour: - vector vert(6); + /// Create a sequence of points to make a contour + vector vert(6); + vert[0] = Point( 3*r/2, static_cast(1.34*r) ); + vert[1] = Point( 1*r, 2*r ); + vert[2] = Point( 3*r/2, static_cast(2.866*r) ); + vert[3] = Point( 5*r/2, static_cast(2.866*r) ); + vert[4] = Point( 3*r, 2*r ); + vert[5] = Point( 5*r/2, static_cast(1.34*r) ); - vert[0] = Point( 3*r/2, static_cast(1.34*r) ); - vert[1] = Point( 1*r, 2*r ); - vert[2] = Point( 3*r/2, static_cast(2.866*r) ); - vert[3] = Point( 5*r/2, static_cast(2.866*r) ); - vert[4] = Point( 3*r, 2*r ); - vert[5] = Point( 5*r/2, static_cast(1.34*r) ); + /// Draw it in src + for( int i = 0; i < 6; i++ ) + { + line( src, vert[i], vert[(i+1)%6], Scalar( 255 ), 3 ); + } - /// Draw it in src - for( int j = 0; j < 6; j++ ) - { line( src, vert[j], vert[(j+1)%6], Scalar( 255 ), 3, 8 ); } + /// Get the contours + vector > contours; + findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE); - /// Get the contours - vector > contours; + /// Calculate the distances to the contour + Mat raw_dist( src.size(), CV_32F ); + for( int i = 0; i < src.rows; i++ ) + { + for( int j = 0; j < src.cols; j++ ) + { + raw_dist.at(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true ); + } + } - findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE); + double minVal, maxVal; + minMaxLoc( raw_dist, &minVal, &maxVal ); + minVal = abs(minVal); + maxVal = abs(maxVal); - /// Calculate the distances to the contour - Mat raw_dist( src.size(), CV_32FC1 ); - - for( int j = 0; j < src.rows; j++ ) - { for( int i = 0; i < src.cols; i++ ) - { raw_dist.at(j,i) = (float)pointPolygonTest( contours[0], Point2f((float)i,(float)j), true ); } - } - - double minVal; double maxVal; - minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() ); - minVal = abs(minVal); maxVal = abs(maxVal); - - /// Depicting the distances graphically - Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); - - for( int j = 0; j < src.rows; j++ ) - { for( int i = 0; i < src.cols; i++ ) - { - if( raw_dist.at(j,i) < 0 ) - { drawing.at(j,i)[0] = (uchar)(255 - abs(raw_dist.at(j,i))*255/minVal); } - else if( raw_dist.at(j,i) > 0 ) - { drawing.at(j,i)[2] = (uchar)(255 - raw_dist.at(j,i)*255/maxVal); } + /// Depicting the distances graphically + Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); + for( int i = 0; i < src.rows; i++ ) + { + for( int j = 0; j < src.cols; j++ ) + { + if( raw_dist.at(i,j) < 0 ) + { + drawing.at(i,j)[0] = (uchar)(255 - abs(raw_dist.at(i,j)) * 255 / minVal); + } + else if( raw_dist.at(i,j) > 0 ) + { + drawing.at(i,j)[2] = (uchar)(255 - raw_dist.at(i,j) * 255 / maxVal); + } else - { drawing.at(j,i)[0] = 255; drawing.at(j,i)[1] = 255; drawing.at(j,i)[2] = 255; } - } - } + { + drawing.at(i,j)[0] = 255; + drawing.at(i,j)[1] = 255; + drawing.at(i,j)[2] = 255; + } + } + } - /// Show your results - imshow( "Source", src ); - imshow( "Distance", drawing ); + /// Show your results + imshow( "Source", src ); + imshow( "Distance", drawing ); - waitKey(0); - return(0); + waitKey(); + return 0; } diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp index 1eb1df6a10..b5b1b9229e 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp @@ -6,11 +6,12 @@ using namespace std; using namespace cv; -const float inlier_threshold = 2.5f; // Distance threshold to identify inliers +const float inlier_threshold = 2.5f; // Distance threshold to identify inliers with homography check const float nn_match_ratio = 0.8f; // Nearest neighbor matching ratio int main(int argc, char* argv[]) { + //! [load] CommandLineParser parser(argc, argv, "{@img1 | ../data/graf1.png | input image 1}" "{@img2 | ../data/graf3.png | input image 2}" @@ -21,20 +22,25 @@ int main(int argc, char* argv[]) Mat homography; FileStorage fs(parser.get("@homography"), FileStorage::READ); fs.getFirstTopLevelNode() >> homography; + //! [load] + //! [AKAZE] vector kpts1, kpts2; Mat desc1, desc2; Ptr akaze = AKAZE::create(); akaze->detectAndCompute(img1, noArray(), kpts1, desc1); akaze->detectAndCompute(img2, noArray(), kpts2, desc2); + //! [AKAZE] + //! [2-nn matching] BFMatcher matcher(NORM_HAMMING); vector< vector > nn_matches; matcher.knnMatch(desc1, desc2, nn_matches, 2); + //! [2-nn matching] - vector matched1, matched2, inliers1, inliers2; - vector good_matches; + //! [ratio test filtering] + vector matched1, matched2; for(size_t i = 0; i < nn_matches.size(); i++) { DMatch first = nn_matches[i][0]; float dist1 = nn_matches[i][0].distance; @@ -45,8 +51,12 @@ int main(int argc, char* argv[]) matched2.push_back(kpts2[first.trainIdx]); } } + //! [ratio test filtering] - for(unsigned i = 0; i < matched1.size(); i++) { + //! [homography check] + vector good_matches; + vector inliers1, inliers2; + for(size_t i = 0; i < matched1.size(); i++) { Mat col = Mat::ones(3, 1, CV_64F); col.at(0) = matched1[i].pt.x; col.at(1) = matched1[i].pt.y; @@ -63,12 +73,14 @@ int main(int argc, char* argv[]) good_matches.push_back(DMatch(new_i, new_i, 0)); } } + //! [homography check] + //! [draw final matches] Mat res; drawMatches(img1, inliers1, img2, inliers2, good_matches, res); imwrite("akaze_result.png", res); - double inlier_ratio = inliers1.size() * 1.0 / matched1.size(); + double inlier_ratio = inliers1.size() / (double) matched1.size(); cout << "A-KAZE Matching Results" << endl; cout << "*******************************" << endl; cout << "# Keypoints 1: \t" << kpts1.size() << endl; @@ -80,6 +92,7 @@ int main(int argc, char* argv[]) imshow("result", res); waitKey(); + //! [draw final matches] return 0; } diff --git a/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp b/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp index e22155f471..1724709828 100755 --- a/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp +++ b/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp @@ -46,7 +46,7 @@ int main( int argc, char* argv[] ) std::vector good_matches; for (size_t i = 0; i < knn_matches.size(); i++) { - if (knn_matches[i].size() > 1 && knn_matches[i][0].distance / knn_matches[i][1].distance <= ratio_thresh) + if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance) { good_matches.push_back(knn_matches[i][0]); } diff --git a/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp b/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp index 68b1d2a720..231cda887d 100755 --- a/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp +++ b/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp @@ -48,7 +48,7 @@ int main( int argc, char* argv[] ) std::vector good_matches; for (size_t i = 0; i < knn_matches.size(); i++) { - if (knn_matches[i].size() > 1 && knn_matches[i][0].distance / knn_matches[i][1].distance <= ratio_thresh) + if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance) { good_matches.push_back(knn_matches[i][0]); } diff --git a/samples/cpp/videocapture_basic.cpp b/samples/cpp/videocapture_basic.cpp index 6f46715458..75992f6a0c 100644 --- a/samples/cpp/videocapture_basic.cpp +++ b/samples/cpp/videocapture_basic.cpp @@ -20,7 +20,7 @@ int main(int, char**) //--- INITIALIZE VIDEOCAPTURE VideoCapture cap; // open the default camera using default API - cap.open(0); + // cap.open(0); // OR advance usage: select any API backend int deviceID = 0; // 0 = open default camera int apiID = cv::CAP_ANY; // 0 = autodetect default API diff --git a/samples/cpp/videocapture_camera.cpp b/samples/cpp/videocapture_camera.cpp index 4d5a341657..ca39b2093b 100644 --- a/samples/cpp/videocapture_camera.cpp +++ b/samples/cpp/videocapture_camera.cpp @@ -11,7 +11,7 @@ int main(int, char**) { Mat frame; cout << "Opening camera..." << endl; - VideoCapture capture(-1); // open the first available camera + VideoCapture capture(0); // open the first camera if (!capture.isOpened()) { cerr << "ERROR: Can't initialize camera capture" << endl; diff --git a/samples/data/dnn/object_detection_classes_coco.txt b/samples/data/dnn/object_detection_classes_coco.txt index 75aa546f48..10ecf0b455 100644 --- a/samples/data/dnn/object_detection_classes_coco.txt +++ b/samples/data/dnn/object_detection_classes_coco.txt @@ -9,7 +9,7 @@ truck boat traffic light fire hydrant - +street sign stop sign parking meter bench @@ -23,11 +23,11 @@ elephant bear zebra giraffe - +hat backpack umbrella - - +shoe +eye glasses handbag tie suitcase @@ -42,7 +42,7 @@ skateboard surfboard tennis racket bottle - +plate wine glass cup fork @@ -63,12 +63,12 @@ chair couch potted plant bed - +mirror dining table - - +window +desk toilet - +door tv laptop mouse @@ -80,7 +80,7 @@ oven toaster sink refrigerator - +blender book clock vase diff --git a/samples/data/dnn/object_detection_classes_yolov3.txt b/samples/data/dnn/object_detection_classes_yolov3.txt new file mode 100644 index 0000000000..941cb4e139 --- /dev/null +++ b/samples/data/dnn/object_detection_classes_yolov3.txt @@ -0,0 +1,80 @@ +person +bicycle +car +motorcycle +airplane +bus +train +truck +boat +traffic light +fire hydrant +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +backpack +umbrella +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +couch +potted plant +bed +dining table +toilet +tv +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +book +clock +vase +scissors +teddy bear +hair drier +toothbrush diff --git a/samples/dnn/object_detection.cpp b/samples/dnn/object_detection.cpp index 084d41bb5f..922bdcc9a0 100644 --- a/samples/dnn/object_detection.cpp +++ b/samples/dnn/object_detection.cpp @@ -22,6 +22,7 @@ const char* keys = "{ height | -1 | Preprocess input image by resizing to a specific height. }" "{ rgb | | Indicate that model works with RGB input images instead BGR ones. }" "{ thr | .5 | Confidence threshold. }" + "{ thr | .4 | Non-maximum suppression threshold. }" "{ backend | 0 | Choose one of computation backends: " "0: automatically (by default), " "1: Halide language (http://halide-lang.org/), " @@ -37,7 +38,7 @@ const char* keys = using namespace cv; using namespace dnn; -float confThreshold; +float confThreshold, nmsThreshold; std::vector classes; void postprocess(Mat& frame, const std::vector& out, Net& net); @@ -59,6 +60,7 @@ int main(int argc, char** argv) } confThreshold = parser.get("thr"); + nmsThreshold = parser.get("nms"); float scale = parser.get("scale"); Scalar mean = parser.get("mean"); bool swapRB = parser.get("rgb"); @@ -144,6 +146,9 @@ void postprocess(Mat& frame, const std::vector& outs, Net& net) static std::vector outLayers = net.getUnconnectedOutLayers(); static std::string outLayerType = net.getLayer(outLayers[0])->type; + std::vector classIds; + std::vector confidences; + std::vector boxes; if (net.getLayer(0)->outputNameToIndex("im_info") != -1) // Faster-RCNN or R-FCN { // Network produces output blob with a shape 1x1xNx7 where N is a number of @@ -160,8 +165,11 @@ void postprocess(Mat& frame, const std::vector& outs, Net& net) int top = (int)data[i + 4]; int right = (int)data[i + 5]; int bottom = (int)data[i + 6]; - int classId = (int)(data[i + 1]) - 1; // Skip 0th background class id. - drawPred(classId, confidence, left, top, right, bottom, frame); + int width = right - left + 1; + int height = bottom - top + 1; + classIds.push_back((int)(data[i + 1]) - 1); // Skip 0th background class id. + boxes.push_back(Rect(left, top, width, height)); + confidences.push_back(confidence); } } } @@ -181,16 +189,16 @@ void postprocess(Mat& frame, const std::vector& outs, Net& net) int top = (int)(data[i + 4] * frame.rows); int right = (int)(data[i + 5] * frame.cols); int bottom = (int)(data[i + 6] * frame.rows); - int classId = (int)(data[i + 1]) - 1; // Skip 0th background class id. - drawPred(classId, confidence, left, top, right, bottom, frame); + int width = right - left + 1; + int height = bottom - top + 1; + classIds.push_back((int)(data[i + 1]) - 1); // Skip 0th background class id. + boxes.push_back(Rect(left, top, width, height)); + confidences.push_back(confidence); } } } else if (outLayerType == "Region") { - std::vector classIds; - std::vector confidences; - std::vector boxes; for (size_t i = 0; i < outs.size(); ++i) { // Network produces output blob with a shape NxC where N is a number of @@ -218,18 +226,19 @@ void postprocess(Mat& frame, const std::vector& outs, Net& net) } } } - std::vector indices; - NMSBoxes(boxes, confidences, confThreshold, 0.4f, indices); - for (size_t i = 0; i < indices.size(); ++i) - { - int idx = indices[i]; - Rect box = boxes[idx]; - drawPred(classIds[idx], confidences[idx], box.x, box.y, - box.x + box.width, box.y + box.height, frame); - } } else CV_Error(Error::StsNotImplemented, "Unknown output layer type: " + outLayerType); + + std::vector indices; + NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices); + for (size_t i = 0; i < indices.size(); ++i) + { + int idx = indices[i]; + Rect box = boxes[idx]; + drawPred(classIds[idx], confidences[idx], box.x, box.y, + box.x + box.width, box.y + box.height, frame); + } } void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame) diff --git a/samples/dnn/object_detection.py b/samples/dnn/object_detection.py index b191cd4925..386e02890d 100644 --- a/samples/dnn/object_detection.py +++ b/samples/dnn/object_detection.py @@ -31,6 +31,7 @@ parser.add_argument('--height', type=int, parser.add_argument('--rgb', action='store_true', help='Indicate that model works with RGB input images instead BGR ones.') parser.add_argument('--thr', type=float, default=0.5, help='Confidence threshold') +parser.add_argument('--nms', type=float, default=0.4, help='Non-maximum suppression threshold') parser.add_argument('--backend', choices=backends, default=cv.dnn.DNN_BACKEND_DEFAULT, type=int, help="Choose one of computation backends: " "%d: automatically (by default), " @@ -57,6 +58,7 @@ net.setPreferableBackend(args.backend) net.setPreferableTarget(args.target) confThreshold = args.thr +nmsThreshold = args.nms def getOutputsNames(net): layersNames = net.getLayerNames() @@ -86,36 +88,43 @@ def postprocess(frame, outs): lastLayerId = net.getLayerId(layerNames[-1]) lastLayer = net.getLayer(lastLayerId) + classIds = [] + confidences = [] + boxes = [] if net.getLayer(0).outputNameToIndex('im_info') != -1: # Faster-RCNN or R-FCN # Network produces output blob with a shape 1x1xNx7 where N is a number of # detections and an every detection is a vector of values # [batchId, classId, confidence, left, top, right, bottom] - assert(len(outs) == 1) - out = outs[0] - for detection in out[0, 0]: - confidence = detection[2] - if confidence > confThreshold: - left = int(detection[3]) - top = int(detection[4]) - right = int(detection[5]) - bottom = int(detection[6]) - classId = int(detection[1]) - 1 # Skip background label - drawPred(classId, confidence, left, top, right, bottom) + for out in outs: + for detection in out[0, 0]: + confidence = detection[2] + if confidence > confThreshold: + left = int(detection[3]) + top = int(detection[4]) + right = int(detection[5]) + bottom = int(detection[6]) + width = right - left + 1 + height = bottom - top + 1 + classIds.append(int(detection[1]) - 1) # Skip background label + confidences.append(float(confidence)) + boxes.append([left, top, width, height]) elif lastLayer.type == 'DetectionOutput': # Network produces output blob with a shape 1x1xNx7 where N is a number of # detections and an every detection is a vector of values # [batchId, classId, confidence, left, top, right, bottom] - assert(len(outs) == 1) - out = outs[0] - for detection in out[0, 0]: - confidence = detection[2] - if confidence > confThreshold: - left = int(detection[3] * frameWidth) - top = int(detection[4] * frameHeight) - right = int(detection[5] * frameWidth) - bottom = int(detection[6] * frameHeight) - classId = int(detection[1]) - 1 # Skip background label - drawPred(classId, confidence, left, top, right, bottom) + for out in outs: + for detection in out[0, 0]: + confidence = detection[2] + if confidence > confThreshold: + left = int(detection[3] * frameWidth) + top = int(detection[4] * frameHeight) + right = int(detection[5] * frameWidth) + bottom = int(detection[6] * frameHeight) + width = right - left + 1 + height = bottom - top + 1 + classIds.append(int(detection[1]) - 1) # Skip background label + confidences.append(float(confidence)) + boxes.append([left, top, width, height]) elif lastLayer.type == 'Region': # Network produces output blob with a shape NxC where N is a number of # detected objects and C is a number of classes + 4 where the first 4 @@ -138,15 +147,19 @@ def postprocess(frame, outs): classIds.append(classId) confidences.append(float(confidence)) boxes.append([left, top, width, height]) - indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, 0.4) - for i in indices: - i = i[0] - box = boxes[i] - left = box[0] - top = box[1] - width = box[2] - height = box[3] - drawPred(classIds[i], confidences[i], left, top, left + width, top + height) + else: + print('Unknown output layer type: ' + lastLayer.type) + exit() + + indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold) + for i in indices: + i = i[0] + box = boxes[i] + left = box[0] + top = box[1] + width = box[2] + height = box[3] + drawPred(classIds[i], confidences[i], left, top, left + width, top + height) # Process inputs winName = 'Deep learning object detection in OpenCV' diff --git a/samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java b/samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java new file mode 100644 index 0000000000..8f44a378fb --- /dev/null +++ b/samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java @@ -0,0 +1,219 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +/** + * + * @brief Sample code showing how to segment overlapping objects using Laplacian filtering, in addition to Watershed + * and Distance Transformation + * + */ +class ImageSegmentation { + public void run(String[] args) { + //! [load_image] + // Load the image + String filename = args.length > 0 ? args[0] : "../data/cards.png"; + Mat srcOriginal = Imgcodecs.imread(filename); + if (srcOriginal.empty()) { + System.err.println("Cannot read image: " + filename); + System.exit(0); + } + + // Show source image + HighGui.imshow("Source Image", srcOriginal); + //! [load_image] + + //! [black_bg] + // Change the background from white to black, since that will help later to + // extract + // better results during the use of Distance Transform + Mat src = srcOriginal.clone(); + byte[] srcData = new byte[(int) (src.total() * src.channels())]; + src.get(0, 0, srcData); + for (int i = 0; i < src.rows(); i++) { + for (int j = 0; j < src.cols(); j++) { + if (srcData[(i * src.cols() + j) * 3] == (byte) 255 && srcData[(i * src.cols() + j) * 3 + 1] == (byte) 255 + && srcData[(i * src.cols() + j) * 3 + 2] == (byte) 255) { + srcData[(i * src.cols() + j) * 3] = 0; + srcData[(i * src.cols() + j) * 3 + 1] = 0; + srcData[(i * src.cols() + j) * 3 + 2] = 0; + } + } + } + src.put(0, 0, srcData); + + // Show output image + HighGui.imshow("Black Background Image", src); + //! [black_bg] + + //! [sharp] + // Create a kernel that we will use to sharpen our image + Mat kernel = new Mat(3, 3, CvType.CV_32F); + // an approximation of second derivative, a quite strong kernel + float[] kernelData = new float[(int) (kernel.total() * kernel.channels())]; + kernelData[0] = 1; kernelData[1] = 1; kernelData[2] = 1; + kernelData[3] = 1; kernelData[4] = -8; kernelData[5] = 1; + kernelData[6] = 1; kernelData[7] = 1; kernelData[8] = 1; + kernel.put(0, 0, kernelData); + + // do the laplacian filtering as it is + // well, we need to convert everything in something more deeper then CV_8U + // because the kernel has some negative values, + // and we can expect in general to have a Laplacian image with negative values + // BUT a 8bits unsigned int (the one we are working with) can contain values + // from 0 to 255 + // so the possible negative number will be truncated + Mat imgLaplacian = new Mat(); + Imgproc.filter2D(src, imgLaplacian, CvType.CV_32F, kernel); + Mat sharp = new Mat(); + src.convertTo(sharp, CvType.CV_32F); + Mat imgResult = new Mat(); + Core.subtract(sharp, imgLaplacian, imgResult); + + // convert back to 8bits gray scale + imgResult.convertTo(imgResult, CvType.CV_8UC3); + imgLaplacian.convertTo(imgLaplacian, CvType.CV_8UC3); + + // imshow( "Laplace Filtered Image", imgLaplacian ); + HighGui.imshow("New Sharped Image", imgResult); + //! [sharp] + + //! [bin] + // Create binary image from source image + Mat bw = new Mat(); + Imgproc.cvtColor(imgResult, bw, Imgproc.COLOR_BGR2GRAY); + Imgproc.threshold(bw, bw, 40, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU); + HighGui.imshow("Binary Image", bw); + //! [bin] + + //! [dist] + // Perform the distance transform algorithm + Mat dist = new Mat(); + Imgproc.distanceTransform(bw, dist, Imgproc.DIST_L2, 3); + + // Normalize the distance image for range = {0.0, 1.0} + // so we can visualize and threshold it + Core.normalize(dist, dist, 0.0, 1.0, Core.NORM_MINMAX); + Mat distDisplayScaled = new Mat(); + Core.multiply(dist, new Scalar(255), distDisplayScaled); + Mat distDisplay = new Mat(); + distDisplayScaled.convertTo(distDisplay, CvType.CV_8U); + HighGui.imshow("Distance Transform Image", distDisplay); + //! [dist] + + //! [peaks] + // Threshold to obtain the peaks + // This will be the markers for the foreground objects + Imgproc.threshold(dist, dist, 0.4, 1.0, Imgproc.THRESH_BINARY); + + // Dilate a bit the dist image + Mat kernel1 = Mat.ones(3, 3, CvType.CV_8U); + Imgproc.dilate(dist, dist, kernel1); + Mat distDisplay2 = new Mat(); + dist.convertTo(distDisplay2, CvType.CV_8U); + Core.multiply(distDisplay2, new Scalar(255), distDisplay2); + HighGui.imshow("Peaks", distDisplay2); + //! [peaks] + + //! [seeds] + // Create the CV_8U version of the distance image + // It is needed for findContours() + Mat dist_8u = new Mat(); + dist.convertTo(dist_8u, CvType.CV_8U); + + // Find total markers + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(dist_8u, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); + + // Create the marker image for the watershed algorithm + Mat markers = Mat.zeros(dist.size(), CvType.CV_32S); + + // Draw the foreground markers + for (int i = 0; i < contours.size(); i++) { + Imgproc.drawContours(markers, contours, i, new Scalar(i + 1), -1); + } + + // Draw the background marker + Mat markersScaled = new Mat(); + markers.convertTo(markersScaled, CvType.CV_32F); + Core.normalize(markersScaled, markersScaled, 0.0, 255.0, Core.NORM_MINMAX); + Imgproc.circle(markersScaled, new Point(5, 5), 3, new Scalar(255, 255, 255), -1); + Mat markersDisplay = new Mat(); + markersScaled.convertTo(markersDisplay, CvType.CV_8U); + HighGui.imshow("Markers", markersDisplay); + Imgproc.circle(markers, new Point(5, 5), 3, new Scalar(255, 255, 255), -1); + //! [seeds] + + //! [watershed] + // Perform the watershed algorithm + Imgproc.watershed(imgResult, markers); + + Mat mark = Mat.zeros(markers.size(), CvType.CV_8U); + markers.convertTo(mark, CvType.CV_8UC1); + Core.bitwise_not(mark, mark); + // imshow("Markers_v2", mark); // uncomment this if you want to see how the mark + // image looks like at that point + + // Generate random colors + Random rng = new Random(12345); + List colors = new ArrayList<>(contours.size()); + for (int i = 0; i < contours.size(); i++) { + int b = rng.nextInt(256); + int g = rng.nextInt(256); + int r = rng.nextInt(256); + + colors.add(new Scalar(b, g, r)); + } + + // Create the result image + Mat dst = Mat.zeros(markers.size(), CvType.CV_8UC3); + byte[] dstData = new byte[(int) (dst.total() * dst.channels())]; + dst.get(0, 0, dstData); + + // Fill labeled objects with random colors + int[] markersData = new int[(int) (markers.total() * markers.channels())]; + markers.get(0, 0, markersData); + for (int i = 0; i < markers.rows(); i++) { + for (int j = 0; j < markers.cols(); j++) { + int index = markersData[i * markers.cols() + j]; + if (index > 0 && index <= contours.size()) { + dstData[(i * dst.cols() + j) * 3 + 0] = (byte) colors.get(index - 1).val[0]; + dstData[(i * dst.cols() + j) * 3 + 1] = (byte) colors.get(index - 1).val[1]; + dstData[(i * dst.cols() + j) * 3 + 2] = (byte) colors.get(index - 1).val[2]; + } else { + dstData[(i * dst.cols() + j) * 3 + 0] = 0; + dstData[(i * dst.cols() + j) * 3 + 1] = 0; + dstData[(i * dst.cols() + j) * 3 + 2] = 0; + } + } + } + dst.put(0, 0, dstData); + + // Visualize the final image + HighGui.imshow("Final Result", dst); + //! [watershed] + + HighGui.waitKey(); + System.exit(0); + } +} + +public class ImageSegmentationDemo { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + new ImageSegmentation().run(args); + } +} diff --git a/samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java b/samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java new file mode 100644 index 0000000000..85bbf45e5f --- /dev/null +++ b/samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java @@ -0,0 +1,179 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.MatOfPoint2f; +import org.opencv.core.Point; +import org.opencv.core.Rect; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +class GeneralContours1 { + private Mat srcGray = new Mat(); + private JFrame frame; + private JLabel imgSrcLabel; + private JLabel imgContoursLabel; + private static final int MAX_THRESHOLD = 255; + private int threshold = 100; + private Random rng = new Random(12345); + + public GeneralContours1(String[] args) { + //! [setup] + /// Load source image + String filename = args.length > 0 ? args[0] : "../data/stuff.jpg"; + Mat src = Imgcodecs.imread(filename); + if (src.empty()) { + System.err.println("Cannot read image: " + filename); + System.exit(0); + } + + /// Convert image to gray and blur it + Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY); + Imgproc.blur(srcGray, srcGray, new Size(3, 3)); + //! [setup] + + //! [createWindow] + // Create and set up the window. + frame = new JFrame("Creating Bounding boxes and circles for contours demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + Image img = HighGui.toBufferedImage(src); + addComponentsToPane(frame.getContentPane(), img); + //! [createWindow] + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + update(); + } + + private void addComponentsToPane(Container pane, Image img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + //! [trackbar] + sliderPanel.add(new JLabel("Canny threshold: ")); + JSlider slider = new JSlider(0, MAX_THRESHOLD, threshold); + slider.setMajorTickSpacing(20); + slider.setMinorTickSpacing(10); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + threshold = source.getValue(); + update(); + } + }); + //! [trackbar] + sliderPanel.add(slider); + pane.add(sliderPanel, BorderLayout.PAGE_START); + + JPanel imgPanel = new JPanel(); + imgSrcLabel = new JLabel(new ImageIcon(img)); + imgPanel.add(imgSrcLabel); + + Mat blackImg = Mat.zeros(srcGray.size(), CvType.CV_8U); + imgContoursLabel = new JLabel(new ImageIcon(HighGui.toBufferedImage(blackImg))); + imgPanel.add(imgContoursLabel); + + pane.add(imgPanel, BorderLayout.CENTER); + } + + private void update() { + //! [Canny] + /// Detect edges using Canny + Mat cannyOutput = new Mat(); + Imgproc.Canny(srcGray, cannyOutput, threshold, threshold * 2); + //! [Canny] + + //! [findContours] + /// Find contours + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(cannyOutput, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + //! [findContours] + + //! [allthework] + /// Approximate contours to polygons + get bounding rects and circles + MatOfPoint2f[] contoursPoly = new MatOfPoint2f[contours.size()]; + Rect[] boundRect = new Rect[contours.size()]; + Point[] centers = new Point[contours.size()]; + float[][] radius = new float[contours.size()][1]; + + for (int i = 0; i < contours.size(); i++) { + contoursPoly[i] = new MatOfPoint2f(); + Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i).toArray()), contoursPoly[i], 3, true); + boundRect[i] = Imgproc.boundingRect(new MatOfPoint(contoursPoly[i].toArray())); + centers[i] = new Point(); + Imgproc.minEnclosingCircle(contoursPoly[i], centers[i], radius[i]); + } + //! [allthework] + + //! [zeroMat] + Mat drawing = Mat.zeros(cannyOutput.size(), CvType.CV_8UC3); + //! [zeroMat] + //! [forContour] + /// Draw polygonal contour + bonding rects + circles + List contoursPolyList = new ArrayList<>(contoursPoly.length); + for (MatOfPoint2f poly : contoursPoly) { + contoursPolyList.add(new MatOfPoint(poly.toArray())); + } + + for (int i = 0; i < contours.size(); i++) { + Scalar color = new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)); + Imgproc.drawContours(drawing, contoursPolyList, i, color); + Imgproc.rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2); + Imgproc.circle(drawing, centers[i], (int) radius[i][0], color, 2); + } + //! [forContour] + + //! [showDrawings] + /// Show in a window + imgContoursLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(drawing))); + frame.repaint(); + //! [showDrawings] + } +} + +public class GeneralContoursDemo1 { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new GeneralContours1(args); + } + }); + } +} diff --git a/samples/java/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/GeneralContoursDemo2.java b/samples/java/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/GeneralContoursDemo2.java new file mode 100644 index 0000000000..c7b13dd174 --- /dev/null +++ b/samples/java/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/GeneralContoursDemo2.java @@ -0,0 +1,176 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.MatOfPoint2f; +import org.opencv.core.Point; +import org.opencv.core.RotatedRect; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +class GeneralContours2 { + private Mat srcGray = new Mat(); + private JFrame frame; + private JLabel imgSrcLabel; + private JLabel imgContoursLabel; + private static final int MAX_THRESHOLD = 255; + private int threshold = 100; + private Random rng = new Random(12345); + + public GeneralContours2(String[] args) { + //! [setup] + /// Load source image + String filename = args.length > 0 ? args[0] : "../data/stuff.jpg"; + Mat src = Imgcodecs.imread(filename); + if (src.empty()) { + System.err.println("Cannot read image: " + filename); + System.exit(0); + } + + /// Convert image to gray and blur it + Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY); + Imgproc.blur(srcGray, srcGray, new Size(3, 3)); + //! [setup] + + //! [createWindow] + // Create and set up the window. + frame = new JFrame("Creating Bounding rotated boxes and ellipses for contours demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + Image img = HighGui.toBufferedImage(src); + addComponentsToPane(frame.getContentPane(), img); + //! [createWindow] + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + update(); + } + + private void addComponentsToPane(Container pane, Image img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + //! [trackbar] + sliderPanel.add(new JLabel("Canny threshold: ")); + JSlider slider = new JSlider(0, MAX_THRESHOLD, threshold); + slider.setMajorTickSpacing(20); + slider.setMinorTickSpacing(10); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + threshold = source.getValue(); + update(); + } + }); + //! [trackbar] + sliderPanel.add(slider); + pane.add(sliderPanel, BorderLayout.PAGE_START); + + JPanel imgPanel = new JPanel(); + imgSrcLabel = new JLabel(new ImageIcon(img)); + imgPanel.add(imgSrcLabel); + + Mat blackImg = Mat.zeros(srcGray.size(), CvType.CV_8U); + imgContoursLabel = new JLabel(new ImageIcon(HighGui.toBufferedImage(blackImg))); + imgPanel.add(imgContoursLabel); + + pane.add(imgPanel, BorderLayout.CENTER); + } + + private void update() { + //! [Canny] + /// Detect edges using Canny + Mat cannyOutput = new Mat(); + Imgproc.Canny(srcGray, cannyOutput, threshold, threshold * 2); + //! [Canny] + + //! [findContours] + /// Find contours + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(cannyOutput, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + //! [findContours] + + /// Find the rotated rectangles and ellipses for each contour + RotatedRect[] minRect = new RotatedRect[contours.size()]; + RotatedRect[] minEllipse = new RotatedRect[contours.size()]; + for (int i = 0; i < contours.size(); i++) { + minRect[i] = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(i).toArray())); + minEllipse[i] = new RotatedRect(); + if (contours.get(i).rows() > 5) { + minEllipse[i] = Imgproc.fitEllipse(new MatOfPoint2f(contours.get(i).toArray())); + } + } + + //! [zeroMat] + /// Draw contours + rotated rects + ellipses + Mat drawing = Mat.zeros(cannyOutput.size(), CvType.CV_8UC3); + //! [zeroMat] + //! [forContour] + for (int i = 0; i < contours.size(); i++) { + Scalar color = new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)); + // contour + Imgproc.drawContours(drawing, contours, i, color); + // ellipse + Imgproc.ellipse(drawing, minEllipse[i], color, 2); + // rotated rectangle + Point[] rectPoints = new Point[4]; + minRect[i].points(rectPoints); + for (int j = 0; j < 4; j++) { + Imgproc.line(drawing, rectPoints[j], rectPoints[(j+1) % 4], color); + } + } + //! [forContour] + + //! [showDrawings] + /// Show in a window + imgContoursLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(drawing))); + frame.repaint(); + //! [showDrawings] + } +} + +public class GeneralContoursDemo2 { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new GeneralContours2(args); + } + }); + } +} diff --git a/samples/java/tutorial_code/ShapeDescriptors/find_contours/FindContoursDemo.java b/samples/java/tutorial_code/ShapeDescriptors/find_contours/FindContoursDemo.java new file mode 100644 index 0000000000..5eec4f878a --- /dev/null +++ b/samples/java/tutorial_code/ShapeDescriptors/find_contours/FindContoursDemo.java @@ -0,0 +1,137 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +class FindContours { + private Mat srcGray = new Mat(); + private JFrame frame; + private JLabel imgSrcLabel; + private JLabel imgContoursLabel; + private static final int MAX_THRESHOLD = 255; + private int threshold = 100; + private Random rng = new Random(12345); + + public FindContours(String[] args) { + /// Load source image + String filename = args.length > 0 ? args[0] : "../data/HappyFish.jpg"; + Mat src = Imgcodecs.imread(filename); + if (src.empty()) { + System.err.println("Cannot read image: " + filename); + System.exit(0); + } + + /// Convert image to gray and blur it + Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY); + Imgproc.blur(srcGray, srcGray, new Size(3, 3)); + + // Create and set up the window. + frame = new JFrame("Finding contours in your image demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + Image img = HighGui.toBufferedImage(src); + addComponentsToPane(frame.getContentPane(), img); + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + update(); + } + + private void addComponentsToPane(Container pane, Image img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + sliderPanel.add(new JLabel("Canny threshold: ")); + JSlider slider = new JSlider(0, MAX_THRESHOLD, threshold); + slider.setMajorTickSpacing(20); + slider.setMinorTickSpacing(10); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + threshold = source.getValue(); + update(); + } + }); + sliderPanel.add(slider); + pane.add(sliderPanel, BorderLayout.PAGE_START); + + JPanel imgPanel = new JPanel(); + imgSrcLabel = new JLabel(new ImageIcon(img)); + imgPanel.add(imgSrcLabel); + + Mat blackImg = Mat.zeros(srcGray.size(), CvType.CV_8U); + imgContoursLabel = new JLabel(new ImageIcon(HighGui.toBufferedImage(blackImg))); + imgPanel.add(imgContoursLabel); + + pane.add(imgPanel, BorderLayout.CENTER); + } + + private void update() { + /// Detect edges using Canny + Mat cannyOutput = new Mat(); + Imgproc.Canny(srcGray, cannyOutput, threshold, threshold * 2); + + /// Find contours + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(cannyOutput, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + + /// Draw contours + Mat drawing = Mat.zeros(cannyOutput.size(), CvType.CV_8UC3); + for (int i = 0; i < contours.size(); i++) { + Scalar color = new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)); + Imgproc.drawContours(drawing, contours, i, color, 2, Core.LINE_8, hierarchy, 0, new Point()); + } + + imgContoursLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(drawing))); + frame.repaint(); + } +} + +public class FindContoursDemo { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new FindContours(args); + } + }); + } +} diff --git a/samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java b/samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java new file mode 100644 index 0000000000..0e2104fb2b --- /dev/null +++ b/samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java @@ -0,0 +1,154 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfInt; +import org.opencv.core.MatOfPoint; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +class Hull { + private Mat srcGray = new Mat(); + private JFrame frame; + private JLabel imgSrcLabel; + private JLabel imgContoursLabel; + private static final int MAX_THRESHOLD = 255; + private int threshold = 100; + private Random rng = new Random(12345); + + public Hull(String[] args) { + /// Load source image + String filename = args.length > 0 ? args[0] : "../data/stuff.jpg"; + Mat src = Imgcodecs.imread(filename); + if (src.empty()) { + System.err.println("Cannot read image: " + filename); + System.exit(0); + } + + /// Convert image to gray and blur it + Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY); + Imgproc.blur(srcGray, srcGray, new Size(3, 3)); + + // Create and set up the window. + frame = new JFrame("Convex Hull demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + Image img = HighGui.toBufferedImage(src); + addComponentsToPane(frame.getContentPane(), img); + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + update(); + } + + private void addComponentsToPane(Container pane, Image img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + sliderPanel.add(new JLabel("Canny threshold: ")); + JSlider slider = new JSlider(0, MAX_THRESHOLD, threshold); + slider.setMajorTickSpacing(20); + slider.setMinorTickSpacing(10); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + threshold = source.getValue(); + update(); + } + }); + sliderPanel.add(slider); + pane.add(sliderPanel, BorderLayout.PAGE_START); + + JPanel imgPanel = new JPanel(); + imgSrcLabel = new JLabel(new ImageIcon(img)); + imgPanel.add(imgSrcLabel); + + Mat blackImg = Mat.zeros(srcGray.size(), CvType.CV_8U); + imgContoursLabel = new JLabel(new ImageIcon(HighGui.toBufferedImage(blackImg))); + imgPanel.add(imgContoursLabel); + + pane.add(imgPanel, BorderLayout.CENTER); + } + + private void update() { + /// Detect edges using Canny + Mat cannyOutput = new Mat(); + Imgproc.Canny(srcGray, cannyOutput, threshold, threshold * 2); + + /// Find contours + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(cannyOutput, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + + /// Find the convex hull object for each contour + List hullList = new ArrayList<>(); + for (MatOfPoint contour : contours) { + MatOfInt hull = new MatOfInt(); + Imgproc.convexHull(contour, hull); + + Point[] contourArray = contour.toArray(); + Point[] hullPoints = new Point[hull.rows()]; + List hullContourIdxList = hull.toList(); + for (int i = 0; i < hullContourIdxList.size(); i++) { + hullPoints[i] = contourArray[hullContourIdxList.get(i)]; + } + hullList.add(new MatOfPoint(hullPoints)); + } + + /// Draw contours + hull results + Mat drawing = Mat.zeros(cannyOutput.size(), CvType.CV_8UC3); + for (int i = 0; i < contours.size(); i++) { + Scalar color = new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)); + Imgproc.drawContours(drawing, contours, i, color); + Imgproc.drawContours(drawing, hullList, i, color ); + } + + imgContoursLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(drawing))); + frame.repaint(); + } +} + +public class HullDemo { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new Hull(args); + } + }); + } +} diff --git a/samples/java/tutorial_code/ShapeDescriptors/moments/MomentsDemo.java b/samples/java/tutorial_code/ShapeDescriptors/moments/MomentsDemo.java new file mode 100644 index 0000000000..ffc24207fb --- /dev/null +++ b/samples/java/tutorial_code/ShapeDescriptors/moments/MomentsDemo.java @@ -0,0 +1,178 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.MatOfPoint2f; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; +import org.opencv.imgproc.Moments; + +class MomentsClass { + private Mat srcGray = new Mat(); + private JFrame frame; + private JLabel imgSrcLabel; + private JLabel imgContoursLabel; + private static final int MAX_THRESHOLD = 255; + private int threshold = 100; + private Random rng = new Random(12345); + + public MomentsClass(String[] args) { + //! [setup] + /// Load source image + String filename = args.length > 0 ? args[0] : "../data/stuff.jpg"; + Mat src = Imgcodecs.imread(filename); + if (src.empty()) { + System.err.println("Cannot read image: " + filename); + System.exit(0); + } + + /// Convert image to gray and blur it + Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_BGR2GRAY); + Imgproc.blur(srcGray, srcGray, new Size(3, 3)); + //! [setup] + + //! [createWindow] + // Create and set up the window. + frame = new JFrame("Image Moments demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + Image img = HighGui.toBufferedImage(src); + addComponentsToPane(frame.getContentPane(), img); + //! [createWindow] + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + update(); + } + + private void addComponentsToPane(Container pane, Image img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + //! [trackbar] + sliderPanel.add(new JLabel("Canny threshold: ")); + JSlider slider = new JSlider(0, MAX_THRESHOLD, threshold); + slider.setMajorTickSpacing(20); + slider.setMinorTickSpacing(10); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + threshold = source.getValue(); + update(); + } + }); + //! [trackbar] + sliderPanel.add(slider); + pane.add(sliderPanel, BorderLayout.PAGE_START); + + JPanel imgPanel = new JPanel(); + imgSrcLabel = new JLabel(new ImageIcon(img)); + imgPanel.add(imgSrcLabel); + + Mat blackImg = Mat.zeros(srcGray.size(), CvType.CV_8U); + imgContoursLabel = new JLabel(new ImageIcon(HighGui.toBufferedImage(blackImg))); + imgPanel.add(imgContoursLabel); + + pane.add(imgPanel, BorderLayout.CENTER); + } + + private void update() { + //! [Canny] + /// Detect edges using Canny + Mat cannyOutput = new Mat(); + Imgproc.Canny(srcGray, cannyOutput, threshold, threshold * 2); + //! [Canny] + + //! [findContours] + /// Find contours + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(cannyOutput, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + //! [findContours] + + /// Get the moments + List mu = new ArrayList<>(contours.size()); + for (int i = 0; i < contours.size(); i++) { + mu.add(Imgproc.moments(contours.get(i))); + } + + /// Get the mass centers + List mc = new ArrayList<>(contours.size()); + for (int i = 0; i < contours.size(); i++) { + //add 1e-5 to avoid division by zero + mc.add(new Point(mu.get(i).m10 / (mu.get(i).m00 + 1e-5), mu.get(i).m01 / (mu.get(i).m00 + 1e-5))); + } + + //! [zeroMat] + /// Draw contours + Mat drawing = Mat.zeros(cannyOutput.size(), CvType.CV_8UC3); + //! [zeroMat] + //! [forContour] + for (int i = 0; i < contours.size(); i++) { + Scalar color = new Scalar(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256)); + Imgproc.drawContours(drawing, contours, i, color, 2); + Imgproc.circle(drawing, mc.get(i), 4, color, -1); + } + //! [forContour] + + //! [showDrawings] + /// Show in a window + imgContoursLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(drawing))); + frame.repaint(); + //! [showDrawings] + + /// Calculate the area with the moments 00 and compare with the result of the OpenCV function + System.out.println("\t Info: Area and Contour Length \n"); + for (int i = 0; i < contours.size(); i++) { + System.out.format(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f\n", i, + mu.get(i).m00, Imgproc.contourArea(contours.get(i)), + Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true)); + } + } +} + +public class MomentsDemo { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new MomentsClass(args); + } + }); + } +} diff --git a/samples/java/tutorial_code/ShapeDescriptors/point_polygon_test/PointPolygonTestDemo.java b/samples/java/tutorial_code/ShapeDescriptors/point_polygon_test/PointPolygonTestDemo.java new file mode 100644 index 0000000000..2d0a542db7 --- /dev/null +++ b/samples/java/tutorial_code/ShapeDescriptors/point_polygon_test/PointPolygonTestDemo.java @@ -0,0 +1,93 @@ +import java.util.ArrayList; +import java.util.List; + +import org.opencv.core.Core; +import org.opencv.core.Core.MinMaxLocResult; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.core.MatOfPoint; +import org.opencv.core.MatOfPoint2f; +import org.opencv.core.Point; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.highgui.HighGui; +import org.opencv.imgproc.Imgproc; + +class PointPolygonTest { + public void run() { + /// Create an image + int r = 100; + Mat src = Mat.zeros(new Size(4 * r, 4 * r), CvType.CV_8U); + + /// Create a sequence of points to make a contour + List vert = new ArrayList<>(6); + vert.add(new Point(3 * r / 2, 1.34 * r)); + vert.add(new Point(1 * r, 2 * r)); + vert.add(new Point(3 * r / 2, 2.866 * r)); + vert.add(new Point(5 * r / 2, 2.866 * r)); + vert.add(new Point(3 * r, 2 * r)); + vert.add(new Point(5 * r / 2, 1.34 * r)); + + /// Draw it in src + for (int i = 0; i < 6; i++) { + Imgproc.line(src, vert.get(i), vert.get((i + 1) % 6), new Scalar(255), 3); + } + + /// Get the contours + List contours = new ArrayList<>(); + Mat hierarchy = new Mat(); + Imgproc.findContours(src, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE); + + /// Calculate the distances to the contour + Mat rawDist = new Mat(src.size(), CvType.CV_32F); + float[] rawDistData = new float[(int) (rawDist.total() * rawDist.channels())]; + for (int i = 0; i < src.rows(); i++) { + for (int j = 0; j < src.cols(); j++) { + rawDistData[i * src.cols() + j] = (float) Imgproc + .pointPolygonTest(new MatOfPoint2f(contours.get(0).toArray()), new Point(j, i), true); + } + } + rawDist.put(0, 0, rawDistData); + + MinMaxLocResult res = Core.minMaxLoc(rawDist); + double minVal = Math.abs(res.minVal); + double maxVal = Math.abs(res.maxVal); + + /// Depicting the distances graphically + Mat drawing = Mat.zeros(src.size(), CvType.CV_8UC3); + byte[] drawingData = new byte[(int) (drawing.total() * drawing.channels())]; + for (int i = 0; i < src.rows(); i++) { + for (int j = 0; j < src.cols(); j++) { + if (rawDistData[i * src.cols() + j] < 0) { + drawingData[(i * src.cols() + j) * 3] = + (byte) (255 - Math.abs(rawDistData[i * src.cols() + j]) * 255 / minVal); + } else if (rawDistData[i * src.cols() + j] > 0) { + drawingData[(i * src.cols() + j) * 3 + 2] = + (byte) (255 - rawDistData[i * src.cols() + j] * 255 / maxVal); + } else { + drawingData[(i * src.cols() + j) * 3] = (byte) 255; + drawingData[(i * src.cols() + j) * 3 + 1] = (byte) 255; + drawingData[(i * src.cols() + j) * 3 + 2] = (byte) 255; + } + } + } + drawing.put(0, 0, drawingData); + + /// Show your results + HighGui.imshow("Source", src); + HighGui.imshow("Distance", drawing); + + HighGui.waitKey(); + System.exit(0); + } +} + +public class PointPolygonTestDemo { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + new PointPolygonTest().run(); + } + +} diff --git a/samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java b/samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java new file mode 100644 index 0000000000..33e3c38bfc --- /dev/null +++ b/samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java @@ -0,0 +1,163 @@ +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.opencv.core.Core; +import org.opencv.core.CvType; +import org.opencv.core.DMatch; +import org.opencv.core.KeyPoint; +import org.opencv.core.Mat; +import org.opencv.core.MatOfDMatch; +import org.opencv.core.MatOfKeyPoint; +import org.opencv.core.Scalar; +import org.opencv.features2d.AKAZE; +import org.opencv.features2d.DescriptorMatcher; +import org.opencv.features2d.Features2d; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +class AKAZEMatch { + public void run(String[] args) { + //! [load] + String filename1 = args.length > 2 ? args[0] : "../data/graf1.png"; + String filename2 = args.length > 2 ? args[1] : "../data/graf3.png"; + String filename3 = args.length > 2 ? args[2] : "../data/H1to3p.xml"; + Mat img1 = Imgcodecs.imread(filename1, Imgcodecs.IMREAD_GRAYSCALE); + Mat img2 = Imgcodecs.imread(filename2, Imgcodecs.IMREAD_GRAYSCALE); + if (img1.empty() || img2.empty()) { + System.err.println("Cannot read images!"); + System.exit(0); + } + + File file = new File(filename3); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder; + Document document; + Mat homography = new Mat(3, 3, CvType.CV_64F); + double[] homographyData = new double[(int) (homography.total()*homography.channels())]; + try { + documentBuilder = documentBuilderFactory.newDocumentBuilder(); + document = documentBuilder.parse(file); + String homographyStr = document.getElementsByTagName("data").item(0).getTextContent(); + String[] splited = homographyStr.split("\\s+"); + int idx = 0; + for (String s : splited) { + if (!s.isEmpty()) { + homographyData[idx] = Double.parseDouble(s); + idx++; + } + } + } catch (ParserConfigurationException e) { + e.printStackTrace(); + System.exit(0); + } catch (SAXException e) { + e.printStackTrace(); + System.exit(0); + } catch (IOException e) { + e.printStackTrace(); + System.exit(0); + } + homography.put(0, 0, homographyData); + //! [load] + + //! [AKAZE] + AKAZE akaze = AKAZE.create(); + MatOfKeyPoint kpts1 = new MatOfKeyPoint(), kpts2 = new MatOfKeyPoint(); + Mat desc1 = new Mat(), desc2 = new Mat(); + akaze.detectAndCompute(img1, new Mat(), kpts1, desc1); + akaze.detectAndCompute(img2, new Mat(), kpts2, desc2); + //! [AKAZE] + + //! [2-nn matching] + DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); + List knnMatches = new ArrayList<>(); + matcher.knnMatch(desc1, desc2, knnMatches, 2); + //! [2-nn matching] + + //! [ratio test filtering] + float ratioThreshold = 0.8f; // Nearest neighbor matching ratio + List listOfMatched1 = new ArrayList<>(); + List listOfMatched2 = new ArrayList<>(); + List listOfKeypoints1 = kpts1.toList(); + List listOfKeypoints2 = kpts2.toList(); + for (int i = 0; i < knnMatches.size(); i++) { + DMatch[] matches = knnMatches.get(i).toArray(); + float dist1 = matches[0].distance; + float dist2 = matches[1].distance; + if (dist1 < ratioThreshold * dist2) { + listOfMatched1.add(listOfKeypoints1.get(matches[0].queryIdx)); + listOfMatched2.add(listOfKeypoints2.get(matches[0].trainIdx)); + } + } + //! [ratio test filtering] + + //! [homography check] + double inlierThreshold = 2.5; // Distance threshold to identify inliers with homography check + List listOfInliers1 = new ArrayList<>(); + List listOfInliers2 = new ArrayList<>(); + List listOfGoodMatches = new ArrayList<>(); + for (int i = 0; i < listOfMatched1.size(); i++) { + Mat col = new Mat(3, 1, CvType.CV_64F); + double[] colData = new double[(int) (col.total() * col.channels())]; + colData[0] = listOfMatched1.get(i).pt.x; + colData[1] = listOfMatched1.get(i).pt.y; + colData[2] = 1.0; + col.put(0, 0, colData); + + Mat colRes = new Mat(); + Core.gemm(homography, col, 1.0, new Mat(), 0.0, colRes); + colRes.get(0, 0, colData); + Core.multiply(colRes, new Scalar(1.0 / colData[2]), col); + col.get(0, 0, colData); + + double dist = Math.sqrt(Math.pow(colData[0] - listOfMatched2.get(i).pt.x, 2) + + Math.pow(colData[1] - listOfMatched2.get(i).pt.y, 2)); + + if (dist < inlierThreshold) { + listOfGoodMatches.add(new DMatch(listOfInliers1.size(), listOfInliers2.size(), 0)); + listOfInliers1.add(listOfMatched1.get(i)); + listOfInliers2.add(listOfMatched2.get(i)); + } + } + //! [homography check] + + //! [draw final matches] + Mat res = new Mat(); + MatOfKeyPoint inliers1 = new MatOfKeyPoint(listOfInliers1.toArray(new KeyPoint[listOfInliers1.size()])); + MatOfKeyPoint inliers2 = new MatOfKeyPoint(listOfInliers2.toArray(new KeyPoint[listOfInliers2.size()])); + MatOfDMatch goodMatches = new MatOfDMatch(listOfGoodMatches.toArray(new DMatch[listOfGoodMatches.size()])); + Features2d.drawMatches(img1, inliers1, img2, inliers2, goodMatches, res); + Imgcodecs.imwrite("akaze_result.png", res); + + double inlierRatio = listOfInliers1.size() / (double) listOfMatched1.size(); + System.out.println("A-KAZE Matching Results"); + System.out.println("*******************************"); + System.out.println("# Keypoints 1: \t" + listOfKeypoints1.size()); + System.out.println("# Keypoints 2: \t" + listOfKeypoints2.size()); + System.out.println("# Matches: \t" + listOfMatched1.size()); + System.out.println("# Inliers: \t" + listOfInliers1.size()); + System.out.println("# Inliers Ratio: \t" + inlierRatio); + + HighGui.imshow("result", res); + HighGui.waitKey(); + //! [draw final matches] + + System.exit(0); + } +} + +public class AKAZEMatchDemo { + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + new AKAZEMatch().run(args); + } +} diff --git a/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java b/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java index e02af9cadb..365c0c7ee2 100644 --- a/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java +++ b/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java @@ -42,12 +42,12 @@ class SURFFLANNMatching { matcher.knnMatch(descriptors1, descriptors2, knnMatches, 2); //-- Filter matches using the Lowe's ratio test - float ratio_thresh = 0.7f; + float ratioThresh = 0.7f; List listOfGoodMatches = new ArrayList<>(); for (int i = 0; i < knnMatches.size(); i++) { if (knnMatches.get(i).rows() > 1) { DMatch[] matches = knnMatches.get(i).toArray(); - if (matches[0].distance / matches[1].distance <= ratio_thresh) { + if (matches[0].distance < ratioThresh * matches[1].distance) { listOfGoodMatches.add(matches[0]); } } diff --git a/samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java b/samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java index 1a5cbe7f30..44367dd966 100644 --- a/samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java +++ b/samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java @@ -48,12 +48,12 @@ class SURFFLANNMatchingHomography { matcher.knnMatch(descriptorsObject, descriptorsScene, knnMatches, 2); //-- Filter matches using the Lowe's ratio test - float ratio_thresh = 0.75f; + float ratioThresh = 0.75f; List listOfGoodMatches = new ArrayList<>(); for (int i = 0; i < knnMatches.size(); i++) { if (knnMatches.get(i).rows() > 1) { DMatch[] matches = knnMatches.get(i).toArray(); - if (matches[0].distance / matches[1].distance <= ratio_thresh) { + if (matches[0].distance < ratioThresh * matches[1].distance) { listOfGoodMatches.add(matches[0]); } } diff --git a/samples/java/tutorial_code/photo/hdr_imaging/HDRImagingDemo.java b/samples/java/tutorial_code/photo/hdr_imaging/HDRImagingDemo.java index 9d96d85f2f..ea201399b8 100644 --- a/samples/java/tutorial_code/photo/hdr_imaging/HDRImagingDemo.java +++ b/samples/java/tutorial_code/photo/hdr_imaging/HDRImagingDemo.java @@ -7,6 +7,7 @@ import java.util.List; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; +import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.photo.CalibrateDebevec; import org.opencv.photo.MergeDebevec; @@ -70,7 +71,7 @@ class HDRImaging { //! [Tonemap HDR image] Mat ldr = new Mat(); - TonemapDurand tonemap = Photo.createTonemapDurand(); + TonemapDurand tonemap = Photo.createTonemapDurand(2.2f, 4.0f, 1.0f, 2.0f, 2.0f); tonemap.process(hdr, ldr); //! [Tonemap HDR image] @@ -81,8 +82,8 @@ class HDRImaging { //! [Perform exposure fusion] //! [Write results] - fusion = fusion.mul(fusion, 255); - ldr = ldr.mul(ldr, 255); + Core.multiply(fusion, new Scalar(255,255,255), fusion); + Core.multiply(ldr, new Scalar(255,255,255), ldr); Imgcodecs.imwrite("fusion.png", fusion); Imgcodecs.imwrite("ldr.png", ldr); Imgcodecs.imwrite("hdr.hdr", hdr); diff --git a/samples/opencl/opencl-opencv-interop.cpp b/samples/opencl/opencl-opencv-interop.cpp index c6630ea45b..d2961af777 100644 --- a/samples/opencl/opencl-opencv-interop.cpp +++ b/samples/opencl/opencl-opencv-interop.cpp @@ -14,6 +14,8 @@ #include #include +#define CL_USE_DEPRECATED_OPENCL_1_1_APIS +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS #define CL_USE_DEPRECATED_OPENCL_2_0_APIS // eliminate build warning #ifdef __APPLE__ diff --git a/samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py b/samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py new file mode 100644 index 0000000000..e679001bc1 --- /dev/null +++ b/samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py @@ -0,0 +1,138 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse +import random as rng + +rng.seed(12345) + +## [load_image] +# Load the image +parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\ + Sample code showing how to segment overlapping objects using Laplacian filtering, \ + in addition to Watershed and Distance Transformation') +parser.add_argument('--input', help='Path to input image.', default='../data/cards.png') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image:', args.input) + exit(0) + +# Show source image +cv.imshow('Source Image', src) +## [load_image] + +## [black_bg] +# Change the background from white to black, since that will help later to extract +# better results during the use of Distance Transform +src[np.all(src == 255, axis=2)] = 0 + +# Show output image +cv.imshow('Black Background Image', src) +## [black_bg] + +## [sharp] +# Create a kernel that we will use to sharpen our image +# an approximation of second derivative, a quite strong kernel +kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32) + +# do the laplacian filtering as it is +# well, we need to convert everything in something more deeper then CV_8U +# because the kernel has some negative values, +# and we can expect in general to have a Laplacian image with negative values +# BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255 +# so the possible negative number will be truncated +imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel) +sharp = np.float32(src) +imgResult = sharp - imgLaplacian + +# convert back to 8bits gray scale +imgResult = np.clip(imgResult, 0, 255) +imgResult = imgResult.astype('uint8') +imgLaplacian = np.clip(imgLaplacian, 0, 255) +imgLaplacian = np.uint8(imgLaplacian) + +#cv.imshow('Laplace Filtered Image', imgLaplacian) +cv.imshow('New Sharped Image', imgResult) +## [sharp] + +## [bin] +# Create binary image from source image +bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY) +_, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) +cv.imshow('Binary Image', bw) +## [bin] + +## [dist] +# Perform the distance transform algorithm +dist = cv.distanceTransform(bw, cv.DIST_L2, 3) + +# Normalize the distance image for range = {0.0, 1.0} +# so we can visualize and threshold it +cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX) +cv.imshow('Distance Transform Image', dist) +## [dist] + +## [peaks] +# Threshold to obtain the peaks +# This will be the markers for the foreground objects +_, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY) + +# Dilate a bit the dist image +kernel1 = np.ones((3,3), dtype=np.uint8) +dist = cv.dilate(dist, kernel1) +cv.imshow('Peaks', dist) +## [peaks] + +## [seeds] +# Create the CV_8U version of the distance image +# It is needed for findContours() +dist_8u = dist.astype('uint8') + +# Find total markers +_, contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + +# Create the marker image for the watershed algorithm +markers = np.zeros(dist.shape, dtype=np.int32) + +# Draw the foreground markers +for i in range(len(contours)): + cv.drawContours(markers, contours, i, (i+1), -1) + +# Draw the background marker +cv.circle(markers, (5,5), 3, (255,255,255), -1) +cv.imshow('Markers', markers*10000) +## [seeds] + +## [watershed] +# Perform the watershed algorithm +cv.watershed(imgResult, markers) + +#mark = np.zeros(markers.shape, dtype=np.uint8) +mark = markers.astype('uint8') +mark = cv.bitwise_not(mark) +# uncomment this if you want to see how the mark +# image looks like at that point +#cv.imshow('Markers_v2', mark) + +# Generate random colors +colors = [] +for contour in contours: + colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))) + +# Create the result image +dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8) + +# Fill labeled objects with random colors +for i in range(markers.shape[0]): + for j in range(markers.shape[1]): + index = markers[i,j] + if index > 0 and index <= len(contours): + dst[i,j,:] = colors[index-1] + +# Visualize the final image +cv.imshow('Final Result', dst) +## [watershed] + +cv.waitKey() diff --git a/samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py b/samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py new file mode 100644 index 0000000000..060167484c --- /dev/null +++ b/samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py @@ -0,0 +1,82 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse +import random as rng + +rng.seed(12345) + +def thresh_callback(val): + threshold = val + + ## [Canny] + # Detect edges using Canny + canny_output = cv.Canny(src_gray, threshold, threshold * 2) + ## [Canny] + + ## [findContours] + # Find contours + _, contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + ## [findContours] + + ## [allthework] + # Approximate contours to polygons + get bounding rects and circles + contours_poly = [None]*len(contours) + boundRect = [None]*len(contours) + centers = [None]*len(contours) + radius = [None]*len(contours) + for i in range(len(contours)): + contours_poly[i] = cv.approxPolyDP(contours[i], 3, True) + boundRect[i] = cv.boundingRect(contours_poly[i]) + centers[i], radius[i] = cv.minEnclosingCircle(contours_poly[i]) + ## [allthework] + + ## [zeroMat] + drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8) + ## [zeroMat] + + ## [forContour] + # Draw polygonal contour + bonding rects + circles + for i in range(len(contours)): + color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)) + cv.drawContours(drawing, contours_poly, i, color) + cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \ + (int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2) + cv.circle(drawing, (int(centers[i][0]), int(centers[i][1])), int(radius[i]), color, 2) + ## [forContour] + + ## [showDrawings] + # Show in a window + cv.imshow('Contours', drawing) + ## [showDrawings] + +## [setup] +# Load source image +parser = argparse.ArgumentParser(description='Code for Creating Bounding boxes and circles for contours tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/stuff.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image:', args.input) + exit(0) + +# Convert image to gray and blur it +src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) +src_gray = cv.blur(src_gray, (3,3)) +## [setup] + +## [createWindow] +# Create Window +source_window = 'Source' +cv.namedWindow(source_window) +cv.imshow(source_window, src) +## [createWindow] +## [trackbar] +max_thresh = 255 +thresh = 100 # initial threshold +cv.createTrackbar('Canny thresh:', source_window, thresh, max_thresh, thresh_callback) +thresh_callback(thresh) +## [trackbar] + +cv.waitKey() diff --git a/samples/python/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/generalContours_demo2.py b/samples/python/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/generalContours_demo2.py new file mode 100644 index 0000000000..a461aba49b --- /dev/null +++ b/samples/python/tutorial_code/ShapeDescriptors/bounding_rotated_ellipses/generalContours_demo2.py @@ -0,0 +1,82 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse +import random as rng + +rng.seed(12345) + +def thresh_callback(val): + threshold = val + + ## [Canny] + # Detect edges using Canny + canny_output = cv.Canny(src_gray, threshold, threshold * 2) + ## [Canny] + + ## [findContours] + # Find contours + _, contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + ## [findContours] + + # Find the rotated rectangles and ellipses for each contour + minRect = [None]*len(contours) + minEllipse = [None]*len(contours) + for i in range(len(contours)): + minRect[i] = cv.minAreaRect(contours[i]) + if contours[i].shape[0] > 5: + minEllipse[i] = cv.fitEllipse(contours[i]) + + # Draw contours + rotated rects + ellipses + ## [zeroMat] + drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8) + ## [zeroMat] + ## [forContour] + for i in range(len(contours)): + color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)) + # contour + cv.drawContours(drawing, contours, i, color) + # ellipse + if contours[i].shape[0] > 5: + cv.ellipse(drawing, minEllipse[i], color, 2) + # rotated rectangle + box = cv.boxPoints(minRect[i]) + box = np.intp(box) #np.intp: Integer used for indexing (same as C ssize_t; normally either int32 or int64) + cv.drawContours(drawing, [box], 0, color) + ## [forContour] + + ## [showDrawings] + # Show in a window + cv.imshow('Contours', drawing) + ## [showDrawings] + +## [setup] +# Load source image +parser = argparse.ArgumentParser(description='Code for Creating Bounding rotated boxes and ellipses for contours tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/stuff.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image:', args.input) + exit(0) + +# Convert image to gray and blur it +src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) +src_gray = cv.blur(src_gray, (3,3)) +## [setup] + +## [createWindow] +# Create Window +source_window = 'Source' +cv.namedWindow(source_window) +cv.imshow(source_window, src) +## [createWindow] +## [trackbar] +max_thresh = 255 +thresh = 100 # initial threshold +cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback) +thresh_callback(thresh) +## [trackbar] + +cv.waitKey() diff --git a/samples/python/tutorial_code/ShapeDescriptors/find_contours/findContours_demo.py b/samples/python/tutorial_code/ShapeDescriptors/find_contours/findContours_demo.py new file mode 100644 index 0000000000..f4cbb5f401 --- /dev/null +++ b/samples/python/tutorial_code/ShapeDescriptors/find_contours/findContours_demo.py @@ -0,0 +1,50 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse +import random as rng + +rng.seed(12345) + +def thresh_callback(val): + threshold = val + + # Detect edges using Canny + canny_output = cv.Canny(src_gray, threshold, threshold * 2) + + # Find contours + _, contours, hierarchy = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + + # Draw contours + drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8) + for i in range(len(contours)): + color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)) + cv.drawContours(drawing, contours, i, color, 2, cv.LINE_8, hierarchy, 0) + + # Show in a window + cv.imshow('Contours', drawing) + +# Load source image +parser = argparse.ArgumentParser(description='Code for Finding contours in your image tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/HappyFish.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image:', args.input) + exit(0) + +# Convert image to gray and blur it +src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) +src_gray = cv.blur(src_gray, (3,3)) + +# Create Window +source_window = 'Source' +cv.namedWindow(source_window) +cv.imshow(source_window, src) +max_thresh = 255 +thresh = 100 # initial threshold +cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback) +thresh_callback(thresh) + +cv.waitKey() diff --git a/samples/python/tutorial_code/ShapeDescriptors/hull/hull_demo.py b/samples/python/tutorial_code/ShapeDescriptors/hull/hull_demo.py new file mode 100644 index 0000000000..3254941ac0 --- /dev/null +++ b/samples/python/tutorial_code/ShapeDescriptors/hull/hull_demo.py @@ -0,0 +1,57 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse +import random as rng + +rng.seed(12345) + +def thresh_callback(val): + threshold = val + + # Detect edges using Canny + canny_output = cv.Canny(src_gray, threshold, threshold * 2) + + # Find contours + _, contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + + # Find the convex hull object for each contour + hull_list = [] + for i in range(len(contours)): + hull = cv.convexHull(contours[i]) + hull_list.append(hull) + + # Draw contours + hull results + drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8) + for i in range(len(contours)): + color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)) + cv.drawContours(drawing, contours, i, color) + cv.drawContours(drawing, hull_list, i, color) + + # Show in a window + cv.imshow('Contours', drawing) + +# Load source image +parser = argparse.ArgumentParser(description='Code for Convex Hull tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/stuff.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image:', args.input) + exit(0) + +# Convert image to gray and blur it +src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) +src_gray = cv.blur(src_gray, (3,3)) + +# Create Window +source_window = 'Source' +cv.namedWindow(source_window) +cv.imshow(source_window, src) +max_thresh = 255 +thresh = 100 # initial threshold +cv.createTrackbar('Canny thresh:', source_window, thresh, max_thresh, thresh_callback) +thresh_callback(thresh) + +cv.waitKey() diff --git a/samples/python/tutorial_code/ShapeDescriptors/moments/moments_demo.py b/samples/python/tutorial_code/ShapeDescriptors/moments/moments_demo.py new file mode 100644 index 0000000000..c528110ba1 --- /dev/null +++ b/samples/python/tutorial_code/ShapeDescriptors/moments/moments_demo.py @@ -0,0 +1,83 @@ +from __future__ import print_function +from __future__ import division +import cv2 as cv +import numpy as np +import argparse +import random as rng + +rng.seed(12345) + +def thresh_callback(val): + threshold = val + + ## [Canny] + # Detect edges using Canny + canny_output = cv.Canny(src_gray, threshold, threshold * 2) + ## [Canny] + + ## [findContours] + # Find contours + _, contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + ## [findContours] + + # Get the moments + mu = [None]*len(contours) + for i in range(len(contours)): + mu[i] = cv.moments(contours[i]) + + # Get the mass centers + mc = [None]*len(contours) + for i in range(len(contours)): + # add 1e-5 to avoid division by zero + mc[i] = (mu[i]['m10'] / (mu[i]['m00'] + 1e-5), mu[i]['m01'] / (mu[i]['m00'] + 1e-5)) + + # Draw contours + ## [zeroMat] + drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8) + ## [zeroMat] + ## [forContour] + for i in range(len(contours)): + color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)) + cv.drawContours(drawing, contours, i, color, 2) + cv.circle(drawing, (int(mc[i][0]), int(mc[i][1])), 4, color, -1) + ## [forContour] + + ## [showDrawings] + # Show in a window + cv.imshow('Contours', drawing) + ## [showDrawings] + + # Calculate the area with the moments 00 and compare with the result of the OpenCV function + for i in range(len(contours)): + print(' * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f' % (i, mu[i]['m00'], cv.contourArea(contours[i]), cv.arcLength(contours[i], True))) + +## [setup] +# Load source image +parser = argparse.ArgumentParser(description='Code for Image Moments tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/stuff.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image:', args.input) + exit(0) + +# Convert image to gray and blur it +src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) +src_gray = cv.blur(src_gray, (3,3)) +## [setup] + +## [createWindow] +# Create Window +source_window = 'Source' +cv.namedWindow(source_window) +cv.imshow(source_window, src) +## [createWindow] +## [trackbar] +max_thresh = 255 +thresh = 100 # initial threshold +cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback) +thresh_callback(thresh) +## [trackbar] + +cv.waitKey() diff --git a/samples/python/tutorial_code/ShapeDescriptors/point_polygon_test/pointPolygonTest_demo.py b/samples/python/tutorial_code/ShapeDescriptors/point_polygon_test/pointPolygonTest_demo.py new file mode 100644 index 0000000000..150727e1d5 --- /dev/null +++ b/samples/python/tutorial_code/ShapeDescriptors/point_polygon_test/pointPolygonTest_demo.py @@ -0,0 +1,51 @@ +from __future__ import print_function +from __future__ import division +import cv2 as cv +import numpy as np + +# Create an image +r = 100 +src = np.zeros((4*r, 4*r), dtype=np.uint8) + +# Create a sequence of points to make a contour +vert = [None]*6 +vert[0] = (3*r//2, int(1.34*r)) +vert[1] = (1*r, 2*r) +vert[2] = (3*r//2, int(2.866*r)) +vert[3] = (5*r//2, int(2.866*r)) +vert[4] = (3*r, 2*r) +vert[5] = (5*r//2, int(1.34*r)) + +# Draw it in src +for i in range(6): + cv.line(src, vert[i], vert[(i+1)%6], ( 255 ), 3) + +# Get the contours +_, contours, _ = cv.findContours(src, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) + +# Calculate the distances to the contour +raw_dist = np.empty(src.shape, dtype=np.float32) +for i in range(src.shape[0]): + for j in range(src.shape[1]): + raw_dist[i,j] = cv.pointPolygonTest(contours[0], (j,i), True) + +minVal, maxVal, _, _ = cv.minMaxLoc(raw_dist) +minVal = abs(minVal) +maxVal = abs(maxVal) + +# Depicting the distances graphically +drawing = np.zeros((src.shape[0], src.shape[1], 3), dtype=np.uint8) +for i in range(src.shape[0]): + for j in range(src.shape[1]): + if raw_dist[i,j] < 0: + drawing[i,j,0] = 255 - abs(raw_dist[i,j]) * 255 / minVal + elif raw_dist[i,j] > 0: + drawing[i,j,2] = 255 - raw_dist[i,j] * 255 / maxVal + else: + drawing[i,j,0] = 255 + drawing[i,j,1] = 255 + drawing[i,j,2] = 255 + +cv.imshow('Source', src) +cv.imshow('Distance', drawing) +cv.waitKey() diff --git a/samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py b/samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py new file mode 100644 index 0000000000..0d9818a3c1 --- /dev/null +++ b/samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py @@ -0,0 +1,81 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse +from math import sqrt + +## [load] +parser = argparse.ArgumentParser(description='Code for AKAZE local features matching tutorial.') +parser.add_argument('--input1', help='Path to input image 1.', default='../data/graf1.png') +parser.add_argument('--input2', help='Path to input image 2.', default='../data/graf3.png') +parser.add_argument('--homography', help='Path to the homography matrix.', default='../data/H1to3p.xml') +args = parser.parse_args() + +img1 = cv.imread(args.input1, cv.IMREAD_GRAYSCALE) +img2 = cv.imread(args.input2, cv.IMREAD_GRAYSCALE) +if img1 is None or img2 is None: + print('Could not open or find the images!') + exit(0) + +fs = cv.FileStorage(args.homography, cv.FILE_STORAGE_READ) +homography = fs.getFirstTopLevelNode().mat() +## [load] + +## [AKAZE] +akaze = cv.AKAZE_create() +kpts1, desc1 = akaze.detectAndCompute(img1, None) +kpts2, desc2 = akaze.detectAndCompute(img2, None) +## [AKAZE] + +## [2-nn matching] +matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_BRUTEFORCE_HAMMING) +nn_matches = matcher.knnMatch(desc1, desc2, 2) +## [2-nn matching] + +## [ratio test filtering] +matched1 = [] +matched2 = [] +nn_match_ratio = 0.8 # Nearest neighbor matching ratio +for m, n in nn_matches: + if m.distance < nn_match_ratio * n.distance: + matched1.append(kpts1[m.queryIdx]) + matched2.append(kpts2[m.trainIdx]) +## [ratio test filtering] + +## [homography check] +inliers1 = [] +inliers2 = [] +good_matches = [] +inlier_threshold = 2.5 # Distance threshold to identify inliers with homography check +for i, m in enumerate(matched1): + col = np.ones((3,1), dtype=np.float64) + col[0:2,0] = m.pt + + col = np.dot(homography, col) + col /= col[2,0] + dist = sqrt(pow(col[0,0] - matched2[i].pt[0], 2) +\ + pow(col[1,0] - matched2[i].pt[1], 2)) + + if dist < inlier_threshold: + good_matches.append(cv.DMatch(len(inliers1), len(inliers2), 0)) + inliers1.append(matched1[i]) + inliers2.append(matched2[i]) +## [homography check] + +## [draw final matches] +res = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8) +cv.drawMatches(img1, inliers1, img2, inliers2, good_matches, res) +cv.imwrite("akaze_result.png", res) + +inlier_ratio = len(inliers1) / float(len(matched1)) +print('A-KAZE Matching Results') +print('*******************************') +print('# Keypoints 1: \t', len(kpts1)) +print('# Keypoints 2: \t', len(kpts2)) +print('# Matches: \t', len(matched1)) +print('# Inliers: \t', len(inliers1)) +print('# Inliers Ratio: \t', inlier_ratio) + +cv.imshow('result', res) +cv.waitKey() +## [draw final matches] diff --git a/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py b/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py index d22f9a8a6f..fbe35675d7 100644 --- a/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py +++ b/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py @@ -28,10 +28,9 @@ knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2) #-- Filter matches using the Lowe's ratio test ratio_thresh = 0.7 good_matches = [] -for matches in knn_matches: - if len(matches) > 1: - if matches[0].distance / matches[1].distance <= ratio_thresh: - good_matches.append(matches[0]) +for m,n in knn_matches: + if m.distance < ratio_thresh * n.distance: + good_matches.append(m) #-- Draw matches img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8) diff --git a/samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py b/samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py index 8820addce2..8ef500e7af 100644 --- a/samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py +++ b/samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py @@ -28,10 +28,9 @@ knn_matches = matcher.knnMatch(descriptors_obj, descriptors_scene, 2) #-- Filter matches using the Lowe's ratio test ratio_thresh = 0.75 good_matches = [] -for matches in knn_matches: - if len(matches) > 1: - if matches[0].distance / matches[1].distance <= ratio_thresh: - good_matches.append(matches[0]) +for m,n in knn_matches: + if m.distance < ratio_thresh * n.distance: + good_matches.append(m) #-- Draw matches img_matches = np.empty((max(img_object.shape[0], img_scene.shape[0]), img_object.shape[1]+img_scene.shape[1], 3), dtype=np.uint8)