mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
OpenCV 3.4.2
This commit is contained in:
commit
9e1b1e5389
2
3rdparty/carotene/hal/tegra_hal.hpp
vendored
2
3rdparty/carotene/hal/tegra_hal.hpp
vendored
@ -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__); \
|
||||
} \
|
||||
|
@ -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 <m1> [<m2> ...]] SRCS <src1> [<src2> ...])
|
||||
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)
|
||||
|
@ -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)
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||

|
||||
|
||||
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 at least 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
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
@ -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:
|
||||
|
@ -7,7 +7,6 @@ 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).
|
||||
|
||||
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).
|
||||
|
||||

|
||||
|
||||
@ -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**
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py load
|
||||
@end_toggle
|
||||
|
||||
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.
|
||||
|
||||
-# **Detect keypoints and compute descriptors using AKAZE**
|
||||
@code{.cpp}
|
||||
vector<KeyPoint> kpts1, kpts2;
|
||||
Mat desc1, desc2;
|
||||
- **Detect keypoints and compute descriptors using AKAZE**
|
||||
|
||||
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*
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp AKAZE
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java AKAZE
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py AKAZE
|
||||
@end_toggle
|
||||
|
||||
We create AKAZE and detect and compute AKAZE keypoints and descriptors. Since we don't need the *mask*
|
||||
parameter, *noArray()* is used.
|
||||
|
||||
-# **Use brute-force matcher to find 2-nn matches**
|
||||
@code{.cpp}
|
||||
BFMatcher matcher(NORM_HAMMING);
|
||||
vector< vector<DMatch> > nn_matches;
|
||||
matcher.knnMatch(desc1, desc2, nn_matches, 2);
|
||||
@endcode
|
||||
- **Use brute-force matcher to find 2-nn matches**
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp 2-nn matching
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java 2-nn matching
|
||||
@end_toggle
|
||||
|
||||
@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 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;
|
||||
- **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
|
||||
|
||||
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_java
|
||||
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java ratio test filtering
|
||||
@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<double>(0) = matched1[i].pt.x;
|
||||
col.at<double>(1) = matched1[i].pt.y;
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py ratio test filtering
|
||||
@end_toggle
|
||||
|
||||
col = homography * col;
|
||||
col /= col.at<double>(2);
|
||||
float dist = sqrt( pow(col.at<double>(0) - matched2[i].pt.x, 2) +
|
||||
pow(col.at<double>(1) - matched2[i].pt.y, 2));
|
||||
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(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.
|
||||
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**
|
||||
@code{.cpp}
|
||||
Mat res;
|
||||
drawMatches(img1, inliers1, img2, inliers2, good_matches, res);
|
||||
imwrite("res.png", res);
|
||||
...
|
||||
@endcode
|
||||
- **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
|
||||
Results
|
||||
-------
|
||||
|
||||
Found matches
|
||||
-------------
|
||||
### Found matches
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
@ -98,6 +98,8 @@ OpenCV.
|
||||
|
||||
- @subpage tutorial_akaze_matching
|
||||
|
||||
*Languages:* C++, Java, Python
|
||||
|
||||
*Compatibility:* \> OpenCV 3.0
|
||||
|
||||
*Author:* Fedor Morozov
|
||||
|
@ -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).
|
||||
@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:
|
||||
- Load the source image and check if it is loaded without any problem, then show it:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java load_image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py load_image
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
-# 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:
|
||||
- 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:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg
|
||||
@end_toggle
|
||||
|
||||
@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
|
||||
|
||||

|
||||
|
||||
-# 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):
|
||||
- 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
|
||||
|
||||

|
||||

|
||||
|
||||
-# Now we transform our new sharpened source image to a grayscale and a binary one, respectively:
|
||||
- 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
|
||||
|
||||

|
||||
|
||||
-# 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:
|
||||
- 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
|
||||
|
||||

|
||||
|
||||
-# We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image:
|
||||
- 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
|
||||
|
||||

|
||||
|
||||
-# From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function:
|
||||
- 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
|
||||
|
||||

|
||||
|
||||
-# Finally, we can apply the watershed algorithm, and visualize the result:
|
||||
- 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
|
||||
|
||||

|
@ -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.
|
||||
- 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
|
||||
-# Create a window with header "Source" and display the source file in it.
|
||||
@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
|
||||
-# Create a trackbar on the source_window and assign a callback function to it
|
||||
@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`.
|
||||
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
|
||||
-# For every found contour we now apply approximation to polygons
|
||||
with accuracy +-3 and stating that the curve must me closed.
|
||||
@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.
|
||||
|
||||
@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).
|
||||
|
||||
@add_toggle_cpp
|
||||
@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,
|
||||
@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
|
||||
-# Display the results: create a new window "Contours" and show everything we added to drawings on it.
|
||||
@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
|
||||
------
|
||||
|
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -17,6 +17,7 @@
|
||||
// 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.
|
||||
//
|
||||
@ -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<uchar> solutionMask(nsolutions, (uchar)1);
|
||||
std::vector<Mat> normals(nsolutions);
|
||||
std::vector<Mat> 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<Point2f>(j);
|
||||
Point2f currPoint = afterRectifiedPoints.at<Point2f>(j);
|
||||
|
||||
for( int i = 0; i < nsolutions; i++ )
|
||||
{
|
||||
if( !solutionMask[i] )
|
||||
continue;
|
||||
|
||||
const double* normal_i = normals[i].ptr<double>();
|
||||
const double* rotnorm_i = rotnorm[i].ptr<double>();
|
||||
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<int> possibleSolutions;
|
||||
for( int i = 0; i < nsolutions; i++ )
|
||||
if( solutionMask[i] )
|
||||
possibleSolutions.push_back(i);
|
||||
|
||||
Mat(possibleSolutions).copyTo(_possibleSolutions);
|
||||
}
|
||||
|
||||
} //namespace cv
|
||||
|
575
modules/calib3d/test/test_filter_homography_decomp.cpp
Normal file
575
modules/calib3d/test/test_filter_homography_decomp.cpp
Normal file
@ -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<int> 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<Point2f> 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<Point2f> prevRectifiedPoints(prevRectifiedPointArr_2f, prevRectifiedPointArr_2f +
|
||||
sizeof(prevRectifiedPointArr) / sizeof(prevRectifiedPointArr[0]) / 2);
|
||||
|
||||
_prevRectifiedPoints.swap(prevRectifiedPoints);
|
||||
|
||||
int validSolutionArr[2] = { 0, 2 };
|
||||
|
||||
vector<int> validSolutions(validSolutionArr, validSolutionArr +
|
||||
sizeof(validSolutionArr) / sizeof(validSolutionArr[0]));
|
||||
|
||||
_validSolutions.swap(validSolutions);
|
||||
|
||||
vector<Mat> rotations;
|
||||
vector<Mat> 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<int>& solutions)
|
||||
{
|
||||
return (solutions == _validSolutions);
|
||||
}
|
||||
|
||||
vector<int> _validSolutions;
|
||||
vector<Point2f> _prevRectifiedPoints, _currRectifiedPoints;
|
||||
Mat _mask;
|
||||
vector<Mat> _rotations, _normals;
|
||||
};
|
||||
|
||||
TEST(Calib3d_FilterDecomposeHomography, regression) { CV_FilterHomographyDecompTest test; test.safe_run(); }
|
||||
|
||||
}}
|
@ -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<double>(i) < iwTypeGetMin(ipp32f) || _val.at<double>(i) > iwTypeGetMax(ipp32f))
|
||||
{
|
||||
float v = (float)(_val.at<double>(i)); // cast to float
|
||||
if (cvIsNaN(v) || cvIsInf(v)) // accept finite numbers only
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(dst.dims <= 2)
|
||||
{
|
||||
|
@ -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<uchar>(1,0) = 0;
|
||||
test_mask.at<uchar>(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<float>::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<float>(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)
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -361,6 +361,23 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
|
||||
static Ptr<PermuteLayer> 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<Layer> 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<ResizeLayer> 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<Layer> create(const LayerParams& params);
|
||||
};
|
||||
|
||||
class CV_EXPORTS ProposalLayer : public Layer
|
||||
{
|
||||
public:
|
||||
|
@ -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<DNNBackend, DNNTarget> testCases[] = {
|
||||
#ifdef HAVE_HALIDE
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),
|
||||
|
@ -212,6 +212,44 @@ namespace cv {
|
||||
fused_layer_names.push_back(last_layer);
|
||||
}
|
||||
|
||||
void setAvgpool()
|
||||
{
|
||||
cv::dnn::LayerParams avgpool_param;
|
||||
avgpool_param.set<cv::String>("pool", "ave");
|
||||
avgpool_param.set<bool>("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<int>(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<int>(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<std::string>(layer_params, "layers", "");
|
||||
|
@ -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<LayerPin> getLayerOutPins(const String &pinAlias)
|
||||
std::vector<LayerPin> getLayerOutPins(const String &layerName)
|
||||
{
|
||||
String layerName, outName;
|
||||
splitPin(pinAlias, layerName, outName);
|
||||
|
||||
int lid = (layerName.empty()) ? 0 : getLayerId(layerName);
|
||||
|
||||
std::vector<LayerPin> 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<Layer>& currLayer = ld.layerInstance;
|
||||
@ -2013,11 +1993,17 @@ Net Net::readFromModelOptimizer(const String& xml, const String& bin)
|
||||
backendNode->net = Ptr<InfEngineBackendNet>(new InfEngineBackendNet(ieNet));
|
||||
for (auto& it : ieNet.getOutputsInfo())
|
||||
{
|
||||
Ptr<Layer> 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<Layer>(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)
|
||||
|
@ -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);
|
||||
|
@ -96,6 +96,46 @@ public:
|
||||
shift = bias_;
|
||||
}
|
||||
|
||||
virtual bool tryFuse(Ptr<Layer>& 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<float>(0), weights_);
|
||||
multiply(bias_, w.at<float>(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<float>(0), bias_);
|
||||
else
|
||||
add(bias_, b.reshape(1, 1), bias_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
||||
const int requiredOutputs,
|
||||
std::vector<MatShape> &outputs,
|
||||
|
@ -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<Mat*> &inputs, std::vector<Mat> &outputs) CV_OVERRIDE
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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<BackendNode> tryAttach(const Ptr<BackendNode>& 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);
|
||||
|
@ -310,7 +310,6 @@ public:
|
||||
innerProductOp = Ptr<OCL4DNNInnerProduct<float> >(new OCL4DNNInnerProduct<float>(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);
|
||||
}
|
||||
|
@ -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<OCL4DNNPool<float> >(new OCL4DNNPool<float>(config));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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<String>("interpolation");
|
||||
CV_Assert(interpolation == "nearest" || interpolation == "bilinear");
|
||||
|
||||
alignCorners = params.get<bool>("align_corners", false);
|
||||
bool alignCorners = params.get<bool>("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<Mat*>& inputs, std::vector<Mat> &outputs) CV_OVERRIDE
|
||||
@ -64,6 +66,8 @@ public:
|
||||
outHeight = outputs[0].size[2];
|
||||
outWidth = outputs[0].size[3];
|
||||
}
|
||||
scaleHeight = static_cast<float>(inputs[0]->size[2]) / outHeight;
|
||||
scaleWidth = static_cast<float>(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<float>(inpHeight) / (outHeight);
|
||||
const float widthScale = static_cast<float>(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<int>(input_y);
|
||||
const float* inpData_row0 = inpPlanes.ptr<float>(y0);
|
||||
const float* inpData_row1 = inpPlanes.ptr<float>(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<int>(input_x);
|
||||
int x1 = std::min(x0 + 1, inpWidth - 1);
|
||||
|
||||
@ -160,10 +162,10 @@ public:
|
||||
return Ptr<BackendNode>();
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
int outWidth, outHeight, zoomFactorWidth, zoomFactorHeight;
|
||||
String interpolation;
|
||||
bool alignCorners;
|
||||
float scaleWidth, scaleHeight;
|
||||
};
|
||||
|
||||
|
||||
@ -172,5 +174,44 @@ Ptr<ResizeLayer> ResizeLayer::create(const LayerParams& params)
|
||||
return Ptr<ResizeLayer>(new ResizeLayerImpl(params));
|
||||
}
|
||||
|
||||
class InterpLayerImpl CV_FINAL : public ResizeLayerImpl
|
||||
{
|
||||
public:
|
||||
InterpLayerImpl(const LayerParams& params) : ResizeLayerImpl(params) {}
|
||||
|
||||
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
||||
const int requiredOutputs,
|
||||
std::vector<MatShape> &outputs,
|
||||
std::vector<MatShape> &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<Mat*>& inputs, std::vector<Mat> &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<float>(inpHeight - 1) / (outHeight - 1)) : 0.f;
|
||||
scaleWidth = (outWidth > 1) ? (static_cast<float>(inpWidth - 1) / (outWidth - 1)) : 0.f;
|
||||
}
|
||||
};
|
||||
|
||||
Ptr<Layer> InterpLayer::create(const LayerParams& params)
|
||||
{
|
||||
LayerParams lp(params);
|
||||
lp.set("interpolation", "bilinear");
|
||||
return Ptr<Layer>(new InterpLayerImpl(lp));
|
||||
}
|
||||
|
||||
} // namespace dnn
|
||||
} // namespace cv
|
||||
|
104
modules/dnn/src/layers/shuffle_channel_layer.cpp
Normal file
104
modules/dnn/src/layers/shuffle_channel_layer.cpp
Normal file
@ -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<int>("group", 1);
|
||||
}
|
||||
|
||||
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
||||
const int requiredOutputs,
|
||||
std::vector<MatShape> &outputs,
|
||||
std::vector<MatShape> &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<Mat*>& inputs, std::vector<Mat> &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<Mat*> permuteInputs(1, &inp);
|
||||
std::vector<Mat> 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<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &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<Mat*> permuteInputs(1, &inp);
|
||||
std::vector<Mat> permuteOutputs(1, out);
|
||||
permute->forward(permuteInputs, permuteOutputs, internals);
|
||||
}
|
||||
else
|
||||
inp.copyTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Ptr<PermuteLayer> permute;
|
||||
std::vector<int> permuteInpShape, permuteOutShape;
|
||||
};
|
||||
|
||||
Ptr<Layer> ShuffleChannelLayer::create(const LayerParams& params)
|
||||
{
|
||||
return Ptr<Layer>(new ShuffleChannelLayerImpl(params));
|
||||
}
|
||||
|
||||
} // namespace dnn
|
||||
} // namespace cv
|
@ -41,6 +41,7 @@
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "../op_inf_engine.hpp"
|
||||
#include "layers_common.hpp"
|
||||
#include <opencv2/dnn/shape_utils.hpp>
|
||||
|
||||
@ -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<MatShape> &inputs,
|
||||
const int requiredOutputs,
|
||||
std::vector<MatShape> &outputs,
|
||||
@ -247,6 +254,29 @@ public:
|
||||
inpMat(sliceRanges[i]).copyTo(outputs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >& 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<InferenceEngine::CropLayer> 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<BackendNode>(new InfEngineBackendNode(ieLayer));
|
||||
|
||||
#endif // HAVE_INF_ENGINE
|
||||
return Ptr<BackendNode>();
|
||||
}
|
||||
};
|
||||
|
||||
Ptr<SliceLayer> SliceLayer::create(const LayerParams& params)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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<kernelConfig> > 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;
|
||||
};
|
||||
|
||||
|
@ -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 <windows.h>
|
||||
@ -67,6 +68,69 @@ typedef std::map<std::string, std::string> 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<std::string, std::string> 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<std::string, std::string> entry(
|
||||
key,
|
||||
default_kernel_config_intel_fp16[2 * i + 1]);
|
||||
kernelConfigMap.insert(entry);
|
||||
}
|
||||
|
||||
defaultConfigLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
template<typename Dtype>
|
||||
OCL4DNNConvSpatial<Dtype>::OCL4DNNConvSpatial(OCL4DNNConvConfig config)
|
||||
{
|
||||
@ -139,9 +203,8 @@ OCL4DNNConvSpatial<Dtype>::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<typename Dtype>
|
||||
@ -272,40 +335,38 @@ void OCL4DNNConvSpatial<Dtype>::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_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 tile_y_stride = (4 * simd_size) / tile_x;
|
||||
int invec_size = divUp(tile_y, tile_y_stride);
|
||||
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<Dtype>::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<Dtype>::calculateBenchmark(const UMat &bottom, UMat &ver
|
||||
template<typename Dtype>
|
||||
void OCL4DNNConvSpatial<Dtype>::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<Dtype>::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<Dtype>::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<float>::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<float>::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<float>::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<float>::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<float>::generate_idlf_tuneritems(std::vector< cv::Ptr<tu
|
||||
return;
|
||||
|
||||
int actual_tile_x = kernel_w_ * dilation_w_ + (blockM - 1) * stride_w_ ;
|
||||
int tile_x = alignSize(actual_tile_x, 4);
|
||||
int tile_y = kernel_h_ * dilation_h_ + (blockK - 1) * stride_h_;
|
||||
if (tile_x > (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<tunerParam>(KERNEL_TYPE_INTEL_IDLF, blockM, blockK, simd_size));
|
||||
@ -1570,11 +1596,7 @@ void OCL4DNNConvSpatial<float>::generateTunerItems(std::vector< cv::Ptr<tunerPar
|
||||
for (uint32_t height = height_max; height > 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,10 +1683,8 @@ void OCL4DNNConvSpatial<float>::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]: "
|
||||
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] << " "
|
||||
@ -1685,11 +1705,9 @@ void OCL4DNNConvSpatial<float>::setupConvolution(const UMat &bottom,
|
||||
<< "kernelQueue[x]->local_work_size[2]: "
|
||||
<< kernelQueue[x]->local_work_size[2] << " "
|
||||
<< kernelQueue[x]->swizzle_weights << " "
|
||||
<< kernelQueue[x]->use_null_local << std::endl);
|
||||
<< 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<float>::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;
|
||||
@ -1805,7 +1832,7 @@ void OCL4DNNConvSpatial<Dtype>::prepareKernel(const UMat &bottom, UMat &top,
|
||||
|
||||
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<typename Dtype>
|
||||
bool OCL4DNNConvSpatial<Dtype>::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<std::string, std::string> 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<Dtype>::setupKernelByConfig(int x, int y, int z, int typ
|
||||
template<typename Dtype>
|
||||
bool OCL4DNNConvSpatial<Dtype>::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_)
|
||||
|
@ -56,6 +56,7 @@ OCL4DNNPool<Dtype>::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<Dtype>::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<Dtype>::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<Dtype>::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())
|
||||
|
@ -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,124 +217,76 @@ __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 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<OUT_BLOCK_SIZE;i++) {
|
||||
out[i]=0.0f;
|
||||
}
|
||||
unsigned int num_in_batch = fm / ALIGNED_NUM_FILTERS;
|
||||
|
||||
unsigned int num_in_batch = ( fm ) / ALIGNED_NUM_FILTERS;
|
||||
unsigned int input_batch_offset = num_in_batch * INPUT_PITCH * TOTAL_INPUT_DEPTH_SIZE;
|
||||
|
||||
unsigned int input_batch_offset = num_in_batch * input_height * input_width * TOTAL_INPUT_DEPTH_SIZE;
|
||||
|
||||
int curr_local_y = ( lid / ( TILE_X / 4 ) );
|
||||
int curr_local_x = ( lid % ( TILE_X / 4 ) ) * 4;
|
||||
int curr_y = or * STRIDE_Y + curr_local_y;
|
||||
int curr_x = oc * STRIDE_X + curr_local_x;
|
||||
int curr_y = or * STRIDE_Y;
|
||||
int curr_x = oc * STRIDE_X + lid;
|
||||
#if INPUT_PAD_W != 0 || INPUT_PAD_H != 0 || INPUT_PAD_BOTTOM != 0 || INPUT_PAD_RIGHT != 0
|
||||
int saved_y = curr_y;
|
||||
#endif
|
||||
in_addr = input_batch_offset
|
||||
+ (curr_y - INPUT_PAD_H) * input_width // y tile offset
|
||||
int in_addr = input_batch_offset
|
||||
+ (curr_y - INPUT_PAD_H) * INPUT_WIDTH // y tile offset
|
||||
+ curr_x - INPUT_PAD_W; // x tile offset
|
||||
union {
|
||||
Dtype4 in_vec[INVEC_SIZE];
|
||||
Dtype in_array[INVEC_SIZE * 4];
|
||||
} in_buf;
|
||||
|
||||
Dtype in_buf[INVEC_SIZE];
|
||||
|
||||
for(int kd = 0; kd < INPUT_DEPTH; kd++)
|
||||
{
|
||||
int in_offset = in_addr;
|
||||
int reg = 0;
|
||||
LOOP(INVEC_SIZE, reg,
|
||||
__attribute__((opencl_unroll_hint(INVEC_SIZE)))
|
||||
for (int reg = 0; reg < INVEC_SIZE; reg++)
|
||||
{
|
||||
if (curr_local_y + reg * TILE_Y_STRIDE < TILE_Y || INVEC_SIZE * TILE_Y_STRIDE <= (TILE_Y + 2) || reg < INVEC_SIZE - 1) {
|
||||
in_buf[reg] = inputs[in_offset];
|
||||
#if INPUT_PAD_W != 0 || INPUT_PAD_H != 0 || INPUT_PAD_BOTTOM != 0 || INPUT_PAD_RIGHT != 0
|
||||
if (curr_y >= 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;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
in_buf.in_vec[reg] = 0;
|
||||
}
|
||||
curr_y += TILE_Y_STRIDE;
|
||||
#else
|
||||
VLOAD4(in_buf.in_vec[reg], inputs + in_offset);
|
||||
#endif
|
||||
curr_y += 1;
|
||||
in_offset += INPUT_WIDTH;
|
||||
}
|
||||
in_offset += input_width * TILE_Y_STRIDE;
|
||||
});
|
||||
in_addr += input_height * 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.
|
||||
@ -344,51 +294,29 @@ convolve_simd(
|
||||
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
|
||||
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;
|
||||
#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
|
||||
@ -396,13 +324,16 @@ convolve_simd(
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,28 +65,33 @@ __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 ph = (index / pooled_width) % pooled_height;
|
||||
const int c = (index / pooled_width / pooled_height) % channels;
|
||||
const int n = index / pooled_width / pooled_height / channels;
|
||||
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;
|
||||
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 in_offset = ch * height * width;
|
||||
for (int h = 0; h < KERNEL_H; ++h)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,7 +100,6 @@ __kernel void
|
||||
mask[index] = maxidx;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined KERNEL_AVE_POOL
|
||||
|
||||
@ -105,14 +109,14 @@ __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))
|
||||
{
|
||||
{
|
||||
int index = get_global_id(0);
|
||||
if (index >= nthreads)
|
||||
return;
|
||||
|
||||
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;
|
||||
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);
|
||||
@ -132,17 +136,16 @@ __kernel void TEMPLATE(ave_pool_forward, Dtype)(
|
||||
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];
|
||||
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
|
||||
|
||||
|
@ -18,6 +18,7 @@ Implementation of Tensorflow models parser
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#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<std::pair<String, int> > 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<String, int>& data_layouts)
|
||||
{
|
||||
std::map<String, int>::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<int>(val.list().i(1)));
|
||||
layerParams.set("stride_w", static_cast<int>(val.list().i(2)));
|
||||
layerParams.set("stride_h", static_cast<int>(val.list().i(dimY)));
|
||||
layerParams.set("stride_w", static_cast<int>(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<int>(val.list().i(1)));
|
||||
layerParams.set("kernel_w", static_cast<int>(val.list().i(2)));
|
||||
layerParams.set("kernel_h", static_cast<int>(val.list().i(dimY)));
|
||||
layerParams.set("kernel_w", static_cast<int>(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<String> netInputsNames;
|
||||
};
|
||||
|
||||
TFImporter::TFImporter(const char *model, const char *config)
|
||||
@ -442,7 +493,14 @@ void TFImporter::connect(const std::map<String, int>& layers_name_id_map, Net& n
|
||||
std::map<String, int>::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<String>::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<String, int>& layer_id, Net& network, const Pin& outPin,
|
||||
@ -560,39 +618,38 @@ static void addConstNodes(tensorflow::GraphDef& net, std::map<String, int>& 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<String, int>& data_layouts)
|
||||
static int predictOutputDataLayout(const tensorflow::GraphDef& net,
|
||||
const tensorflow::NodeDef& layer,
|
||||
const std::map<String, int>& 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<String, int>::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;
|
||||
}
|
||||
}
|
||||
|
||||
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<String, int> 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<String, int>::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<String, int> 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<int32_t>(0, 2), *newShape.ptr<int32_t>(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<String> netInputs(1);
|
||||
netInputs[0] = name;
|
||||
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;
|
||||
dstNet.setInputsNames(netInputs);
|
||||
}
|
||||
}
|
||||
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<int32_t>(0, 2), *begins.ptr<int32_t>(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<int>(i) = toNCHW(reductionIndices.at<int>(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<float>(0));
|
||||
layerParams.set("max_value", maxValue.at<float>(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
|
||||
|
@ -592,8 +592,8 @@ struct TorchImporter
|
||||
DictValue dimParam = scalarParams.get("size");
|
||||
layerParams.set("dim", dimParam);
|
||||
|
||||
if (scalarParams.has("batchMode") && scalarParams.get<bool>("batchMode"))
|
||||
layerParams.set("axis", 1);
|
||||
int axis = (int)scalarParams.get<bool>("batchMode", true);
|
||||
layerParams.set("axis", axis);
|
||||
|
||||
curModule->modules.push_back(newModule);
|
||||
}
|
||||
|
@ -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<DNNBackend, DNNTarget> testCases[] = {
|
||||
#ifdef HAVE_HALIDE
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_HALIDE, DNN_TARGET_CPU),
|
||||
|
@ -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();
|
||||
|
@ -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<cv::String> outNames(1, "detection_out");
|
||||
|
||||
std::vector<int> 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
|
||||
|
@ -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<int> 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<uint8_t>(y, x);
|
||||
if ((float)inp.at<uint8_t>(y, x) > maxValues.at<float>(dstY, dstX))
|
||||
{
|
||||
maxValues.at<float>(dstY, dstX) = val;
|
||||
indices.at<float>(dstY, dstX) = y * 10 + x;
|
||||
}
|
||||
}
|
||||
}
|
||||
net.setPreferableBackend(DNN_BACKEND_OPENCV);
|
||||
net.setInput(blobFromImage(inp));
|
||||
|
||||
std::vector<Mat> outputs;
|
||||
net.forward(outputs, lp.name);
|
||||
normAssert(maxValues, outputs[0].reshape(1, 5));
|
||||
normAssert(indices, outputs[1].reshape(1, 5));
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<Vec4i, int> > 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Mat> 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.
|
||||
|
@ -175,8 +175,6 @@ bool SunRasterDecoder::readData( Mat& img )
|
||||
|
||||
AutoBuffer<uchar> _src(src_pitch + 32);
|
||||
uchar* src = _src;
|
||||
AutoBuffer<uchar> _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 );
|
||||
}
|
||||
}
|
||||
|
@ -670,6 +670,14 @@ public:
|
||||
void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& 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<Point> &points, double eps_x = 0.2, double eps_y = 0.1);
|
||||
|
||||
//! @} objdetect
|
||||
|
||||
}
|
||||
|
775
modules/objdetect/src/qrcode.cpp
Normal file
775
modules/objdetect/src/qrcode.cpp
Normal file
@ -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 <limits>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
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<Point> getTransformationPoints() { return transformation_points; }
|
||||
Mat getStraightBarcode() { return straight_barcode; }
|
||||
protected:
|
||||
std::vector<Vec3d> searchVerticalLines();
|
||||
std::vector<Vec3d> separateHorizontalLines(std::vector<Vec3d> list_lines);
|
||||
std::vector<Vec3d> pointClustering(std::vector<Vec3d> list_lines);
|
||||
void fixationPoints(std::vector<Point> &local_point, std::vector<double> &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<Point> getQuadrilateral(std::vector<Point> 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<Point> localization_points, transformation_points;
|
||||
std::vector<double> localization_length;
|
||||
double experimental_area;
|
||||
|
||||
double eps_vertical, eps_horizontal;
|
||||
std::vector<Vec3d> result;
|
||||
std::vector<double> 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<Vec3d> list_lines_x = searchVerticalLines();
|
||||
std::vector<Vec3d> list_lines_y = separateHorizontalLines(list_lines_x);
|
||||
std::vector<Vec3d> result_point = pointClustering(list_lines_y);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
localization_points.push_back(
|
||||
Point(static_cast<int>(result_point[i][0]),
|
||||
static_cast<int>(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<Vec3d> 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<uint8_t>(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<uint8_t>(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<Vec3d> QRDecode::separateHorizontalLines(std::vector<Vec3d> list_lines)
|
||||
{
|
||||
result.clear();
|
||||
int temp_length = 0;
|
||||
int x, y;
|
||||
|
||||
for (size_t pnt = 0; pnt < list_lines.size(); pnt++)
|
||||
{
|
||||
x = static_cast<int>(list_lines[pnt][0] + list_lines[pnt][2] / 2);
|
||||
y = static_cast<int>(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<uint8_t>(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<uint8_t>(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<Vec3d> QRDecode::pointClustering(std::vector<Vec3d> list_lines)
|
||||
{
|
||||
std::vector<Vec3d> centers;
|
||||
std::vector<Point> 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<int>(list_lines[0][1]), static_cast<int>(list_lines[0][0]));
|
||||
for (size_t i = 1; i < list_lines.size(); i++)
|
||||
{
|
||||
temp_pnt = Point(static_cast<int>(list_lines[i][1]), static_cast<int>(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<int>(list_lines[i][1]), static_cast<int>(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<int>(list_lines[i][1]), static_cast<int>(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<int>(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<Point> &local_point, std::vector<double> &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<float>(0, 0) = 1;
|
||||
vector_mult.at<float>(1, 0) = 1;
|
||||
vector_mult.at<float>(2, 0) = 1;
|
||||
vector_mult.at<float>(0, 1) = static_cast<float>((local_point[1] - local_point[0]).x);
|
||||
vector_mult.at<float>(1, 1) = static_cast<float>((local_point[1] - local_point[0]).y);
|
||||
vector_mult.at<float>(0, 2) = static_cast<float>((local_point[2] - local_point[0]).x);
|
||||
vector_mult.at<float>(1, 2) = static_cast<float>((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<Point> 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<int>(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<Point> 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<double>::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<uint8_t>(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<float>(0, 0) = 1;
|
||||
vector_mult.at<float>(1, 0) = 1;
|
||||
vector_mult.at<float>(2, 0) = 1;
|
||||
vector_mult.at<float>(0, 1) = static_cast<float>((left - center).x);
|
||||
vector_mult.at<float>(1, 1) = static_cast<float>((left - center).y);
|
||||
vector_mult.at<float>(0, 2) = static_cast<float>((left - start_pnt).x);
|
||||
vector_mult.at<float>(1, 2) = static_cast<float>((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<int>(
|
||||
static_cast<double>
|
||||
((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<int>(
|
||||
static_cast<double>
|
||||
((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<Point> QRDecode::getQuadrilateral(std::vector<Point> 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<uint8_t>(line_iter.pos());
|
||||
mask_value = mask.at<uint8_t>(line_iter.pos() + Point(1, 1));
|
||||
if (value == 0 && mask_value == 0)
|
||||
{
|
||||
floodFill(bin_barcode, mask, line_iter.pos(), 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<Point> 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<Point> > hull(1), approx_hull(1);
|
||||
convexHull(Mat(locations), hull[0]);
|
||||
int hull_size = static_cast<int>(hull[0].size());
|
||||
|
||||
Point min_pnt;
|
||||
|
||||
std::vector<Point> min_abc;
|
||||
double min_abs_cos_abc, abs_cos_abc;
|
||||
for (int count = 0; count < 4; count++)
|
||||
{
|
||||
min_abs_cos_abc = std::numeric_limits<double>::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<int>(min_abc.size());
|
||||
std::vector<int> 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<Point> result_hull_point(angle_size);
|
||||
double min_norm, temp_norm;
|
||||
for (size_t i = 0; i < angle_size; i++)
|
||||
{
|
||||
min_norm = std::numeric_limits<double>::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<double>::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<double>::max())
|
||||
{
|
||||
result_side_begin[0] = angle_list[2];
|
||||
result_side_end[0] = angle_list[3];
|
||||
}
|
||||
|
||||
min_norm = std::numeric_limits<double>::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<double>::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<int>(start_line[0])
|
||||
: static_cast<int>(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<Point> result_angle_list(4), test_result_angle_list(4);
|
||||
double min_area = std::numeric_limits<double>::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<Point> &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;
|
||||
}
|
||||
|
||||
}
|
74
modules/objdetect/test/test_qrcode.cpp
Normal file
74
modules/objdetect/test/test_qrcode.cpp
Normal file
@ -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<Rect> 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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -251,6 +251,8 @@ when fullAffine=false.
|
||||
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, int ransacMaxIters, double ransacGoodRatio,
|
||||
int ransacSize0);
|
||||
|
||||
|
||||
enum
|
||||
|
@ -1412,7 +1412,7 @@ namespace cv
|
||||
{
|
||||
|
||||
static void
|
||||
getRTMatrix( const Point2f* a, const Point2f* b,
|
||||
getRTMatrix( const std::vector<Point2f> a, const std::vector<Point2f> 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<Point2f> pA, pB;
|
||||
std::vector<int> 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<Point2f> a(ransacSize0);
|
||||
std::vector<Point2f> 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<int> 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<double>(0, 2) /= scale;
|
||||
M.at<double>(1, 2) /= scale;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 <comdef.h>
|
||||
|
||||
#include <shlwapi.h> // 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 T>
|
||||
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)
|
||||
{
|
||||
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()
|
||||
void Release()
|
||||
{
|
||||
if (p)
|
||||
p.Release();
|
||||
}
|
||||
|
||||
// query for U interface
|
||||
template<typename U>
|
||||
HRESULT As(_Inout_ U** lp) const
|
||||
HRESULT As(_Out_ ComPtr<U>& lp) const
|
||||
{
|
||||
return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp));
|
||||
}
|
||||
// query for U interface
|
||||
template<typename U>
|
||||
HRESULT As(_Out_ ComPtr<U>* lp) const
|
||||
{
|
||||
return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp->ReleaseAndGetAddressOf()));
|
||||
lp.Release();
|
||||
return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>((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<IMFSample>& 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<IMFSourceReader> m_reader;
|
||||
DWORD m_dwStreamIndex;
|
||||
_ComPtr<IMFSample> 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<IMFSample> videoSample;
|
||||
LONGLONG sampleTime;
|
||||
bool isOpen;
|
||||
_ComPtr<IMFSourceReaderCallback> 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<ID3D11Multithread> 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<IMFAttributes> 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<IMFAttributes> 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<IMFSourceReaderCallback>(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<IMFSample>& 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<IMF2DBuffer> buffer2d;
|
||||
if (convertFormat)
|
||||
{
|
||||
if (SUCCEEDED(buf.As<IMF2DBuffer>(&buffer2d)))
|
||||
if (SUCCEEDED(buf.As<IMF2DBuffer>(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::IVideoCapture> cv::cvCreateCapture_MSMF( int index )
|
||||
{
|
||||
cv::Ptr<CvCapture_MSMF> capture = cv::makePtr<CvCapture_MSMF>(index);
|
||||
if (capture && capture->isOpened())
|
||||
cv::Ptr<CvCapture_MSMF> capture = cv::makePtr<CvCapture_MSMF>();
|
||||
if (capture)
|
||||
{
|
||||
capture->open(index);
|
||||
if (capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
return cv::Ptr<cv::IVideoCapture>();
|
||||
}
|
||||
|
||||
cv::Ptr<cv::IVideoCapture> cv::cvCreateCapture_MSMF (const cv::String& filename)
|
||||
{
|
||||
cv::Ptr<CvCapture_MSMF> capture = cv::makePtr<CvCapture_MSMF>(filename);
|
||||
if (capture && capture->isOpened())
|
||||
cv::Ptr<CvCapture_MSMF> capture = cv::makePtr<CvCapture_MSMF>();
|
||||
if (capture)
|
||||
{
|
||||
capture->open(filename);
|
||||
if (capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
return cv::Ptr<cv::IVideoCapture>();
|
||||
}
|
||||
|
||||
@ -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::IVideoWriter> cv::cvCreateVideoWriter_MSMF( const cv::String& filename, int fourcc,
|
||||
double fps, cv::Size frameSize, int isColor )
|
||||
{
|
||||
cv::Ptr<CvVideoWriter_MSMF> writer = cv::makePtr<CvVideoWriter_MSMF>(filename, fourcc, fps, frameSize, isColor != 0);
|
||||
if (writer && writer->isOpened())
|
||||
cv::Ptr<CvVideoWriter_MSMF> writer = cv::makePtr<CvVideoWriter_MSMF>();
|
||||
if (writer)
|
||||
{
|
||||
writer->open(filename, fourcc, fps, frameSize, isColor != 0);
|
||||
if (writer->isOpened())
|
||||
return writer;
|
||||
}
|
||||
return cv::Ptr<cv::IVideoWriter>();
|
||||
}
|
||||
|
||||
|
@ -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<openni::VideoStream> streams;
|
||||
std::vector<openni::VideoFrameRef> streamFrames;
|
||||
std::vector<cv::Mat> 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)
|
||||
{
|
||||
// Initialize and configure the context.
|
||||
OpenNI2Initializer::init();
|
||||
|
||||
const char* deviceURI = openni::ANY_DEVICE;
|
||||
openni::Status status;
|
||||
bool needColor = true;
|
||||
bool needIR = true;
|
||||
if (index >= 0)
|
||||
{
|
||||
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();
|
||||
|
||||
if (status != openni::STATUS_OK)
|
||||
{
|
||||
CV_Error(CV_StsError, cv::format("Failed to initialize:", openni::OpenNI::getExtendedError()));
|
||||
return;
|
||||
}
|
||||
// Asus XTION and Occipital Structure Sensor do not have an image generator
|
||||
needColor = (deviceType != DEVICE_ASUS_XTION);
|
||||
|
||||
// find appropriate device URI
|
||||
openni::Array<openni::DeviceInfo> 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;
|
||||
CV_Error(CV_StsError, std::string("OpenCVKinect2: Failed to open device: ") + openni::OpenNI::getExtendedError());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
// try to set up default stream mode (if available)
|
||||
const openni::Array<openni::VideoMode>& vm = streams[stream].getSensorInfo().getSupportedVideoModes();
|
||||
openni::VideoMode dm = defaultStreamOutputMode(stream);
|
||||
for (int i = 0; i < vm.getSize(); i++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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
|
||||
|
||||
//streams[stream].stop();
|
||||
//streams[stream].destroy();
|
||||
}
|
||||
}
|
||||
|
||||
return openni::STATUS_OK;
|
||||
}
|
||||
|
||||
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<double>(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<double>(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;
|
||||
@ -531,8 +536,14 @@ bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )
|
||||
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<CvCapture_OpenNI2*>(this)->readCamerasParams();
|
||||
propValue = baseline;
|
||||
break;
|
||||
case CV_CAP_PROP_OPENNI_FOCAL_LENGTH :
|
||||
if(depthFocalLength_VGA <= 0)
|
||||
const_cast<CvCapture_OpenNI2*>(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,6 +959,8 @@ 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);
|
||||
|
||||
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -4,444 +4,373 @@
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
class GStreamerPipeline
|
||||
{
|
||||
public:
|
||||
// Preprocessing arguments command line
|
||||
GStreamerPipeline(int argc, char *argv[])
|
||||
{
|
||||
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"))
|
||||
template<typename M>
|
||||
inline typename M::mapped_type getValue(const M &dict, const typename M::key_type &key, const string & errorMessage)
|
||||
{
|
||||
cmd_parser->printMessage();
|
||||
CV_Error(Error::StsBadArg, "Called help.");
|
||||
typename M::const_iterator it = dict.find(key);
|
||||
if (it == dict.end())
|
||||
{
|
||||
CV_Error(Error::StsBadArg, errorMessage);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
fast_measure = cmd_parser->has("fast"); // fast measure fps
|
||||
fix_fps = cmd_parser->get<int>("fps"); // fixed frame per second
|
||||
pipeline = cmd_parser->get<string>("pipeline"), // gstreamer pipeline type
|
||||
mode = cmd_parser->get<string>("mode"), // coding mode
|
||||
codec = cmd_parser->get<string>("codec"), // codec type
|
||||
file_name = cmd_parser->get<string>("file"), // path to videofile
|
||||
resolution = cmd_parser->get<string>("resolution"); // video resolution
|
||||
inline map<string, Size> sizeByResolution()
|
||||
{
|
||||
map<string, Size> res;
|
||||
res["720p"] = Size(1280, 720);
|
||||
res["1080p"] = Size(1920, 1080);
|
||||
res["4k"] = Size(3840, 2160);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t found = file_name.rfind(".");
|
||||
inline map<string, int> fourccByCodec()
|
||||
{
|
||||
map<string, int> 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<string, string> defaultEncodeElementByCodec()
|
||||
{
|
||||
map<string, string> res;
|
||||
res["h264"] = "x264enc";
|
||||
res["h265"] = "x265enc";
|
||||
res["mpeg2"] = "mpeg2enc";
|
||||
res["mjpeg"] = "jpegenc";
|
||||
res["vp8"] = "vp8enc";
|
||||
return res;
|
||||
}
|
||||
|
||||
inline map<string, string> VAAPIEncodeElementByCodec()
|
||||
{
|
||||
map<string, string> 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<string, string> mfxDecodeElementByCodec()
|
||||
{
|
||||
map<string, string> res;
|
||||
res["h264"] = "parsebin ! mfxh264dec";
|
||||
res["h265"] = "parsebin ! mfxhevcdec";
|
||||
res["mpeg2"] = "parsebin ! mfxmpeg2dec";
|
||||
res["mjpeg"] = "parsebin ! mfxjpegdec";
|
||||
return res;
|
||||
}
|
||||
|
||||
inline map<string, string> mfxEncodeElementByCodec()
|
||||
{
|
||||
map<string, string> res;
|
||||
res["h264"] = "mfxh264enc";
|
||||
res["h265"] = "mfxhevcenc";
|
||||
res["mpeg2"] = "mfxmpeg2enc";
|
||||
res["mjpeg"] = "mfxjpegenc";
|
||||
return res;
|
||||
}
|
||||
|
||||
inline map<string, string> libavDecodeElementByCodec()
|
||||
{
|
||||
map<string, string> 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<string, string> libavEncodeElementByCodec()
|
||||
{
|
||||
map<string, string> 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<string, string> demuxPluginByContainer()
|
||||
{
|
||||
map<string, string> res;
|
||||
res["avi"] = "avidemux";
|
||||
res["mp4"] = "qtdemux";
|
||||
res["mov"] = "qtdemux";
|
||||
res["mkv"] = "matroskademux";
|
||||
return res;
|
||||
}
|
||||
|
||||
inline map<string, string> muxPluginByContainer()
|
||||
{
|
||||
map<string, string> 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)
|
||||
{
|
||||
container = file_name.substr(found + 1); // container type
|
||||
return 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.");
|
||||
}
|
||||
}
|
||||
|
||||
~GStreamerPipeline() { delete cmd_parser; }
|
||||
|
||||
// Start pipeline
|
||||
int run()
|
||||
{
|
||||
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<double> 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<double>(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;
|
||||
}
|
||||
|
||||
// Free video resource
|
||||
void close()
|
||||
{
|
||||
cap.release();
|
||||
wrt.release();
|
||||
}
|
||||
|
||||
private:
|
||||
// Choose the constructed GStreamer pipeline for decode
|
||||
int createDecodePipeline()
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unsupported pipeline: " << pipeline << endl;
|
||||
cmd_parser->printErrors();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Choose the constructed GStreamer pipeline for encode
|
||||
int createEncodePipeline()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Choose video resolution for encoding
|
||||
string getVideoSettings()
|
||||
{
|
||||
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); }
|
||||
//================================================================================
|
||||
|
||||
inline Ptr<VideoCapture> createCapture(const string &backend, const string &file_name, const string &codec)
|
||||
{
|
||||
if (backend == "gst-default")
|
||||
{
|
||||
cout << "Created GStreamer capture ( " << file_name << " )" << endl;
|
||||
return makePtr<VideoCapture>(file_name, CAP_GSTREAMER);
|
||||
}
|
||||
else if (backend.find("gst") == 0)
|
||||
{
|
||||
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
|
||||
return Ptr<VideoCapture>();
|
||||
line << " ! videoconvert n-threads=" << getNumThreads();
|
||||
line << " ! appsink sync=false";
|
||||
cout << "Created GStreamer capture ( " << line.str() << " )" << endl;
|
||||
return makePtr<VideoCapture>(line.str(), CAP_GSTREAMER);
|
||||
}
|
||||
else if (backend == "ffmpeg")
|
||||
{
|
||||
cout << "Unsupported video resolution: " << resolution << endl;
|
||||
cmd_parser->printErrors();
|
||||
return string();
|
||||
cout << "Created FFmpeg capture ( " << file_name << " )" << endl;
|
||||
return makePtr<VideoCapture>(file_name, CAP_FFMPEG);
|
||||
}
|
||||
return Ptr<VideoCapture>();
|
||||
}
|
||||
|
||||
video_size << "width=" << fix_size.width << ", height=" << fix_size.height;
|
||||
return video_size.str();
|
||||
inline Ptr<VideoCapture> 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<VideoCapture>(line.str(), CAP_GSTREAMER);
|
||||
}
|
||||
|
||||
// Choose a video container
|
||||
string getGstMuxPlugin()
|
||||
inline Ptr<VideoWriter> createWriter(const string &backend, const string &file_name, const string &codec, Size sz, unsigned fps)
|
||||
{
|
||||
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"; }
|
||||
if (backend == "gst-default")
|
||||
{
|
||||
cout << "Created GStreamer writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << ")" << endl;
|
||||
return makePtr<VideoWriter>(file_name, CAP_GSTREAMER, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true);
|
||||
}
|
||||
else if (backend.find("gst") == 0)
|
||||
{
|
||||
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
|
||||
return Ptr<VideoWriter>();
|
||||
line << " ! ";
|
||||
line << getValue(muxPluginByContainer(), containerByName(file_name), "Invalid container");
|
||||
line << " ! ";
|
||||
line << "filesink location=\"" << file_name << "\"";
|
||||
cout << "Created GStreamer writer ( " << line.str() << " )" << endl;
|
||||
return makePtr<VideoWriter>(line.str(), CAP_GSTREAMER, 0, fps, sz, true);
|
||||
}
|
||||
else if (backend == "ffmpeg")
|
||||
{
|
||||
cout << "Unsupported container: " << container << endl;
|
||||
cmd_parser->printErrors();
|
||||
return string();
|
||||
cout << "Created FFMpeg writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << " )" << endl;
|
||||
return makePtr<VideoWriter>(file_name, CAP_FFMPEG, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true);
|
||||
}
|
||||
return Ptr<VideoWriter>();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Choose a libav codec
|
||||
string getGstAvCodePlugin()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// 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<unsigned>("fps"); // fixed frame per second
|
||||
string backend = cmd_parser.get<string>("backend"); // video backend
|
||||
string mode = cmd_parser.get<string>("mode"); // coding mode
|
||||
string codec = cmd_parser.get<string>("codec"); // codec type
|
||||
string file_name = cmd_parser.get<string>("file"); // path to videofile
|
||||
string resolution = cmd_parser.get<string>("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<VideoCapture> cap;
|
||||
Ptr<VideoWriter> wrt;
|
||||
try
|
||||
{
|
||||
GStreamerPipeline pipe(argc, argv);
|
||||
return pipe.run();
|
||||
}
|
||||
catch(const Exception& e)
|
||||
if (mode == "decode")
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
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 (...)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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,15 +11,18 @@
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//! [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<String>( "@input" ) );
|
||||
if( src.empty() )
|
||||
{
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
cout << "Usage: " << argv[0] << " <Input image>" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Show source image
|
||||
imshow("Source Image", src);
|
||||
@ -29,12 +31,13 @@ int main()
|
||||
//! [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<Vec3b>(x, y) == Vec3b(255,255,255) ) {
|
||||
src.at<Vec3b>(x, y)[0] = 0;
|
||||
src.at<Vec3b>(x, y)[1] = 0;
|
||||
src.at<Vec3b>(x, y)[2] = 0;
|
||||
for ( int i = 0; i < src.rows; i++ ) {
|
||||
for ( int j = 0; j < src.cols; j++ ) {
|
||||
if ( src.at<Vec3b>(i, j) == Vec3b(255,255,255) )
|
||||
{
|
||||
src.at<Vec3b>(i, j)[0] = 0;
|
||||
src.at<Vec3b>(i, j)[1] = 0;
|
||||
src.at<Vec3b>(i, j)[2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,7 +47,7 @@ int main()
|
||||
//! [black_bg]
|
||||
|
||||
//! [sharp]
|
||||
// Create a kernel that we will use for accuting/sharpening our image
|
||||
// Create a kernel that we will use to sharpen our image
|
||||
Mat kernel = (Mat_<float>(3,3) <<
|
||||
1, 1, 1,
|
||||
1, -8, 1,
|
||||
@ -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;
|
||||
|
||||
@ -70,12 +73,10 @@ int main()
|
||||
imshow( "New Sharped Image", imgResult );
|
||||
//! [sharp]
|
||||
|
||||
src = imgResult; // copy back
|
||||
|
||||
//! [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]
|
||||
@ -87,17 +88,17 @@ int main()
|
||||
|
||||
// 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]
|
||||
|
||||
//! [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]
|
||||
@ -113,23 +114,25 @@ 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<int>(i), Scalar::all(static_cast<int>(i)+1), -1);
|
||||
{
|
||||
drawContours(markers, contours, static_cast<int>(i), Scalar(static_cast<int>(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]
|
||||
|
||||
//! [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
|
||||
@ -138,9 +141,9 @@ int main()
|
||||
vector<Vec3b> 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,9 +158,9 @@ int main()
|
||||
{
|
||||
int index = markers.at<int>(i,j);
|
||||
if (index > 0 && index <= static_cast<int>(contours.size()))
|
||||
{
|
||||
dst.at<Vec3b>(i,j) = colors[index-1];
|
||||
else
|
||||
dst.at<Vec3b>(i,j) = Vec3b(0,0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,6 +168,6 @@ int main()
|
||||
imshow("Final Result", dst);
|
||||
//! [watershed]
|
||||
|
||||
waitKey(0);
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
|
@ -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
|
||||
@ -26,16 +25,12 @@ 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);
|
||||
|
||||
CommandLineParser parser( argc, argv, "{@input | ../data/HappyFish.jpg | input image}" );
|
||||
Mat src = imread( parser.get<String>( "@input" ) );
|
||||
if( src.empty() )
|
||||
{
|
||||
cerr << "No image supplied ..." << endl;
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
cout << "Usage: " << argv[0] << " <Input image>" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -45,14 +40,15 @@ int main( int argc, char** argv )
|
||||
|
||||
/// Create Window
|
||||
const char* source_window = "Source";
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,24 +56,23 @@ int main( int argc, char** argv )
|
||||
*/
|
||||
void thresh_callback(int, void* )
|
||||
{
|
||||
/// Detect edges using Canny
|
||||
Mat canny_output;
|
||||
Canny( src_gray, canny_output, thresh, thresh*2 );
|
||||
|
||||
/// Find contours
|
||||
vector<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
/// 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) );
|
||||
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() );
|
||||
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 );
|
||||
}
|
||||
|
@ -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
|
||||
@ -28,7 +27,7 @@ int main( int argc, char** argv )
|
||||
//! [setup]
|
||||
/// Load source image
|
||||
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
|
||||
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR );
|
||||
Mat src = imread( parser.get<String>( "@input" ) );
|
||||
if( src.empty() )
|
||||
{
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
@ -44,23 +43,18 @@ int main( int argc, char** argv )
|
||||
//! [createWindow]
|
||||
/// Create Window
|
||||
const char* source_window = "Source";
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window );
|
||||
imshow( source_window, src );
|
||||
//! [createWindow]
|
||||
|
||||
//![taskbar]
|
||||
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
//![taskbar]
|
||||
|
||||
//![callback00]
|
||||
//! [trackbar]
|
||||
const int max_thresh = 255;
|
||||
createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
|
||||
thresh_callback( 0, 0 );
|
||||
//![callback00]
|
||||
//! [trackbar]
|
||||
|
||||
//![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<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
//![threshold]
|
||||
/// Detect edges using Threshold
|
||||
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
|
||||
//![threshold]
|
||||
//! [Canny]
|
||||
/// Detect edges using Canny
|
||||
Mat canny_output;
|
||||
Canny( src_gray, canny_output, thresh, thresh*2 );
|
||||
//! [Canny]
|
||||
|
||||
//! [findContours]
|
||||
/// Find contours
|
||||
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
vector<vector<Point> > contours;
|
||||
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
|
||||
//! [findContours]
|
||||
|
||||
//! [allthework]
|
||||
/// Approximate contours to polygons + get bounding rects and circles
|
||||
vector<vector<Point> > contours_poly( contours.size() );
|
||||
vector<Rect> boundRect( contours.size() );
|
||||
vector<Point2f>center( contours.size() );
|
||||
vector<Point2f>centers( contours.size() );
|
||||
vector<float>radius( contours.size() );
|
||||
|
||||
//![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] );
|
||||
minEnclosingCircle( contours_poly[i], centers[i], radius[i] );
|
||||
}
|
||||
//! [allthework]
|
||||
|
||||
//! [zeroMat]
|
||||
/// Draw polygonal contour + bonding rects + circles
|
||||
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
|
||||
Mat drawing = Mat::zeros( canny_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, 255), rng.uniform(0,255), rng.uniform(0,255) );
|
||||
drawContours( drawing, contours_poly, (int)i, color, 1, 8, vector<Vec4i>(), 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 );
|
||||
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]
|
||||
|
||||
//! [showDrawings]
|
||||
/// Show in a window
|
||||
namedWindow( "Contours", WINDOW_AUTOSIZE );
|
||||
imshow( "Contours", drawing );
|
||||
//! [showDrawings]
|
||||
}
|
||||
|
@ -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
|
||||
@ -27,7 +26,7 @@ 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<String>( "@input" ), IMREAD_COLOR );
|
||||
Mat src = imread( parser.get<String>( "@input" ) );
|
||||
if( src.empty() )
|
||||
{
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
@ -41,14 +40,15 @@ int main( int argc, char** argv )
|
||||
|
||||
/// Create Window
|
||||
const char* source_window = "Source";
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
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<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
/// Detect edges using Threshold
|
||||
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
|
||||
/// Detect edges using Canny
|
||||
Mat canny_output;
|
||||
Canny( src_gray, canny_output, thresh, thresh*2 );
|
||||
/// Find contours
|
||||
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
vector<vector<Point> > contours;
|
||||
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
|
||||
/// Find the rotated rectangles and ellipses for each contour
|
||||
vector<RotatedRect> minRect( contours.size() );
|
||||
vector<RotatedRect> minEllipse( contours.size() );
|
||||
|
||||
for( size_t i = 0; i < contours.size(); i++ )
|
||||
{ minRect[i] = minAreaRect( contours[i] );
|
||||
{
|
||||
minRect[i] = minAreaRect( contours[i] );
|
||||
if( contours[i].size() > 5 )
|
||||
{ minEllipse[i] = fitEllipse( contours[i] ); }
|
||||
{
|
||||
minEllipse[i] = fitEllipse( contours[i] );
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw contours + rotated rects + ellipses
|
||||
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
|
||||
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) );
|
||||
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
|
||||
// contour
|
||||
drawContours( drawing, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
|
||||
drawContours( drawing, contours, (int)i, color );
|
||||
// ellipse
|
||||
ellipse( drawing, minEllipse[i], color, 2, 8 );
|
||||
ellipse( drawing, minEllipse[i], color, 2 );
|
||||
// rotated rectangle
|
||||
Point2f rect_points[4]; minRect[i].points( rect_points );
|
||||
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 );
|
||||
{
|
||||
line( drawing, rect_points[j], rect_points[(j+1)%4], color );
|
||||
}
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Contours", WINDOW_AUTOSIZE );
|
||||
imshow( "Contours", drawing );
|
||||
}
|
||||
|
@ -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
|
||||
@ -27,7 +26,7 @@ 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<String>( "@input" ), IMREAD_COLOR );
|
||||
Mat src = imread( parser.get<String>( "@input" ) );
|
||||
if( src.empty() )
|
||||
{
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
@ -41,14 +40,15 @@ int main( int argc, char** argv )
|
||||
|
||||
/// Create Window
|
||||
const char* source_window = "Source";
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
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<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
/// Detect edges using Threshold
|
||||
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
|
||||
/// Detect edges using Canny
|
||||
Mat canny_output;
|
||||
Canny( src_gray, canny_output, thresh, thresh*2 );
|
||||
|
||||
/// Find contours
|
||||
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
vector<vector<Point> > contours;
|
||||
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
|
||||
|
||||
/// Find the convex hull object for each contour
|
||||
vector<vector<Point> >hull( contours.size() );
|
||||
for( size_t i = 0; i < contours.size(); i++ )
|
||||
{ convexHull( contours[i], hull[i], false ); }
|
||||
{
|
||||
convexHull( contours[i], hull[i] );
|
||||
}
|
||||
|
||||
/// Draw contours + hull results
|
||||
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
|
||||
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, 1, 8, vector<Vec4i>(), 0, Point() );
|
||||
drawContours( drawing, hull, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
|
||||
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 );
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Hull demo", WINDOW_AUTOSIZE );
|
||||
imshow( "Hull demo", drawing );
|
||||
}
|
||||
|
@ -8,13 +8,13 @@
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
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,15 +25,15 @@ void thresh_callback(int, void* );
|
||||
*/
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/// Load source image and convert it to gray
|
||||
/// Load source image
|
||||
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
|
||||
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR );
|
||||
Mat src = imread( parser.get<String>( "@input" ) );
|
||||
|
||||
if( src.empty() )
|
||||
{
|
||||
cout << "Could not open or find the image!\n" << endl;
|
||||
cout << "usage: " << argv[0] << " <Input image>" << endl;
|
||||
exit(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Convert image to gray and blur it
|
||||
@ -42,14 +42,15 @@ int main( int argc, char** argv )
|
||||
|
||||
/// Create Window
|
||||
const char* source_window = "Source";
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
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<vector<Point> > contours;
|
||||
|
||||
/// Detect edges using canny
|
||||
Mat canny_output;
|
||||
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
|
||||
/// Find contours
|
||||
vector<vector<Point> > contours;
|
||||
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
|
||||
|
||||
/// Get the moments
|
||||
vector<Moments> mu(contours.size() );
|
||||
for( size_t i = 0; i < contours.size(); i++ )
|
||||
{ mu[i] = moments( contours[i], false ); }
|
||||
{
|
||||
mu[i] = moments( contours[i] );
|
||||
}
|
||||
|
||||
/// Get the mass centers:
|
||||
/// Get the mass centers
|
||||
vector<Point2f> mc( contours.size() );
|
||||
for( size_t i = 0; i < contours.size(); i++ )
|
||||
{ mc[i] = Point2f( static_cast<float>(mu[i].m10/mu[i].m00) , static_cast<float>(mu[i].m01/mu[i].m00) ); }
|
||||
{
|
||||
//add 1e-5 to avoid division by zero
|
||||
mc[i] = Point2f( static_cast<float>(mu[i].m10 / (mu[i].m00 + 1e-5)),
|
||||
static_cast<float>(mu[i].m01 / (mu[i].m00 + 1e-5)) );
|
||||
cout << "mc[" << i << "]=" << mc[i] << endl;
|
||||
}
|
||||
|
||||
/// 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 );
|
||||
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 );
|
||||
}
|
||||
|
||||
/// 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");
|
||||
cout << "\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 );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,10 @@ int main( void )
|
||||
{
|
||||
/// Create an image
|
||||
const int r = 100;
|
||||
Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8UC1 );
|
||||
Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U );
|
||||
|
||||
/// Create a sequence of points to make a contour:
|
||||
/// Create a sequence of points to make a contour
|
||||
vector<Point2f> vert(6);
|
||||
|
||||
vert[0] = Point( 3*r/2, static_cast<int>(1.34*r) );
|
||||
vert[1] = Point( 1*r, 2*r );
|
||||
vert[2] = Point( 3*r/2, static_cast<int>(2.866*r) );
|
||||
@ -31,38 +30,50 @@ int main( void )
|
||||
vert[5] = Point( 5*r/2, static_cast<int>(1.34*r) );
|
||||
|
||||
/// Draw it in src
|
||||
for( int j = 0; j < 6; j++ )
|
||||
{ line( src, vert[j], vert[(j+1)%6], Scalar( 255 ), 3, 8 ); }
|
||||
for( int i = 0; i < 6; i++ )
|
||||
{
|
||||
line( src, vert[i], vert[(i+1)%6], Scalar( 255 ), 3 );
|
||||
}
|
||||
|
||||
/// Get the contours
|
||||
vector<vector<Point> > contours;
|
||||
|
||||
findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
|
||||
|
||||
/// 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<float>(j,i) = (float)pointPolygonTest( contours[0], Point2f((float)i,(float)j), true ); }
|
||||
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<float>(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true );
|
||||
}
|
||||
}
|
||||
|
||||
double minVal; double maxVal;
|
||||
minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() );
|
||||
minVal = abs(minVal); maxVal = abs(maxVal);
|
||||
double minVal, maxVal;
|
||||
minMaxLoc( raw_dist, &minVal, &maxVal );
|
||||
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++ )
|
||||
for( int i = 0; i < src.rows; i++ )
|
||||
{
|
||||
if( raw_dist.at<float>(j,i) < 0 )
|
||||
{ drawing.at<Vec3b>(j,i)[0] = (uchar)(255 - abs(raw_dist.at<float>(j,i))*255/minVal); }
|
||||
else if( raw_dist.at<float>(j,i) > 0 )
|
||||
{ drawing.at<Vec3b>(j,i)[2] = (uchar)(255 - raw_dist.at<float>(j,i)*255/maxVal); }
|
||||
for( int j = 0; j < src.cols; j++ )
|
||||
{
|
||||
if( raw_dist.at<float>(i,j) < 0 )
|
||||
{
|
||||
drawing.at<Vec3b>(i,j)[0] = (uchar)(255 - abs(raw_dist.at<float>(i,j)) * 255 / minVal);
|
||||
}
|
||||
else if( raw_dist.at<float>(i,j) > 0 )
|
||||
{
|
||||
drawing.at<Vec3b>(i,j)[2] = (uchar)(255 - raw_dist.at<float>(i,j) * 255 / maxVal);
|
||||
}
|
||||
else
|
||||
{ drawing.at<Vec3b>(j,i)[0] = 255; drawing.at<Vec3b>(j,i)[1] = 255; drawing.at<Vec3b>(j,i)[2] = 255; }
|
||||
{
|
||||
drawing.at<Vec3b>(i,j)[0] = 255;
|
||||
drawing.at<Vec3b>(i,j)[1] = 255;
|
||||
drawing.at<Vec3b>(i,j)[2] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +81,6 @@ int main( void )
|
||||
imshow( "Source", src );
|
||||
imshow( "Distance", drawing );
|
||||
|
||||
waitKey(0);
|
||||
return(0);
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
|
@ -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<String>("@homography"), FileStorage::READ);
|
||||
fs.getFirstTopLevelNode() >> homography;
|
||||
//! [load]
|
||||
|
||||
//! [AKAZE]
|
||||
vector<KeyPoint> kpts1, kpts2;
|
||||
Mat desc1, desc2;
|
||||
|
||||
Ptr<AKAZE> 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<DMatch> > nn_matches;
|
||||
matcher.knnMatch(desc1, desc2, nn_matches, 2);
|
||||
//! [2-nn matching]
|
||||
|
||||
vector<KeyPoint> matched1, matched2, inliers1, inliers2;
|
||||
vector<DMatch> good_matches;
|
||||
//! [ratio test filtering]
|
||||
vector<KeyPoint> 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<DMatch> good_matches;
|
||||
vector<KeyPoint> inliers1, inliers2;
|
||||
for(size_t i = 0; i < matched1.size(); i++) {
|
||||
Mat col = Mat::ones(3, 1, CV_64F);
|
||||
col.at<double>(0) = matched1[i].pt.x;
|
||||
col.at<double>(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;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ int main( int argc, char* argv[] )
|
||||
std::vector<DMatch> 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]);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ int main( int argc, char* argv[] )
|
||||
std::vector<DMatch> 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]);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
80
samples/data/dnn/object_detection_classes_yolov3.txt
Normal file
80
samples/data/dnn/object_detection_classes_yolov3.txt
Normal file
@ -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
|
@ -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<std::string> classes;
|
||||
|
||||
void postprocess(Mat& frame, const std::vector<Mat>& out, Net& net);
|
||||
@ -59,6 +60,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
confThreshold = parser.get<float>("thr");
|
||||
nmsThreshold = parser.get<float>("nms");
|
||||
float scale = parser.get<float>("scale");
|
||||
Scalar mean = parser.get<Scalar>("mean");
|
||||
bool swapRB = parser.get<bool>("rgb");
|
||||
@ -144,6 +146,9 @@ void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net)
|
||||
static std::vector<int> outLayers = net.getUnconnectedOutLayers();
|
||||
static std::string outLayerType = net.getLayer(outLayers[0])->type;
|
||||
|
||||
std::vector<int> classIds;
|
||||
std::vector<float> confidences;
|
||||
std::vector<Rect> 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<Mat>& 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<Mat>& 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<int> classIds;
|
||||
std::vector<float> confidences;
|
||||
std::vector<Rect> 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,8 +226,12 @@ void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
CV_Error(Error::StsNotImplemented, "Unknown output layer type: " + outLayerType);
|
||||
|
||||
std::vector<int> indices;
|
||||
NMSBoxes(boxes, confidences, confThreshold, 0.4f, indices);
|
||||
NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
|
||||
for (size_t i = 0; i < indices.size(); ++i)
|
||||
{
|
||||
int idx = indices[i];
|
||||
@ -228,9 +240,6 @@ void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net)
|
||||
box.x + box.width, box.y + box.height, frame);
|
||||
}
|
||||
}
|
||||
else
|
||||
CV_Error(Error::StsNotImplemented, "Unknown output layer type: " + outLayerType);
|
||||
}
|
||||
|
||||
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)
|
||||
{
|
||||
|
@ -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,12 +88,14 @@ 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 out in outs:
|
||||
for detection in out[0, 0]:
|
||||
confidence = detection[2]
|
||||
if confidence > confThreshold:
|
||||
@ -99,14 +103,16 @@ def postprocess(frame, outs):
|
||||
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)
|
||||
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 out in outs:
|
||||
for detection in out[0, 0]:
|
||||
confidence = detection[2]
|
||||
if confidence > confThreshold:
|
||||
@ -114,8 +120,11 @@ def postprocess(frame, outs):
|
||||
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)
|
||||
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,7 +147,11 @@ 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)
|
||||
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]
|
||||
|
@ -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<MatOfPoint> 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<Scalar> 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);
|
||||
}
|
||||
}
|
@ -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<MatOfPoint> 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<MatOfPoint> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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<MatOfPoint> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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<MatOfPoint> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
154
samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java
Normal file
154
samples/java/tutorial_code/ShapeDescriptors/hull/HullDemo.java
Normal file
@ -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<MatOfPoint> 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<MatOfPoint> 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<Integer> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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<MatOfPoint> contours = new ArrayList<>();
|
||||
Mat hierarchy = new Mat();
|
||||
Imgproc.findContours(cannyOutput, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
|
||||
//! [findContours]
|
||||
|
||||
/// Get the moments
|
||||
List<Moments> 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<Point> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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<Point> 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<MatOfPoint> 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();
|
||||
}
|
||||
|
||||
}
|
@ -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<MatOfDMatch> knnMatches = new ArrayList<>();
|
||||
matcher.knnMatch(desc1, desc2, knnMatches, 2);
|
||||
//! [2-nn matching]
|
||||
|
||||
//! [ratio test filtering]
|
||||
float ratioThreshold = 0.8f; // Nearest neighbor matching ratio
|
||||
List<KeyPoint> listOfMatched1 = new ArrayList<>();
|
||||
List<KeyPoint> listOfMatched2 = new ArrayList<>();
|
||||
List<KeyPoint> listOfKeypoints1 = kpts1.toList();
|
||||
List<KeyPoint> 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<KeyPoint> listOfInliers1 = new ArrayList<>();
|
||||
List<KeyPoint> listOfInliers2 = new ArrayList<>();
|
||||
List<DMatch> 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);
|
||||
}
|
||||
}
|
@ -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<DMatch> 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]);
|
||||
}
|
||||
}
|
||||
|
@ -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<DMatch> 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]);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
|
||||
#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__
|
||||
|
@ -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()
|
@ -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()
|
@ -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()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user