OpenCV 3.4.2

This commit is contained in:
Alexander Alekhin 2018-07-04 14:05:47 +03:00
commit 9e1b1e5389
107 changed files with 7390 additions and 2477 deletions

View File

@ -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__); \
} \

View File

@ -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)

View File

@ -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)

View File

@ -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})

View File

@ -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})

View File

@ -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})

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -4,32 +4,34 @@ Camera Calibration {#tutorial_py_calibration}
Goal
----
In this section,
- We will learn about distortions in camera, intrinsic and extrinsic parameters of camera etc.
- We will learn to find these parameters, undistort images etc.
In this section, we will learn about
* types of distortion caused by cameras
* how to find the intrinsic and extrinsic properties of a camera
* how to undistort images based off these properties
Basics
------
Today's cheap pinhole cameras introduces a lot of distortion to images. Two major distortions are
Some pinhole cameras introduce significant distortion to images. Two major kinds of distortion are
radial distortion and tangential distortion.
Due to radial distortion, straight lines will appear curved. Its effect is more as we move away from
the center of image. For example, one image is shown below, where two edges of a chess board are
marked with red lines. But you can see that border is not a straight line and doesn't match with the
Radial distortion causes straight lines to appear curved. Radial distortion becomes larger the farther points are from
the center of the image. For example, one image is shown below in which two edges of a chess board are
marked with red lines. But, you can see that the border of the chess board is not a straight line and doesn't match with the
red line. All the expected straight lines are bulged out. Visit [Distortion
(optics)](http://en.wikipedia.org/wiki/Distortion_%28optics%29) for more details.
![image](images/calib_radial.jpg)
This distortion is represented as follows:
Radial distortion can be represented as follows:
\f[x_{distorted} = x( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \\
y_{distorted} = y( 1 + k_1 r^2 + k_2 r^4 + k_3 r^6)\f]
Similarly, another distortion is the tangential distortion which occurs because image taking lense
is not aligned perfectly parallel to the imaging plane. So some areas in image may look nearer than
expected. It is represented as below:
Similarly, tangential distortion occurs because the image-taking lense
is not aligned perfectly parallel to the imaging plane. So, some areas in the image may look nearer than
expected. The amount of tangential distortion can be represented as below:
\f[x_{distorted} = x + [ 2p_1xy + p_2(r^2+2x^2)] \\
y_{distorted} = y + [ p_1(r^2+ 2y^2)+ 2p_2xy]\f]
@ -38,10 +40,9 @@ In short, we need to find five parameters, known as distortion coefficients give
\f[Distortion \; coefficients=(k_1 \hspace{10pt} k_2 \hspace{10pt} p_1 \hspace{10pt} p_2 \hspace{10pt} k_3)\f]
In addition to this, we need to find a few more information, like intrinsic and extrinsic parameters
of a camera. Intrinsic parameters are specific to a camera. It includes information like focal
length (\f$f_x,f_y\f$), optical centers (\f$c_x, c_y\f$) etc. It is also called camera matrix. It depends on
the camera only, so once calculated, it can be stored for future purposes. It is expressed as a 3x3
In addition to this, we need to some other information, like the intrinsic and extrinsic parameters
of the camera. Intrinsic parameters are specific to a camera. They include information like focal
length (\f$f_x,f_y\f$) and optical centers (\f$c_x, c_y\f$). The focal length and optical centers can be used to create a camera matrix, which can be used to remove distortion due to the lenses of a specific camera. The camera matrix is unique to a specific camera, so once calculated, it can be reused on other images taken by the same camera. It is expressed as a 3x3
matrix:
\f[camera \; matrix = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ]\f]
@ -49,20 +50,16 @@ matrix:
Extrinsic parameters corresponds to rotation and translation vectors which translates a coordinates
of a 3D point to a coordinate system.
For stereo applications, these distortions need to be corrected first. To find all these parameters,
what we have to do is to provide some sample images of a well defined pattern (eg, chess board). We
find some specific points in it ( square corners in chess board). We know its coordinates in real
world space and we know its coordinates in image. With these data, some mathematical problem is
solved in background to get the distortion coefficients. That is the summary of the whole story. For
better results, we need atleast 10 test patterns.
For stereo applications, these distortions need to be corrected first. To find these parameters,
we must provide some sample images of a well defined pattern (e.g. a chess board). We
find some specific points of which we already know the relative positions (e.g. square corners in the chess board). We know the coordinates of these points in real world space and we know the coordinates in the image, so we can solve for the distortion coefficients. For better results, we need at least 10 test patterns.
Code
----
As mentioned above, we need atleast 10 test patterns for camera calibration. OpenCV comes with some
images of chess board (see samples/cpp/left01.jpg -- left14.jpg), so we will utilize it. For sake of
understanding, consider just one image of a chess board. Important input datas needed for camera
calibration is a set of 3D real world points and its corresponding 2D image points. 2D image points
As mentioned above, we need at least 10 test patterns for camera calibration. OpenCV comes with some
images of a chess board (see samples/data/left01.jpg -- left14.jpg), so we will utilize these. Consider an image of a chess board. The important input data needed for calibration of the camera
is the set of 3D real world points and the corresponding 2D coordinates of these points in the image. 2D image points
are OK which we can easily find from the image. (These image points are locations where two black
squares touch each other in chess boards)
@ -72,7 +69,7 @@ values. But for simplicity, we can say chess board was kept stationary at XY pla
and camera was moved accordingly. This consideration helps us to find only X,Y values. Now for X,Y
values, we can simply pass the points as (0,0), (1,0), (2,0), ... which denotes the location of
points. In this case, the results we get will be in the scale of size of chess board square. But if
we know the square size, (say 30 mm), and we can pass the values as (0,0),(30,0),(60,0),..., we get
we know the square size, (say 30 mm), we can pass the values as (0,0), (30,0), (60,0), ... . Thus, we get
the results in mm. (In this case, we don't know square size since we didn't take those images, so we
pass in terms of square size).
@ -80,23 +77,22 @@ pass in terms of square size).
### Setup
So to find pattern in chess board, we use the function, **cv.findChessboardCorners()**. We also
need to pass what kind of pattern we are looking, like 8x8 grid, 5x5 grid etc. In this example, we
So to find pattern in chess board, we can use the function, **cv.findChessboardCorners()**. We also
need to pass what kind of pattern we are looking for, like 8x8 grid, 5x5 grid etc. In this example, we
use 7x6 grid. (Normally a chess board has 8x8 squares and 7x7 internal corners). It returns the
corner points and retval which will be True if pattern is obtained. These corners will be placed in
an order (from left-to-right, top-to-bottom)
@sa This function may not be able to find the required pattern in all the images. So one good option
@sa This function may not be able to find the required pattern in all the images. So, one good option
is to write the code such that, it starts the camera and check each frame for required pattern. Once
pattern is obtained, find the corners and store it in a list. Also provides some interval before
the pattern is obtained, find the corners and store it in a list. Also, provide some interval before
reading next frame so that we can adjust our chess board in different direction. Continue this
process until required number of good patterns are obtained. Even in the example provided here, we
are not sure out of 14 images given, how many are good. So we read all the images and take the good
process until the required number of good patterns are obtained. Even in the example provided here, we
are not sure how many images out of the 14 given are good. Thus, we must read all the images and take only the good
ones.
@sa Instead of chess board, we can use some circular grid, but then use the function
**cv.findCirclesGrid()** to find the pattern. It is said that less number of images are enough when
using circular grid.
@sa Instead of chess board, we can alternatively use a circular grid. In this case, we must use the function
**cv.findCirclesGrid()** to find the pattern. Fewer images are sufficient to perform camera calibration using a circular grid.
Once we find the corners, we can increase their accuracy using **cv.cornerSubPix()**. We can also
draw the pattern using **cv.drawChessboardCorners()**. All these steps are included in below code:
@ -146,22 +142,23 @@ One image with pattern drawn on it is shown below:
### Calibration
So now we have our object points and image points we are ready to go for calibration. For that we
use the function, **cv.calibrateCamera()**. It returns the camera matrix, distortion coefficients,
Now that we have our object points and image points, we are ready to go for calibration. We can
use the function, **cv.calibrateCamera()** which returns the camera matrix, distortion coefficients,
rotation and translation vectors etc.
@code{.py}
ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
@endcode
### Undistortion
We have got what we were trying. Now we can take an image and undistort it. OpenCV comes with two
methods, we will see both. But before that, we can refine the camera matrix based on a free scaling
Now, we can take an image and undistort it. OpenCV comes with two
methods for doing this. However first, we can refine the camera matrix based on a free scaling
parameter using **cv.getOptimalNewCameraMatrix()**. If the scaling parameter alpha=0, it returns
undistorted image with minimum unwanted pixels. So it may even remove some pixels at image corners.
If alpha=1, all pixels are retained with some extra black images. It also returns an image ROI which
If alpha=1, all pixels are retained with some extra black images. This function also returns an image ROI which
can be used to crop the result.
So we take a new image (left12.jpg in this case. That is the first image in this chapter)
So, we take a new image (left12.jpg in this case. That is the first image in this chapter)
@code{.py}
img = cv.imread('left12.jpg')
h, w = img.shape[:2]
@ -169,7 +166,7 @@ newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
@endcode
#### 1. Using **cv.undistort()**
This is the shortest path. Just call the function and use ROI obtained above to crop the result.
This is the easiest way. Just call the function and use ROI obtained above to crop the result.
@code{.py}
# undistort
dst = cv.undistort(img, mtx, dist, None, newcameramtx)
@ -181,7 +178,7 @@ cv.imwrite('calibresult.png', dst)
@endcode
#### 2. Using **remapping**
This is curved path. First find a mapping function from distorted image to undistorted image. Then
This way is a little bit more difficult. First, find a mapping function from the distorted image to the undistorted image. Then
use the remap function.
@code{.py}
# undistort
@ -193,23 +190,22 @@ x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
cv.imwrite('calibresult.png', dst)
@endcode
Both the methods give the same result. See the result below:
Still, both the methods give the same result. See the result below:
![image](images/calib_result.jpg)
You can see in the result that all the edges are straight.
Now you can store the camera matrix and distortion coefficients using write functions in Numpy
Now you can store the camera matrix and distortion coefficients using write functions in NumPy
(np.savez, np.savetxt etc) for future uses.
Re-projection Error
-------------------
Re-projection error gives a good estimation of just how exact is the found parameters. This should
be as close to zero as possible. Given the intrinsic, distortion, rotation and translation matrices,
we first transform the object point to image point using **cv.projectPoints()**. Then we calculate
Re-projection error gives a good estimation of just how exact the found parameters are. The closer the re-projection error is to zero, the more accurate the parameters we found are. Given the intrinsic, distortion, rotation and translation matrices,
we must first transform the object point to image point using **cv.projectPoints()**. Then, we can calculate
the absolute norm between what we got with our transformation and the corner finding algorithm. To
find the average error we calculate the arithmetical mean of the errors calculate for all the
find the average error, we calculate the arithmetical mean of the errors calculated for all the
calibration images.
@code{.py}
mean_error = 0

View File

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

View File

@ -7,8 +7,7 @@ Introduction
In this tutorial we will learn how to use AKAZE @cite ANB13 local features to detect and match keypoints on
two images.
We will find keypoints on a pair of images with given homography matrix, match them and count the
number of inliers (i. e. matches that fit in the given homography).
number of inliers (i.e. matches that fit in the given homography).
You can find expanded version of this example here:
<https://github.com/pablofdezalc/test_kaze_akaze_opencv>
@ -16,7 +15,7 @@ You can find expanded version of this example here:
Data
----
We are going to use images 1 and 3 from *Graffity* sequence of Oxford dataset.
We are going to use images 1 and 3 from *Graffiti* sequence of [Oxford dataset](http://www.robots.ox.ac.uk/~vgg/data/data-aff.html).
![](images/graf.png)
@ -27,107 +26,148 @@ Homography is given by a 3 by 3 matrix:
3.4663091e-04 -1.4364524e-05 1.0000000e+00
@endcode
You can find the images (*graf1.png*, *graf3.png*) and homography (*H1to3p.xml*) in
*opencv/samples/cpp*.
*opencv/samples/data/*.
### Source Code
@include cpp/tutorial_code/features2D/AKAZE_match.cpp
@add_toggle_cpp
- **Downloadable code**: Click
[here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/cpp/tutorial_code/features2D/AKAZE_match.cpp)
- **Code at glance:**
@include samples/cpp/tutorial_code/features2D/AKAZE_match.cpp
@end_toggle
@add_toggle_java
- **Downloadable code**: Click
[here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java)
- **Code at glance:**
@include samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java
@end_toggle
@add_toggle_python
- **Downloadable code**: Click
[here](https://raw.githubusercontent.com/opencv/opencv/3.4/samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py)
- **Code at glance:**
@include samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py
@end_toggle
### Explanation
-# **Load images and homography**
@code{.cpp}
Mat img1 = imread("graf1.png", IMREAD_GRAYSCALE);
Mat img2 = imread("graf3.png", IMREAD_GRAYSCALE);
- **Load images and homography**
Mat homography;
FileStorage fs("H1to3p.xml", FileStorage::READ);
fs.getFirstTopLevelNode() >> homography;
@endcode
We are loading grayscale images here. Homography is stored in the xml created with FileStorage.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp load
@end_toggle
-# **Detect keypoints and compute descriptors using AKAZE**
@code{.cpp}
vector<KeyPoint> kpts1, kpts2;
Mat desc1, desc2;
@add_toggle_java
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java load
@end_toggle
AKAZE akaze;
akaze(img1, noArray(), kpts1, desc1);
akaze(img2, noArray(), kpts2, desc2);
@endcode
We create AKAZE object and use it's *operator()* functionality. Since we don't need the *mask*
parameter, *noArray()* is used.
@add_toggle_python
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py load
@end_toggle
-# **Use brute-force matcher to find 2-nn matches**
@code{.cpp}
BFMatcher matcher(NORM_HAMMING);
vector< vector<DMatch> > nn_matches;
matcher.knnMatch(desc1, desc2, nn_matches, 2);
@endcode
We use Hamming distance, because AKAZE uses binary descriptor by default.
We are loading grayscale images here. Homography is stored in the xml created with FileStorage.
-# **Use 2-nn matches to find correct keypoint matches**
@code{.cpp}
for(size_t i = 0; i < nn_matches.size(); i++) {
DMatch first = nn_matches[i][0];
float dist1 = nn_matches[i][0].distance;
float dist2 = nn_matches[i][1].distance;
- **Detect keypoints and compute descriptors using AKAZE**
if(dist1 < nn_match_ratio * dist2) {
matched1.push_back(kpts1[first.queryIdx]);
matched2.push_back(kpts2[first.trainIdx]);
}
}
@endcode
If the closest match is *ratio* closer than the second closest one, then the match is correct.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp AKAZE
@end_toggle
-# **Check if our matches fit in the homography model**
@code{.cpp}
for(int i = 0; i < matched1.size(); i++) {
Mat col = Mat::ones(3, 1, CV_64F);
col.at<double>(0) = matched1[i].pt.x;
col.at<double>(1) = matched1[i].pt.y;
@add_toggle_java
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java AKAZE
@end_toggle
col = homography * col;
col /= col.at<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));
@add_toggle_python
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py AKAZE
@end_toggle
if(dist < inlier_threshold) {
int new_i = inliers1.size();
inliers1.push_back(matched1[i]);
inliers2.push_back(matched2[i]);
good_matches.push_back(DMatch(new_i, new_i, 0));
}
}
@endcode
If the distance from first keypoint's projection to the second keypoint is less than threshold,
then it it fits in the homography.
We create AKAZE and detect and compute AKAZE keypoints and descriptors. Since we don't need the *mask*
parameter, *noArray()* is used.
We create a new set of matches for the inliers, because it is required by the drawing function.
- **Use brute-force matcher to find 2-nn matches**
-# **Output results**
@code{.cpp}
Mat res;
drawMatches(img1, inliers1, img2, inliers2, good_matches, res);
imwrite("res.png", res);
...
@endcode
Here we save the resulting image and print some statistics.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp 2-nn matching
@end_toggle
### Results
@add_toggle_java
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java 2-nn matching
@end_toggle
Found matches
-------------
@add_toggle_python
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py 2-nn matching
@end_toggle
We use Hamming distance, because AKAZE uses binary descriptor by default.
- **Use 2-nn matches and ratio criterion to find correct keypoint matches**
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp ratio test filtering
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java ratio test filtering
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py ratio test filtering
@end_toggle
If the closest match distance is significantly lower than the second closest one, then the match is correct (match is not ambiguous).
- **Check if our matches fit in the homography model**
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp homography check
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java homography check
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py homography check
@end_toggle
If the distance from first keypoint's projection to the second keypoint is less than threshold,
then it fits the homography model.
We create a new set of matches for the inliers, because it is required by the drawing function.
- **Output results**
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/features2D/AKAZE_match.cpp draw final matches
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/features2D/akaze_matching/AKAZEMatchDemo.java draw final matches
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/features2D/akaze_matching/AKAZE_match.py draw final matches
@end_toggle
Here we save the resulting image and print some statistics.
Results
-------
### Found matches
![](images/res.png)
A-KAZE Matching Results
-----------------------
Depending on your OpenCV version, you should get results coherent with:
@code{.none}
Keypoints 1: 2943
Keypoints 2: 3511
Matches: 447
Inliers: 308
Inlier Ratio: 0.689038}
Inlier Ratio: 0.689038
@endcode

View File

@ -98,6 +98,8 @@ OpenCV.
- @subpage tutorial_akaze_matching
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 3.0
*Author:* Fedor Morozov

View File

@ -16,42 +16,152 @@ Theory
Code
----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp).
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp).
@include samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java)
@include samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py)
@include samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py
@end_toggle
Explanation / Result
--------------------
-# Load the source image and check if it is loaded without any problem, then show it:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image
![](images/source.jpeg)
- Load the source image and check if it is loaded without any problem, then show it:
-# Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg
![](images/black_bg.jpeg)
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image
@end_toggle
-# Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative):
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp
![](images/laplace.jpeg)
![](images/sharp.jpeg)
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java load_image
@end_toggle
-# Now we transform our new sharpened source image to a grayscale and a binary one, respectively:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin
![](images/bin.jpeg)
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py load_image
@end_toggle
-# We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist
![](images/dist_transf.jpeg)
![](images/source.jpeg)
-# We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks
![](images/peaks.jpeg)
- Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform:
-# From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds
![](images/markers.jpeg)
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg
@end_toggle
-# Finally, we can apply the watershed algorithm, and visualize the result:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed
![](images/final.jpeg)
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java black_bg
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py black_bg
@end_toggle
![](images/black_bg.jpeg)
- Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative):
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java sharp
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py sharp
@end_toggle
![](images/laplace.jpeg)
![](images/sharp.jpeg)
- Now we transform our new sharpened source image to a grayscale and a binary one, respectively:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java bin
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py bin
@end_toggle
![](images/bin.jpeg)
- We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java dist
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py dist
@end_toggle
![](images/dist_transf.jpeg)
- We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java peaks
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py peaks
@end_toggle
![](images/peaks.jpeg)
- From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java seeds
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py seeds
@end_toggle
![](images/markers.jpeg)
- Finally, we can apply the watershed algorithm, and visualize the result:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java watershed
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py watershed
@end_toggle
![](images/final.jpeg)

View File

@ -15,55 +15,167 @@ Theory
Code
----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp)
@include samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java)
@include samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py)
@include samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py
@end_toggle
Explanation
-----------
The main function is rather simple, as follows from the comments we do the following:
-# Open the image, convert it into grayscale and blur it to get rid of the noise.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp setup
-# Create a window with header "Source" and display the source file in it.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp createWindow
-# Create a trackbar on the source_window and assign a callback function to it
- Open the image, convert it into grayscale and blur it to get rid of the noise.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp setup
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java setup
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py setup
@end_toggle
- Create a window with header "Source" and display the source file in it.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp createWindow
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java createWindow
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py createWindow
@end_toggle
- Create a trackbar on the `source_window` and assign a callback function to it.
In general callback functions are used to react to some kind of signal, in our
case it's trackbar's state change.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp taskbar
-# Explicit one-time call of `thresh_callback` is necessary to display
Explicit one-time call of `thresh_callback` is necessary to display
the "Contours" window simultaniously with the "Source" window.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp callback00
-# Wait for user to close the windows.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp waitForIt
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp trackbar
@end_toggle
The callback function `thresh_callback` does all the interesting job.
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java trackbar
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py trackbar
@end_toggle
-# Writes to `threshold_output` the threshold of the grayscale picture (you can check out about thresholding @ref tutorial_threshold "here").
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp threshold
-# Finds contours and saves them to the vectors `contour` and `hierarchy`.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp findContours
-# For every found contour we now apply approximation to polygons
with accuracy +-3 and stating that the curve must me closed.
The callback function does all the interesting job.
- Use @ref cv::Canny to detect edges in the images.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp Canny
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java Canny
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py Canny
@end_toggle
- Finds contours and saves them to the vectors `contour` and `hierarchy`.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp findContours
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java findContours
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py findContours
@end_toggle
- For every found contour we now apply approximation to polygons
with accuracy +-3 and stating that the curve must be closed.
After that we find a bounding rect for every polygon and save it to `boundRect`.
At last we find a minimum enclosing circle for every polygon and
save it to `center` and `radius` vectors.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp allthework
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp allthework
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java allthework
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py allthework
@end_toggle
We found everything we need, all we have to do is to draw.
-# Create new Mat of unsigned 8-bit chars, filled with zeros.
- Create new Mat of unsigned 8-bit chars, filled with zeros.
It will contain all the drawings we are going to make (rects and circles).
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp zeroMat
-# For every contour: pick a random color, draw the contour, the bounding rectangle and
the minimal enclosing circle with it,
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp forContour
-# Display the results: create a new window "Contours" and show everything we added to drawings on it.
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp showDrawings
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp zeroMat
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java zeroMat
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py zeroMat
@end_toggle
- For every contour: pick a random color, draw the contour, the bounding rectangle and
the minimal enclosing circle with it.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp forContour
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java forContour
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py forContour
@end_toggle
- Display the results: create a new window "Contours" and show everything we added to drawings on it.
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp showDrawings
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ShapeDescriptors/bounding_rects_circles/GeneralContoursDemo1.java showDrawings
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ShapeDescriptors/bounding_rects_circles/generalContours_demo1.py showDrawings
@end_toggle
Result
------

View File

@ -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
-----------

View File

@ -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
-----------

View File

@ -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
-----------

View File

@ -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
-----------

View File

@ -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
-----------

View File

@ -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

View File

@ -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

View File

@ -1,50 +1,51 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// This is a homography decomposition implementation contributed to OpenCV
// by Samson Yilma. It implements the homography decomposition algorithm
// described in the research report:
// Malis, E and Vargas, M, "Deeper understanding of the homography decomposition
// for vision-based control", Research Report 6303, INRIA (2007)
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2014, Samson Yilma (samson_yilma@yahoo.com), all rights reserved.
//
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
//
// This is a homography decomposition implementation contributed to OpenCV
// by Samson Yilma. It implements the homography decomposition algorithm
// described in the research report:
// Malis, E and Vargas, M, "Deeper understanding of the homography decomposition
// for vision-based control", Research Report 6303, INRIA (2007)
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2014, Samson Yilma (samson_yilma@yahoo.com), all rights reserved.
// Copyright (C) 2018, Intel Corporation, all rights reserved.
//
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#include <memory>
@ -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

View 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(); }
}}

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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()

View File

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

View File

@ -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),

View File

@ -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", "");

View File

@ -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 &params)
{
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)

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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"

View File

@ -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);

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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

View 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

View File

@ -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

View File

@ -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;
};

View File

@ -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_y = (output_block_height -1) * stride_h_ + kernel_h_ * dilation_h_;
int tile_y_stride = (4 * simd_size) / tile_x;
int invec_size = divUp(tile_y, tile_y_stride);
int tile_x = (output_block_width - 1) * stride_w_ + kernel_w_ * dilation_w_;
int tile_y = (output_block_height - 1) * stride_h_ + kernel_h_ * dilation_h_;
int invec_size = tile_y;
addDef("SIMD_SIZE", simd_size);
addDef("filter_qualifier", "__global");
addDef("OUT_BLOCK_WIDTH", output_block_width);
addDef("OUT_BLOCK_HEIGHT", output_block_height);
addDef("LAST_BLOCK_WIDTH", last_block_width);
addDef("LAST_BLOCK_HEIGHT", last_block_height);
addDef("INPUT_DEPTH", channels_ / group_);
addDef("TOTAL_INPUT_DEPTH_SIZE", channels_);
addDef("TOTAL_OUTPUT_DEPTH", num_output_);
addDef("NUM_FILTERS", M_);
addDef("TILE_X", tile_x);
addDef("TILE_Y", tile_y);
addDef("TILE_Y_STRIDE", tile_y_stride);
addDef("INVEC_SIZE", invec_size);
addDef("ALIGNED_NUM_FILTERS", (int)alignSize(M_, simd_size));
addDef("OUT_BLOCK_SIZE", (output_block_width*output_block_height));
addDef("APPLY_BIAS", bias_term_);
addDef("WEIGHT_PREF", ((kernel_w_ * kernel_h_) == 1) ? 1 : 8);
addDef("INPUT_PITCH", (width_ * height_));
addDef("OUTPUT_PITCH", (output_w_ * output_h_));
addDef("LEFT_FILTERS", ((int)alignSize(M_, simd_size) - M_));
addDef("INPUT_WIDTH", width_);
addDef("INPUT_HEIGHT", height_);
addDef("FILTERS_IN_GROUP", ((int)alignSize(M_, simd_size) / simd_size));
setFusionDefine(fused_activ_, fused_eltwise_);
src_ = cv::ocl::dnn::conv_layer_spatial_oclsrc;
@ -528,13 +589,6 @@ void OCL4DNNConvSpatial<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,35 +1683,31 @@ 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]: "
<< kernelQueue[x]->workItem_output[0] << " "
<< "kernelQueue[x]->workItem_output[1]: "
<< kernelQueue[x]->workItem_output[1] << " "
<< "kernelQueue[x]->workItem_output[2]: "
<< kernelQueue[x]->workItem_output[2] << " "
<< "kernelQueue[x]->kernelType: "
<< kernelQueue[x]->kernelType << " "
<< "kernelQueue[x]->global_work_size[0]: "
<< kernelQueue[x]->global_work_size[0] << " "
<< "kernelQueue[x]->global_work_size[1]: "
<< kernelQueue[x]->global_work_size[1] << " "
<< "kernelQueue[x]->global_work_size[2]: "
<< kernelQueue[x]->global_work_size[2] << " "
<< "kernelQueue[x]->local_work_size[0]: "
<< kernelQueue[x]->local_work_size[0] << " "
<< "kernelQueue[x]->local_work_size[1]: "
<< kernelQueue[x]->local_work_size[1] << " "
<< "kernelQueue[x]->local_work_size[2]: "
<< kernelQueue[x]->local_work_size[2] << " "
<< kernelQueue[x]->swizzle_weights << " "
<< kernelQueue[x]->use_null_local << std::endl);
CV_LOG_ERROR(NULL, "Kernel " << kernelQueue[x]->kernelName << " failed verification");
CV_LOG_ERROR(NULL, "kernelQueue[x]->workItem_output[0]: "
<< kernelQueue[x]->workItem_output[0] << " "
<< "kernelQueue[x]->workItem_output[1]: "
<< kernelQueue[x]->workItem_output[1] << " "
<< "kernelQueue[x]->workItem_output[2]: "
<< kernelQueue[x]->workItem_output[2] << " "
<< "kernelQueue[x]->kernelType: "
<< kernelQueue[x]->kernelType << " "
<< "kernelQueue[x]->global_work_size[0]: "
<< kernelQueue[x]->global_work_size[0] << " "
<< "kernelQueue[x]->global_work_size[1]: "
<< kernelQueue[x]->global_work_size[1] << " "
<< "kernelQueue[x]->global_work_size[2]: "
<< kernelQueue[x]->global_work_size[2] << " "
<< "kernelQueue[x]->local_work_size[0]: "
<< kernelQueue[x]->local_work_size[0] << " "
<< "kernelQueue[x]->local_work_size[1]: "
<< kernelQueue[x]->local_work_size[1] << " "
<< "kernelQueue[x]->local_work_size[2]: "
<< kernelQueue[x]->local_work_size[2] << " "
<< kernelQueue[x]->swizzle_weights << " "
<< kernelQueue[x]->use_null_local);
} else {
dbgPrint(std::cout << "Kernel "
<< kernelQueue[x]->kernelName
<< " pass verification" << std::endl);
CV_LOG_INFO(NULL, "Kernel " << kernelQueue[x]->kernelName << " pass verification");
}
}
#endif
@ -1718,19 +1736,28 @@ void OCL4DNNConvSpatial<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;
@ -1798,14 +1825,14 @@ void OCL4DNNConvSpatial<Dtype>::prepareKernel(const UMat &bottom, UMat &top,
if (loadCachedConfig()) // check in-memory cache
return;
if (loadTunedConfig()) // check external storage
if (loadTunedConfig()) // check external storage
return;
UMat benchData(1, numImages * top_dim_, (use_half_) ? CV_16SC1 : CV_32FC1);
calculateBenchmark(bottom, benchData, (use_half_) ? weights_half : weight, bias, numImages);
if (force_auto_tuning_)
if (run_auto_tuning_ || force_auto_tuning_)
{
setupConvolution(bottom, top, weight, bias, numImages, benchData);
}
@ -1820,18 +1847,8 @@ template<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_)

View File

@ -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())

View File

@ -206,8 +206,6 @@ __kernel void ConvolveBasic(
#elif defined KERNEL_IDLF
#define VLOAD4(_v, _p) do { _v = vload4(0, _p); } while(0)
// Each work-item computes a OUT_BLOCK_WIDTH * OUT_BLOCK_HEIGHT region of one output map.
// Each work-group (which will be mapped to 1 SIMD16/SIMD8 EU thread) will compute 16/8 different feature maps, but each feature map is for the same region of the input image.
// NDRange: (output_width+pad)/ OUT_BLOCK_WIDTH, (output_height+pad)/OUT_BLOCK_HEIGHT, NUM_FILTERS/OUT_BLOCK_DEPTH
@ -219,190 +217,123 @@ __kernel void
convolve_simd(
ELTWISE_DATA_ARG
FUSED_ARG
__global Dtype* inputs_base,
filter_qualifier Dtype* weights_base,
__global Dtype* inputs,
__global Dtype* weights,
BIAS_KERNEL_ARG
__global Dtype* outputs_base,
__global Dtype* outputs,
const ushort input_width,
const ushort input_height,
const ushort output_width,
const ushort output_height)
{
__global Dtype* outputs = outputs_base;
__global Dtype* inputs = inputs_base;
filter_qualifier Dtype* weights = weights_base;
unsigned int oc = get_global_id(0) * OUT_BLOCK_WIDTH; // oc = Output Column
unsigned int or = get_global_id(1) * OUT_BLOCK_HEIGHT;// or = Output Row
unsigned int fm = get_global_id(2);// fm = Feature Map = od = Output Depth
unsigned int or = get_global_id(1) * OUT_BLOCK_HEIGHT; // or = Output Row
unsigned int fm = get_global_id(2); // fm = Feature Map = od = Output Depth
unsigned int fmg = get_group_id(2);
unsigned int lid = get_local_id(2);
Dtype out[OUT_BLOCK_WIDTH * OUT_BLOCK_HEIGHT];
int in_addr;
Dtype out[OUT_BLOCK_WIDTH * OUT_BLOCK_HEIGHT] = { 0.0f };
// find weights address of given neuron (lid is index)
unsigned int weight_addr = (fmg % (ALIGNED_NUM_FILTERS/SIMD_SIZE)) * INPUT_DEPTH * KERNEL_WIDTH * KERNEL_HEIGHT * SIMD_SIZE + lid;
unsigned int weight_addr = (fmg % FILTERS_IN_GROUP) *
INPUT_DEPTH * KERNEL_WIDTH * KERNEL_HEIGHT * SIMD_SIZE + lid;
for(int i=0;i<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
+ curr_x - INPUT_PAD_W; // x tile offset
union {
Dtype4 in_vec[INVEC_SIZE];
Dtype in_array[INVEC_SIZE * 4];
} in_buf;
int in_addr = input_batch_offset
+ (curr_y - INPUT_PAD_H) * INPUT_WIDTH // y tile offset
+ curr_x - INPUT_PAD_W; // x tile offset
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,
{
if (curr_local_y + reg * TILE_Y_STRIDE < TILE_Y || INVEC_SIZE * TILE_Y_STRIDE <= (TILE_Y + 2) || reg < INVEC_SIZE - 1) {
__attribute__((opencl_unroll_hint(INVEC_SIZE)))
for (int reg = 0; reg < INVEC_SIZE; reg++)
{
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;
}
} else {
in_buf.in_vec[reg] = 0;
if (!(curr_y >= INPUT_PAD_H && curr_y < INPUT_HEIGHT + INPUT_PAD_H &&
curr_x >= INPUT_PAD_W && curr_x < INPUT_WIDTH + INPUT_PAD_W))
{
in_buf[reg] = 0;
}
curr_y += TILE_Y_STRIDE;
#else
VLOAD4(in_buf.in_vec[reg], inputs + in_offset);
#endif
}
in_offset += input_width * TILE_Y_STRIDE;
});
in_addr += input_height * input_width;
curr_y += 1;
in_offset += INPUT_WIDTH;
}
in_addr += INPUT_PITCH;
#if INPUT_PAD_W != 0 || INPUT_PAD_H != 0 || INPUT_PAD_BOTTOM != 0 || INPUT_PAD_RIGHT != 0
curr_y = saved_y;
#endif
#if KERNEL_WIDTH * KERNEL_HEIGHT != 1
#define WEIGHT_PREF 8
#else
#define WEIGHT_PREF 1
#endif
union {
Dtype w[WEIGHT_PREF];
#if KERNEL_WIDTH * KERNEL_HEIGHT != 1
INT_TYPE8 ui8;
#endif
} weight_buf;
Dtype weight_buf[WEIGHT_PREF];
int w_idx=0;
unsigned int orig_weight_addr = weight_addr;
#if KERNEL_WIDTH * KERNEL_HEIGHT != 1
weight_buf.ui8 = SUB_GROUP_BLOCK_READ8((__global INT_TYPE *)&weights[weight_addr]);
weight_addr += SIMD_SIZE * WEIGHT_PREF;
#else
weight_buf.w[0] = as_Dtype(SUB_GROUP_BLOCK_READ((__global INT_TYPE *)&weights[weight_addr]));
weight_addr += SIMD_SIZE * 1;
#endif
for (int i = 0; i < WEIGHT_PREF; i++)
{
weight_buf[i] = weights[weight_addr];
weight_addr += SIMD_SIZE;
}
#define BLOCK_IN(n) sub_group_broadcast( in_buf.in_array[((n)%4) + ((n) / (TILE_Y_STRIDE * TILE_X)) * 4], (((n) % (TILE_Y_STRIDE * TILE_X))/4))
#define BLOCK_IN(n, c) intel_sub_group_shuffle(in_buf[n], (c))
int kr = 0; // kr = Kernel Row
LOOP(KERNEL_HEIGHT, kr,// LOOP is a macro that unrolls the loop.
{
int kc = 0; // kc = Kernel Column
LOOP(KERNEL_WIDTH, kc,
{
int kc = 0; // kc = Kernel Column
LOOP(KERNEL_WIDTH, kc,
{
for(int br=0; br < OUT_BLOCK_HEIGHT; br++) {
for(int bc=0; bc < OUT_BLOCK_WIDTH; bc++) {
Dtype input = BLOCK_IN((br * STRIDE_Y + kr * DILATION_Y) * TILE_X + bc * STRIDE_X + kc * DILATION_X);
out[br * OUT_BLOCK_WIDTH + bc] = mad(weight_buf.w[w_idx % WEIGHT_PREF], input, out[br * OUT_BLOCK_WIDTH + bc]);
}
for (int br=0; br < OUT_BLOCK_HEIGHT; br++)
{
for(int bc=0; bc < OUT_BLOCK_WIDTH; bc++)
{
Dtype input = BLOCK_IN((br * STRIDE_Y + kr * DILATION_Y), bc * STRIDE_X + kc * DILATION_X);
out[br * OUT_BLOCK_WIDTH + bc] = mad(weight_buf[w_idx % WEIGHT_PREF], input, out[br * OUT_BLOCK_WIDTH + bc]);
}
#if KERNEL_WIDTH * KERNEL_HEIGHT > WEIGHT_PREF
// We assume KERNEL_W is equal to KERNEL_H here.
if ((w_idx + 1) % WEIGHT_PREF == 0
#if KERNEL_WIDTH * KERNEL_HEIGHT % 8 != 0
&& ((w_idx + 1) <= (KERNEL_WIDTH * KERNEL_HEIGHT - WEIGHT_PREF))
#endif
) {
weight_buf.ui8 = SUB_GROUP_BLOCK_READ8((__global INT_TYPE *)&weights[weight_addr]);
weight_addr += SIMD_SIZE * WEIGHT_PREF; // weights must be stored in just the right SIMD swizzled format for this to work, see host code for details.
}
#if KERNEL_WIDTH*KERNEL_HEIGHT % 8 == 0
// need to do nothing
#else
else if ((w_idx + 1) % WEIGHT_PREF == 0 && ((w_idx + 1) > (KERNEL_WIDTH * KERNEL_HEIGHT - WEIGHT_PREF)))
#if KERNEL_WIDTH * KERNEL_HEIGHT % 8 == 1
weight_buf.w[0] = weights[weight_addr];
#elif KERNEL_WIDTH * KERNEL_HEIGHT % 8 == 2
weight_buf.ui8.s01 = SUB_GROUP_BLOCK_READ2((__global INT_TYPE *)&weights[weight_addr]);
#elif KERNEL_WIDTH * KERNEL_HEIGHT % 8 <= 4
weight_buf.ui8.s0123 = SUB_GROUP_BLOCK_READ4((__global INT_TYPE *)&weights[weight_addr]);
#else
weight_buf.ui8 = SUB_GROUP_BLOCK_READ8((__global INT_TYPE *)&weights[weight_addr]);
#endif
#endif
#endif
++w_idx;
});
}
weight_buf[w_idx % WEIGHT_PREF] = weights[weight_addr];
weight_addr += SIMD_SIZE;
++w_idx;
});
weight_addr = orig_weight_addr + KERNEL_WIDTH * KERNEL_HEIGHT * SIMD_SIZE;
});
weight_addr -= WEIGHT_PREF * SIMD_SIZE;
}
}
// dead code to work around possible compiler bug.
if (ALIGNED_NUM_FILTERS != NUM_FILTERS && fm > 0xfffffffeul) {
outputs[0] = BLOCK_IN(fm % SIMD_SIZE);
}
fm = fm % ALIGNED_NUM_FILTERS;
if ((ALIGNED_NUM_FILTERS == NUM_FILTERS || fm < NUM_FILTERS)) {
unsigned int out_addr = ( num_in_batch * TOTAL_OUTPUT_DEPTH + fm ) * output_width * output_height;
out_addr += or * output_width + oc;
// we need this address calculation for biases because we support views and batching
#if APPLY_BIAS
Dtype bias = biases_base[fm];
#else
Dtype bias = 0;
#if LEFT_FILTERS > 0
if (fm < NUM_FILTERS)
#endif
{
unsigned int out_addr = (num_in_batch * TOTAL_OUTPUT_DEPTH + fm) * OUTPUT_PITCH;
out_addr += or * output_width + oc;
// we need this address calculation for biases because we support views and batching
#if APPLY_BIAS
Dtype bias = biases_base[fm];
#else
Dtype bias = 0;
#endif
for(unsigned int r = 0; r < OUT_BLOCK_HEIGHT; r++) {
if (r + or >= output_height) break;
for(unsigned int c = 0; c < OUT_BLOCK_WIDTH; c++) {
if (c + oc >= output_width) break;
// this does a scattered write to SIMD_SIZE different feature maps, so that data within one map is contiguous, thus ready for input to next layer.
ACTIVATION_FUNCTION(outputs, out_addr + r * output_width + c, bias + out[r * OUT_BLOCK_WIDTH + c], fm);
for(unsigned int r = 0; r < OUT_BLOCK_HEIGHT; r++)
{
if (r + or >= output_height) break;
for(unsigned int c = 0; c < OUT_BLOCK_WIDTH; c++)
{
if (c + oc >= output_width) break;
// this does a scattered write to SIMD_SIZE different feature maps,
// so that data within one map is contiguous, thus ready for input to next layer.
ACTIVATION_FUNCTION(outputs, out_addr + r * output_width + c, bias + out[r * OUT_BLOCK_WIDTH + c], fm);
}
}
}

View File

@ -65,36 +65,40 @@ __kernel void
#endif
)
{
for (int index = get_global_id(0); index < nthreads;
index += get_global_size(0))
int index = get_global_id(0);
if (index >= nthreads)
return;
const int pw = index % pooled_width;
const int xx = index / pooled_width;
const int ph = xx % pooled_height;
const int ch = xx / pooled_height;
int hstart = ph * STRIDE_H - PAD_H;
int wstart = pw * STRIDE_W - PAD_W;
Dtype maxval = -FLT_MAX;
int maxidx = -1;
int in_offset = ch * height * width;
for (int h = 0; h < KERNEL_H; ++h)
{
const int pw = index % pooled_width;
const int ph = (index / pooled_width) % pooled_height;
const int c = (index / pooled_width / pooled_height) % channels;
const int n = index / pooled_width / pooled_height / channels;
int hstart = ph * STRIDE_H - PAD_H;
int wstart = pw * STRIDE_W - PAD_W;
const int hend = min(hstart + KERNEL_H, height);
const int wend = min(wstart + KERNEL_W, width);
hstart = max(hstart, (int)0);
wstart = max(wstart, (int)0);
Dtype maxval = -FLT_MAX;
int maxidx = -1;
__global const Dtype* bottom_slice = bottom_data
+ (n * channels + c) * height * width;
for (int h = hstart; h < hend; ++h) {
for (int w = wstart; w < wend; ++w) {
if (bottom_slice[h * width + w] > maxval) {
maxidx = h * width + w;
maxval = bottom_slice[maxidx];
int off_y = hstart + h;
if (off_y >= 0 && off_y < height)
{
for (int w = 0; w < KERNEL_W; ++w)
{
int off_x = wstart + w;
if (off_x >= 0 && off_x < width)
{
Dtype val = bottom_data[in_offset + off_y * width + off_x];
maxidx = (val > maxval) ? (off_y * width + off_x) : maxidx;
maxval = fmax(val, maxval);
}
}
}
top_data[index] = maxval;
#ifdef HAVE_MASK
mask[index] = maxidx;
#endif
}
top_data[index] = maxval;
#ifdef HAVE_MASK
mask[index] = maxidx;
#endif
}
#elif defined KERNEL_AVE_POOL
@ -105,43 +109,42 @@ __kernel void TEMPLATE(ave_pool_forward, Dtype)(
const int pooled_height, const int pooled_width,
__global Dtype* top_data)
{
for (int index = get_global_id(0); index < nthreads;
index += get_global_size(0))
{
{
const int pw = index % pooled_width;
const int ph = (index / pooled_width) % pooled_height;
const int c = (index / pooled_width / pooled_height) % channels;
const int n = index / pooled_width / pooled_height / channels;
int hstart = ph * STRIDE_H - PAD_H;
int wstart = pw * STRIDE_W - PAD_W;
int hend = min(hstart + KERNEL_H, height + PAD_H);
int wend = min(wstart + KERNEL_W, width + PAD_W);
int pool_size;
int index = get_global_id(0);
if (index >= nthreads)
return;
const int pw = index % pooled_width;
const int xx = index / pooled_width;
const int ph = xx % pooled_height;
const int ch = xx / pooled_height;
int hstart = ph * STRIDE_H - PAD_H;
int wstart = pw * STRIDE_W - PAD_W;
int hend = min(hstart + KERNEL_H, height + PAD_H);
int wend = min(wstart + KERNEL_W, width + PAD_W);
int pool_size;
#ifdef AVE_POOL_PADDING_AREA
pool_size = (hend - hstart) * (wend - wstart);
hstart = max(hstart, (int)0);
wstart = max(wstart, (int)0);
hend = min(hend, height);
wend = min(wend, width);
pool_size = (hend - hstart) * (wend - wstart);
hstart = max(hstart, (int)0);
wstart = max(wstart, (int)0);
hend = min(hend, height);
wend = min(wend, width);
#else
hstart = max(hstart, (int)0);
wstart = max(wstart, (int)0);
hend = min(hend, height);
wend = min(wend, width);
pool_size = (hend - hstart) * (wend - wstart);
hstart = max(hstart, (int)0);
wstart = max(wstart, (int)0);
hend = min(hend, height);
wend = min(wend, width);
pool_size = (hend - hstart) * (wend - wstart);
#endif
Dtype aveval = 0;
__global const Dtype* bottom_slice = bottom_data
+ (n * channels + c) * height * width;
for (int h = hstart; h < hend; ++h) {
for (int w = wstart; w < wend; ++w) {
aveval += bottom_slice[h * width + w];
}
}
top_data[index] = aveval / pool_size;
Dtype aveval = 0;
int in_offset = ch * height * width;
for (int h = hstart; h < hend; ++h)
{
for (int w = wstart; w < wend; ++w)
{
aveval += bottom_data[in_offset + h * width + w];
}
}
top_data[index] = aveval / pool_size;
}
#elif defined KERNEL_STO_POOL

View File

@ -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;
}
}
return layout;
if (layout != DATA_LAYOUT_UNKNOWN)
return layout;
// Determine layout by layer's consumers recursively.
it = data_layouts.find(layer.name());
CV_Assert(it != data_layouts.end());
return it->second;
}
void TFImporter::populateNet(Net dstNet)
@ -610,6 +667,52 @@ void TFImporter::populateNet(Net dstNet)
int layersSize = net.node_size();
std::map<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;
layer_id[name] = 0;
dstNet.setInputsNames(netInputs);
if (!hasLayerAttr(layer, "dtype") ||
getLayerAttr(layer, "dtype").type() != tensorflow::DT_BOOL) // If input is not a train/test flag.
{
netInputsNames.push_back(name);
layer_id[name] = 0;
}
}
else if (type == "Split") {
// TODO: determining axis index remapping by input dimensions order of input blob
@ -1094,7 +1207,7 @@ void TFImporter::populateNet(Net dstNet)
CV_Assert(!begins.empty(), !sizes.empty(), begins.type() == CV_32SC1,
sizes.type() == CV_32SC1);
if (begins.total() == 4 && data_layouts[name] == DATA_LAYOUT_NHWC)
if (begins.total() == 4 && getDataLayout(name, data_layouts) == DATA_LAYOUT_NHWC)
{
// Swap NHWC parameters' order to NCHW.
std::swap(*begins.ptr<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

View File

@ -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);
}

View File

@ -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),

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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 );
}
}

View File

@ -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
}

View 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;
}
}

View 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

View File

@ -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);

View File

@ -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);

View File

@ -250,7 +250,9 @@ when fullAffine=false.
@sa
estimateAffine2D, estimateAffinePartial2D, getAffineTransform, getPerspectiveTransform, findHomography
*/
CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine );
CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine);
CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine, int ransacMaxIters, double ransacGoodRatio,
int ransacSize0);
enum

View File

@ -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;

View File

@ -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

View File

@ -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)
void Release()
{
p.Attach(p2);
}
// Detach the interface (does not Release)
T* Detach()
{
return p.Detach();
}
_Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT)
{
assert(ppT != NULL);
if (ppT == NULL)
return E_POINTER;
*ppT = p;
if (p != NULL)
p->AddRef();
return S_OK;
}
void Reset()
{
p.Release();
if (p)
p.Release();
}
// query for U interface
template<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())
return capture;
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())
return capture;
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())
return writer;
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>();
}

View File

@ -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)
{
const char* deviceURI = openni::ANY_DEVICE;
openni::Status status;
int deviceType = DEVICE_DEFAULT;
noSampleValue = shadowValue = 0;
isContextOpened = false;
maxBufferSize = DEFAULT_MAX_BUFFER_SIZE;
isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER;
maxTimeDuration = DEFAULT_MAX_TIME_DURATION;
if( index >= 10 )
{
deviceType = index / 10;
index %= 10;
}
// Initialize and configure the context.
status = openni::OpenNI::initialize();
OpenNI2Initializer::init();
if (status != openni::STATUS_OK)
const char* deviceURI = openni::ANY_DEVICE;
bool needColor = true;
bool needIR = true;
if (index >= 0)
{
CV_Error(CV_StsError, cv::format("Failed to initialize:", openni::OpenNI::getExtendedError()));
return;
}
// find appropriate device URI
openni::Array<openni::DeviceInfo> ldevs;
if (index > 0)
{
openni::OpenNI::enumerateDevices(&ldevs);
deviceURI = ldevs[index].getUri();
int deviceType = DEVICE_DEFAULT;
if (index >= 10)
{
deviceType = index / 10;
index %= 10;
}
// Asus XTION and Occipital Structure Sensor do not have an image generator
needColor = (deviceType != DEVICE_ASUS_XTION);
// find appropriate device URI
openni::Array<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;
}
status = toggleStream(CV_DEPTH_STREAM, true);
// Asus XTION and Occipital Structure Sensor do not have an image generator
if (deviceType != DEVICE_ASUS_XTION)
status = openni::Status(status | toggleStream(CV_COLOR_STREAM, true));
if (status != openni::STATUS_OK)
{
openni::OpenNI::shutdown();
return;
CV_Error(CV_StsError, std::string("OpenCVKinect2: Failed to open device: ") + openni::OpenNI::getExtendedError());
}
if (!readCamerasParams())
{
CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n"));
return;
}
outputMaps.resize( outputMapsTypesCount );
isContextOpened = true;
toggleStream(CV_DEPTH_STREAM, true);
if (needColor)
toggleStream(CV_COLOR_STREAM, true);
if (needIR)
toggleStream(CV_IR_STREAM, true);
setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0);
// default for Kinect2 camera
setProperty(CV_CAP_PROP_OPENNI2_MIRROR, 0.0);
isContextOpened = true;
}
openni::Status CvCapture_OpenNI2::toggleStream(int stream, bool toggle)
CvCapture_OpenNI2::~CvCapture_OpenNI2()
{
for (size_t i = 0; i < streams.size(); ++i)
{
streamFrames[i].release();
streams[i].stop();
streams[i].destroy();
}
device.close();
}
void CvCapture_OpenNI2::toggleStream(int stream, bool toggle)
{
openni::Status status;
// for logging
static const char* stream_names[CV_MAX_NUM_STREAMS] = {
static const std::string stream_names[CV_MAX_NUM_STREAMS] = {
"depth",
"color",
"IR"
@ -280,140 +333,92 @@ openni::Status CvCapture_OpenNI2::toggleStream(int stream, bool toggle)
{
// already opened
if (streams[stream].isValid())
return openni::STATUS_OK;
return;
// open stream
status = streams[stream].create(device, stream_sensor_types[stream]);
if (status == openni::STATUS_OK)
{
// set video mode
status = streams[stream].setVideoMode(defaultStreamOutputMode(stream)); // xn::DepthGenerator supports VGA only! (Jan 2011)
if (status != openni::STATUS_OK)
// try to set up default stream mode (if available)
const openni::Array<openni::VideoMode>& vm = streams[stream].getSensorInfo().getSupportedVideoModes();
openni::VideoMode dm = defaultStreamOutputMode(stream);
for (int i = 0; i < vm.getSize(); i++)
{
CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't set %s stream output mode: %s\n",
stream_names[stream],
openni::OpenNI::getExtendedError()));
streams[stream].destroy();
return status;
if (vm[i].getPixelFormat() == dm.getPixelFormat() &&
vm[i].getResolutionX() == dm.getResolutionX() &&
vm[i].getResolutionY() == dm.getResolutionY() &&
vm[i].getFps() == dm.getFps())
{
status = streams[stream].setVideoMode(defaultStreamOutputMode(stream));
if (status != openni::STATUS_OK)
{
streams[stream].destroy();
CV_Error(CV_StsError, std::string("OpenCVKinect2 : Couldn't set ") +
stream_names[stream] + std::string(" stream output mode: ") +
std::string(openni::OpenNI::getExtendedError()));
}
}
}
// start stream
status = streams[stream].start();
if (status != openni::STATUS_OK)
{
CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start %s stream: %s\n",
stream_names[stream],
openni::OpenNI::getExtendedError()));
streams[stream].destroy();
return status;
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start ") +
stream_names[stream] + std::string(" stream: ") +
std::string(openni::OpenNI::getExtendedError()));
}
}
else
{
CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find %s stream:: %s\n",
stream_names[stream],
openni::OpenNI::getExtendedError()));
return status;
CV_Error(CV_StsError, std::string("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find ") +
stream_names[stream] + " stream: " +
std::string(openni::OpenNI::getExtendedError()));
}
}
else if (streams[stream].isValid()) // want to close stream
{
streams[stream].stop();
streams[stream].destroy();
}
//FIX for libfreenect2
//which stops the whole device when stopping only one stream
return openni::STATUS_OK;
//streams[stream].stop();
//streams[stream].destroy();
}
}
CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename)
{
openni::Status status;
isContextOpened = false;
maxBufferSize = DEFAULT_MAX_BUFFER_SIZE;
isCircleBuffer = DEFAULT_IS_CIRCLE_BUFFER;
maxTimeDuration = DEFAULT_MAX_TIME_DURATION;
// Initialize and configure the context.
status = openni::OpenNI::initialize();
if (status != openni::STATUS_OK)
{
CV_Error(CV_StsError, cv::format("Failed to initialize:", openni::OpenNI::getExtendedError()));
return;
}
// Open file
status = device.open(filename);
if( status != openni::STATUS_OK )
{
CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Failed to open input file (%s): %s\n", filename, openni::OpenNI::getExtendedError()));
return;
}
status = openni::Status(toggleStream(CV_DEPTH_STREAM, true) | toggleStream(CV_COLOR_STREAM, true));
if (status != openni::STATUS_OK)
{
openni::OpenNI::shutdown();
return;
}
if( !readCamerasParams() )
{
CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n"));
return;
}
outputMaps.resize( outputMapsTypesCount );
isContextOpened = true;
}
CvCapture_OpenNI2::~CvCapture_OpenNI2()
{
for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
{
streamFrames[i].release();
streams[i].stop();
streams[i].destroy();
}
device.close();
openni::OpenNI::shutdown();
}
bool CvCapture_OpenNI2::readCamerasParams()
void CvCapture_OpenNI2::readCamerasParams()
{
double pixelSize = 0;
if (streams[CV_DEPTH_STREAM].getProperty<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;
@ -525,14 +530,20 @@ bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )
// There is a set of properties that correspond to depth generator by default
// (is they are pass without particular generator flag).
case CV_CAP_PROP_OPENNI_REGISTRATION:
isSet = setDepthGeneratorProperty( propIdx, propValue );
isSet = setDepthGeneratorProperty(propIdx, propValue);
break;
case CV_CAP_PROP_OPENNI2_SYNC:
isSet = device.setDepthColorSyncEnabled(propValue > 0.0) == openni::STATUS_OK;
break;
case CV_CAP_PROP_FRAME_WIDTH:
case CV_CAP_PROP_FRAME_HEIGHT:
case CV_CAP_PROP_AUTOFOCUS:
isSet = false;
break;
default:
CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.\n", propIdx) );
CV_Error(CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.", propIdx));
}
return isSet;
@ -565,9 +576,13 @@ double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const
propValue = streams[CV_DEPTH_STREAM].getMaxPixelValue();
break;
case CV_CAP_PROP_OPENNI_BASELINE :
if(baseline <= 0)
const_cast<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,10 +959,12 @@ IplImage* CvCapture_OpenNI2::retrieveDisparityMap()
if (!streamFrames[CV_DEPTH_STREAM].isValid())
return 0;
readCamerasParams();
cv::Mat disp32;
computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
disp32.convertTo( outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1 );
disp32.convertTo(outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1);
return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].getIplImagePtr();
}
@ -944,6 +974,8 @@ IplImage* CvCapture_OpenNI2::retrieveDisparityMap_32F()
if (!streamFrames[CV_DEPTH_STREAM].isValid())
return 0;
readCamerasParams();
computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr();
@ -966,7 +998,7 @@ inline void getBGRImageFromMetaData( const openni::VideoFrameRef& imageMetaData,
{
cv::Mat bufferImage;
if( imageMetaData.getVideoMode().getPixelFormat() != openni::PIXEL_FORMAT_RGB888 )
CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n" );
CV_Error( CV_StsUnsupportedFormat, "Unsupported format of grabbed image." );
bgrImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3);
bufferImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC3);
@ -989,7 +1021,7 @@ inline void getGrayImageFromMetaData(const openni::VideoFrameRef& imageMetaData,
}
else
{
CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n");
CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image.");
}
}

View File

@ -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

View File

@ -4,444 +4,373 @@
#include "opencv2/highgui.hpp"
#include <string>
#include <iostream>
#include <map>
using namespace std;
using namespace cv;
class GStreamerPipeline
//================================================================================
template<typename M>
inline typename M::mapped_type getValue(const M &dict, const typename M::key_type &key, const string & errorMessage)
{
public:
// Preprocessing arguments command line
GStreamerPipeline(int argc, char *argv[])
typename M::const_iterator it = dict.find(key);
if (it == dict.end())
{
const string keys =
"{h help usage ? | | print help messages }"
"{m mode | | coding mode (supported: encode, decode) }"
"{p pipeline |default | pipeline name (supported: 'default', 'gst-basic', 'gst-vaapi', 'gst-libav', 'ffmpeg') }"
"{cd codec |h264 | codec name (supported: 'h264', 'h265', 'mpeg2', 'mpeg4', 'mjpeg', 'vp8') }"
"{f file path | | path to file }"
"{vr resolution |720p | video resolution for encoding (supported: '720p', '1080p', '4k') }"
"{fps |30 | fix frame per second for encoding (supported: fps > 0) }"
"{fm fast | | fast measure fps }";
cmd_parser = new CommandLineParser(argc, argv, keys);
cmd_parser->about("This program shows how to read a video file with GStreamer pipeline with OpenCV.");
if (cmd_parser->has("help"))
{
cmd_parser->printMessage();
CV_Error(Error::StsBadArg, "Called help.");
}
fast_measure = cmd_parser->has("fast"); // fast measure fps
fix_fps = cmd_parser->get<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
size_t found = file_name.rfind(".");
if (found != string::npos)
{
container = file_name.substr(found + 1); // container type
}
else { CV_Error(Error::StsBadArg, "Can not parse container extension."); }
if (!cmd_parser->check())
{
cmd_parser->printErrors();
CV_Error(Error::StsBadArg, "Failed parse arguments.");
}
CV_Error(Error::StsBadArg, errorMessage);
}
return it->second;
}
~GStreamerPipeline() { delete cmd_parser; }
inline map<string, Size> sizeByResolution()
{
map<string, Size> res;
res["720p"] = Size(1280, 720);
res["1080p"] = Size(1920, 1080);
res["4k"] = Size(3840, 2160);
return res;
}
// Start pipeline
int run()
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)
{
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;
return name.substr(found + 1); // container type
}
return string();
}
// Free video resource
void close()
//================================================================================
inline Ptr<VideoCapture> createCapture(const string &backend, const string &file_name, const string &codec)
{
if (backend == "gst-default")
{
cap.release();
wrt.release();
cout << "Created GStreamer capture ( " << file_name << " )" << endl;
return makePtr<VideoCapture>(file_name, CAP_GSTREAMER);
}
private:
// Choose the constructed GStreamer pipeline for decode
int createDecodePipeline()
else if (backend.find("gst") == 0)
{
if (pipeline == "default") {
cap = VideoCapture(file_name, CAP_GSTREAMER);
}
else if (pipeline.find("gst") == 0)
{
stream_pipeline << "filesrc location=\"" << file_name << "\"";
stream_pipeline << " ! " << getGstMuxPlugin();
if (pipeline.find("basic") == 4)
{
stream_pipeline << getGstDefaultCodePlugin();
}
else if (pipeline.find("vaapi1710") == 4)
{
stream_pipeline << getGstVaapiCodePlugin();
}
else if (pipeline.find("libav") == 4)
{
stream_pipeline << getGstAvCodePlugin();
}
else
{
cout << "Unsupported pipeline: " << pipeline << endl;
cmd_parser->printErrors();
return -1;
}
stream_pipeline << " ! videoconvert n-threads=" << getNumThreads();
stream_pipeline << " ! appsink sync=false";
cap = VideoCapture(stream_pipeline.str(), CAP_GSTREAMER);
}
else if (pipeline == "ffmpeg")
{
cap = VideoCapture(file_name, CAP_FFMPEG);
stream_pipeline << "default pipeline for ffmpeg" << endl;
}
ostringstream line;
line << "filesrc location=\"" << file_name << "\"";
line << " ! ";
line << getValue(demuxPluginByContainer(), containerByName(file_name), "Invalid container");
line << " ! ";
if (backend.find("basic") == 4)
line << "decodebin";
else if (backend.find("vaapi") == 4)
line << "vaapidecodebin";
else if (backend.find("libav") == 4)
line << getValue(libavDecodeElementByCodec(), codec, "Invalid codec");
else if (backend.find("mfx") == 4)
line << getValue(mfxDecodeElementByCodec(), codec, "Invalid or unsupported codec");
else
{
cout << "Unsupported pipeline: " << pipeline << endl;
cmd_parser->printErrors();
return -1;
}
return 0;
return Ptr<VideoCapture>();
line << " ! videoconvert n-threads=" << getNumThreads();
line << " ! appsink sync=false";
cout << "Created GStreamer capture ( " << line.str() << " )" << endl;
return makePtr<VideoCapture>(line.str(), CAP_GSTREAMER);
}
// Choose the constructed GStreamer pipeline for encode
int createEncodePipeline()
else if (backend == "ffmpeg")
{
if (checkConfiguration() < 0) return -1;
ostringstream test_pipeline;
test_pipeline << "videotestsrc pattern=smpte";
test_pipeline << " ! video/x-raw, " << getVideoSettings();
test_pipeline << " ! appsink sync=false";
cap = VideoCapture(test_pipeline.str(), CAP_GSTREAMER);
if (pipeline == "default") {
wrt = VideoWriter(file_name, CAP_GSTREAMER, getFourccCode(), fix_fps, fix_size, true);
}
else if (pipeline.find("gst") == 0)
{
stream_pipeline << "appsrc ! videoconvert n-threads=" << getNumThreads() << " ! ";
if (pipeline.find("basic") == 4)
{
stream_pipeline << getGstDefaultCodePlugin();
}
else if (pipeline.find("vaapi1710") == 4)
{
stream_pipeline << getGstVaapiCodePlugin();
}
else if (pipeline.find("libav") == 4)
{
stream_pipeline << getGstAvCodePlugin();
}
else
{
cout << "Unsupported pipeline: " << pipeline << endl;
cmd_parser->printErrors();
return -1;
}
stream_pipeline << " ! " << getGstMuxPlugin();
stream_pipeline << " ! filesink location=\"" << file_name << "\"";
wrt = VideoWriter(stream_pipeline.str(), CAP_GSTREAMER, 0, fix_fps, fix_size, true);
}
else if (pipeline == "ffmpeg")
{
wrt = VideoWriter(file_name, CAP_FFMPEG, getFourccCode(), fix_fps, fix_size, true);
stream_pipeline << "default pipeline for ffmpeg" << endl;
}
else
{
cout << "Unsupported pipeline: " << pipeline << endl;
cmd_parser->printErrors();
return -1;
}
return 0;
cout << "Created FFmpeg capture ( " << file_name << " )" << endl;
return makePtr<VideoCapture>(file_name, CAP_FFMPEG);
}
return Ptr<VideoCapture>();
}
// Choose video resolution for encoding
string getVideoSettings()
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);
}
inline Ptr<VideoWriter> createWriter(const string &backend, const string &file_name, const string &codec, Size sz, unsigned fps)
{
if (backend == "gst-default")
{
ostringstream video_size;
if (fix_fps > 0) { video_size << "framerate=" << fix_fps << "/1, "; }
else
{
cout << "Unsupported fps (< 0): " << fix_fps << endl;
cmd_parser->printErrors();
return string();
}
if (resolution == "720p") { fix_size = Size(1280, 720); }
else if (resolution == "1080p") { fix_size = Size(1920, 1080); }
else if (resolution == "4k") { fix_size = Size(3840, 2160); }
else
{
cout << "Unsupported video resolution: " << resolution << endl;
cmd_parser->printErrors();
return string();
}
video_size << "width=" << fix_size.width << ", height=" << fix_size.height;
return video_size.str();
cout << "Created GStreamer writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << ")" << endl;
return makePtr<VideoWriter>(file_name, CAP_GSTREAMER, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true);
}
// Choose a video container
string getGstMuxPlugin()
else if (backend.find("gst") == 0)
{
ostringstream plugin;
if (container == "avi") { plugin << "avi"; }
else if (container == "mp4") { plugin << "qt"; }
else if (container == "mov") { plugin << "qt"; }
else if (container == "mkv") { plugin << "matroska"; }
ostringstream line;
line << "appsrc ! videoconvert n-threads=" << getNumThreads() << " ! ";
if (backend.find("basic") == 4)
line << getValue(defaultEncodeElementByCodec(), codec, "Invalid codec");
else if (backend.find("vaapi") == 4)
line << getValue(VAAPIEncodeElementByCodec(), codec, "Invalid codec");
else if (backend.find("libav") == 4)
line << getValue(libavEncodeElementByCodec(), codec, "Invalid codec");
else if (backend.find("mfx") == 4)
line << getValue(mfxEncodeElementByCodec(), codec, "Invalid codec");
else
{
cout << "Unsupported container: " << container << endl;
cmd_parser->printErrors();
return string();
}
if (mode == "decode") { plugin << "demux"; }
else if (mode == "encode") { plugin << "mux"; }
else
{
cout << "Unsupported mode: " << mode << endl;
cmd_parser->printErrors();
return string();
}
return plugin.str();
return Ptr<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);
}
// Choose a libav codec
string getGstAvCodePlugin()
else if (backend == "ffmpeg")
{
ostringstream plugin;
if (mode == "decode")
{
if (codec == "h264") { plugin << "h264parse ! "; }
else if (codec == "h265") { plugin << "h265parse ! "; }
plugin << "avdec_";
}
else if (mode == "encode") { plugin << "avenc_"; }
else
{
cout << "Unsupported mode: " << mode << endl;
cmd_parser->printErrors();
return string();
}
if (codec == "h264") { plugin << "h264"; }
else if (codec == "h265") { plugin << "h265"; }
else if (codec == "mpeg2") { plugin << "mpeg2video"; }
else if (codec == "mpeg4") { plugin << "mpeg4"; }
else if (codec == "mjpeg") { plugin << "mjpeg"; }
else if (codec == "vp8") { plugin << "vp8"; }
else
{
cout << "Unsupported libav codec: " << codec << endl;
cmd_parser->printErrors();
return string();
}
return plugin.str();
cout << "Created FFMpeg writer ( " << file_name << ", FPS=" << fps << ", Size=" << sz << " )" << endl;
return makePtr<VideoWriter>(file_name, CAP_FFMPEG, getValue(fourccByCodec(), codec, "Invalid codec"), fps, sz, true);
}
return Ptr<VideoWriter>();
}
// 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();
if (mode == "decode")
{
cap = createCapture(backend, file_name, codec);
if (!cap)
{
cout << "Failed to create video capture" << endl;
return -3;
}
if (!cap->isOpened())
{
cout << "Capture is not opened" << endl;
return -4;
}
}
else if (mode == "encode")
{
Size sz = getValue(sizeByResolution(), resolution, "Invalid resolution");
cout << "FPS: " << fix_fps << ", Frame size: " << sz << endl;
cap = createSynthSource(sz, fix_fps);
wrt = createWriter(backend, file_name, codec, sz, fix_fps);
if (!cap || !wrt)
{
cout << "Failed to create synthetic video source or video writer" << endl;
return -3;
}
if (!cap->isOpened() || !wrt->isOpened())
{
cout << "Synthetic video source or video writer is not opened" << endl;
return -4;
}
}
}
catch(const Exception& e)
catch (...)
{
cerr << e.what() << endl;
return 1;
cout << "Unsupported parameters" << endl;
return -2;
}
TickMeter tick;
Mat frame;
Mat element;
total.start();
while(true)
{
if (mode == "decode")
{
tick.start();
if (!cap->grab())
{
cout << "No more frames - break" << endl;
break;
}
if (!cap->retrieve(frame))
{
cout << "Failed to retrieve frame - break" << endl;
break;
}
if (frame.empty())
{
cout << "Empty frame received - break" << endl;
break;
}
tick.stop();
}
else if (mode == "encode")
{
int limit = 100;
while (!cap->grab() && --limit != 0)
{
cout << "Skipping empty input frame - " << limit << endl;
}
cap->retrieve(element);
tick.start();
*wrt << element;
tick.stop();
}
if (fast_measure && tick.getCounter() >= 1000)
{
cout << "Fast mode frame limit reached - break" << endl;
break;
}
if (mode == "encode" && tick.getCounter() >= 1000)
{
cout << "Encode frame limit reached - break" << endl;
break;
}
}
total.stop();
if (tick.getCounter() == 0)
{
cout << "No frames have been processed" << endl;
return -10;
}
else
{
double res_fps = tick.getCounter() / tick.getTimeSec();
cout << tick.getCounter() << " frames in " << tick.getTimeSec() << " sec ~ " << res_fps << " FPS" << " (total time: " << total.getTimeSec() << " sec)" << endl;
}
return 0;
}

View File

@ -1,5 +1,4 @@
/**
* @function Watershed_and_Distance_Transform.cpp
* @brief Sample code showing how to segment overlapping objects using Laplacian filtering, in addition to Watershed and Distance Transformation
* @author OpenCV Team
*/
@ -12,43 +11,47 @@
using namespace std;
using namespace cv;
int main()
int main(int argc, char *argv[])
{
//! [load_image]
//! [load_image]
// Load the image
Mat src = imread("../data/cards.png");
// Check if everything was fine
if (!src.data)
CommandLineParser parser( argc, argv, "{@input | ../data/cards.png | input image}" );
Mat src = imread( parser.get<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);
//! [load_image]
//! [load_image]
//! [black_bg]
//! [black_bg]
// Change the background from white to black, since that will help later to extract
// better results during the use of Distance Transform
for( int x = 0; x < src.rows; x++ ) {
for( int y = 0; y < src.cols; y++ ) {
if ( src.at<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;
}
}
}
// Show output image
imshow("Black Background Image", src);
//! [black_bg]
//! [black_bg]
//! [sharp]
// Create a kernel that we will use for accuting/sharpening our image
//! [sharp]
// Create a kernel that we will use to sharpen our image
Mat kernel = (Mat_<float>(3,3) <<
1, 1, 1,
1, -8, 1,
1, 1, 1); // an approximation of second derivative, a quite strong kernel
1, 1, 1,
1, -8, 1,
1, 1, 1); // an approximation of second derivative, a quite strong kernel
// do the laplacian filtering as it is
// well, we need to convert everything in something more deeper then CV_8U
@ -57,8 +60,8 @@ int main()
// BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
// so the possible negative number will be truncated
Mat imgLaplacian;
Mat sharp = src; // copy source image to another temporary one
filter2D(sharp, imgLaplacian, CV_32F, kernel);
filter2D(src, imgLaplacian, CV_32F, kernel);
Mat sharp;
src.convertTo(sharp, CV_32F);
Mat imgResult = sharp - imgLaplacian;
@ -68,41 +71,39 @@ int main()
// imshow( "Laplace Filtered Image", imgLaplacian );
imshow( "New Sharped Image", imgResult );
//! [sharp]
//! [sharp]
src = imgResult; // copy back
//! [bin]
//! [bin]
// Create binary image from source image
Mat bw;
cvtColor(src, bw, COLOR_BGR2GRAY);
cvtColor(imgResult, bw, COLOR_BGR2GRAY);
threshold(bw, bw, 40, 255, THRESH_BINARY | THRESH_OTSU);
imshow("Binary Image", bw);
//! [bin]
//! [bin]
//! [dist]
//! [dist]
// Perform the distance transform algorithm
Mat dist;
distanceTransform(bw, dist, DIST_L2, 3);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist, dist, 0, 1., NORM_MINMAX);
normalize(dist, dist, 0, 1.0, NORM_MINMAX);
imshow("Distance Transform Image", dist);
//! [dist]
//! [dist]
//! [peaks]
//! [peaks]
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
threshold(dist, dist, .4, 1., THRESH_BINARY);
threshold(dist, dist, 0.4, 1.0, THRESH_BINARY);
// Dilate a bit the dist image
Mat kernel1 = Mat::ones(3, 3, CV_8UC1);
Mat kernel1 = Mat::ones(3, 3, CV_8U);
dilate(dist, dist, kernel1);
imshow("Peaks", dist);
//! [peaks]
//! [peaks]
//! [seeds]
//! [seeds]
// Create the CV_8U version of the distance image
// It is needed for findContours()
Mat dist_8u;
@ -113,34 +114,36 @@ int main()
findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist.size(), CV_32SC1);
Mat markers = Mat::zeros(dist.size(), CV_32S);
// Draw the foreground markers
for (size_t i = 0; i < contours.size(); i++)
drawContours(markers, contours, static_cast<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]
//! [seeds]
//! [watershed]
//! [watershed]
// Perform the watershed algorithm
watershed(src, markers);
watershed(imgResult, markers);
Mat mark = Mat::zeros(markers.size(), CV_8UC1);
markers.convertTo(mark, CV_8UC1);
Mat mark;
markers.convertTo(mark, CV_8U);
bitwise_not(mark, mark);
// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
// image looks like at that point
// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
// image looks like at that point
// Generate random colors
vector<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,16 +158,16 @@ 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);
}
}
}
// Visualize the final image
imshow("Final Result", dst);
//! [watershed]
//! [watershed]
waitKey(0);
waitKey();
return 0;
}

View File

@ -12,9 +12,8 @@
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
@ -25,34 +24,31 @@ void thresh_callback(int, void* );
*/
int main( int argc, char** argv )
{
/// Load source image
String imageName("../data/happyfish.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
src = imread(imageName, IMREAD_COLOR);
/// Load source image
CommandLineParser parser( argc, argv, "{@input | ../data/HappyFish.jpg | input image}" );
Mat src = imread( parser.get<String>( "@input" ) );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
if (src.empty())
{
cerr << "No image supplied ..." << endl;
return -1;
}
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window );
imshow( source_window, src );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window, WINDOW_AUTOSIZE );
imshow( source_window, src );
const int max_thresh = 255;
createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
waitKey();
return 0;
}
/**
@ -60,24 +56,23 @@ int main( int argc, char** argv )
*/
void thresh_callback(int, void* )
{
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Canny
Mat canny_output;
Canny( src_gray, canny_output, thresh, thresh*2 );
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE );
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, (int)i, color, 2, 8, hierarchy, 0, Point() );
}
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
drawContours( drawing, contours, (int)i, color, 2, LINE_8, hierarchy, 0 );
}
/// Show in a window
namedWindow( "Contours", WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
/// Show in a window
imshow( "Contours", drawing );
}

View File

@ -12,9 +12,8 @@
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
@ -25,42 +24,37 @@ void thresh_callback(int, void* );
*/
int main( int argc, char** argv )
{
//![setup]
/// Load source image
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR );
if( src.empty() )
//! [setup]
/// Load source image
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
Mat src = imread( parser.get<String>( "@input" ) );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "usage: " << argv[0] << " <Input image>" << endl;
return -1;
cout << "Could not open or find the image!\n" << endl;
cout << "usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
//![setup]
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
//! [setup]
//![createWindow]
/// Create Window
const char* source_window = "Source";
namedWindow( source_window, WINDOW_AUTOSIZE );
imshow( source_window, src );
//![createWindow]
//! [createWindow]
/// Create Window
const char* source_window = "Source";
namedWindow( source_window );
imshow( source_window, src );
//! [createWindow]
//![taskbar]
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
//![taskbar]
//! [trackbar]
const int max_thresh = 255;
createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
//! [trackbar]
//![callback00]
thresh_callback( 0, 0 );
//![callback00]
//![waitForIt]
waitKey(0);
//![waitForIt]
return(0);
waitKey();
return 0;
}
/**
@ -68,53 +62,50 @@ int main( int argc, char** argv )
*/
void thresh_callback(int, void* )
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
//! [Canny]
/// Detect edges using Canny
Mat canny_output;
Canny( src_gray, canny_output, thresh, thresh*2 );
//! [Canny]
//![threshold]
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
//![threshold]
//! [findContours]
/// Find contours
vector<vector<Point> > contours;
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
//! [findContours]
//![findContours]
/// Find contours
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
//![findContours]
//! [allthework]
/// Approximate contours to polygons + get bounding rects and circles
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>centers( contours.size() );
vector<float>radius( contours.size() );
/// 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<float>radius( contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{
approxPolyDP( contours[i], contours_poly[i], 3, true );
boundRect[i] = boundingRect( contours_poly[i] );
minEnclosingCircle( contours_poly[i], centers[i], radius[i] );
}
//! [allthework]
//![allthework]
for( size_t i = 0; i < contours.size(); i++ )
{
approxPolyDP( contours[i], contours_poly[i], 3, true );
boundRect[i] = boundingRect( contours_poly[i] );
minEnclosingCircle( contours_poly[i], center[i], radius[i] );
}
//![allthework]
//! [zeroMat]
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
//! [zeroMat]
//![zeroMat]
/// Draw polygonal contour + bonding rects + circles
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
//![zeroMat]
//! [forContour]
/// Draw polygonal contour + bonding rects + circles
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
drawContours( drawing, contours_poly, (int)i, color );
rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2 );
circle( drawing, centers[i], (int)radius[i], color, 2 );
}
//! [forContour]
//![forContour]
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours_poly, (int)i, color, 1, 8, vector<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 );
}
//![forContour]
//![showDrawings]
/// Show in a window
namedWindow( "Contours", WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
//![showDrawings]
//! [showDrawings]
/// Show in a window
imshow( "Contours", drawing );
//! [showDrawings]
}

View File

@ -12,9 +12,8 @@
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
@ -25,30 +24,31 @@ void thresh_callback(int, void* );
*/
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR );
if( src.empty() )
/// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
Mat src = imread( parser.get<String>( "@input" ) );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window, WINDOW_AUTOSIZE );
imshow( source_window, src );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window );
imshow( source_window, src );
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
const int max_thresh = 255;
createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
waitKey();
return 0;
}
/**
@ -56,41 +56,43 @@ int main( int argc, char** argv )
*/
void thresh_callback(int, void* )
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Canny
Mat canny_output;
Canny( src_gray, canny_output, thresh, thresh*2 );
/// Find contours
vector<vector<Point> > contours;
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
/// Find contours
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the rotated rectangles and ellipses for each contour
vector<RotatedRect> minRect( contours.size() );
vector<RotatedRect> minEllipse( contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{
minRect[i] = minAreaRect( contours[i] );
if( contours[i].size() > 5 )
{
minEllipse[i] = fitEllipse( contours[i] );
}
}
/// Find the rotated rectangles and ellipses for each contour
vector<RotatedRect> minRect( contours.size() );
vector<RotatedRect> minEllipse( contours.size() );
/// Draw contours + rotated rects + ellipses
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
// contour
drawContours( drawing, contours, (int)i, color );
// ellipse
ellipse( drawing, minEllipse[i], color, 2 );
// rotated rectangle
Point2f rect_points[4];
minRect[i].points( rect_points );
for ( int j = 0; j < 4; j++ )
{
line( drawing, rect_points[j], rect_points[(j+1)%4], color );
}
}
for( size_t i = 0; i < contours.size(); i++ )
{ minRect[i] = minAreaRect( contours[i] );
if( contours[i].size() > 5 )
{ minEllipse[i] = fitEllipse( contours[i] ); }
}
/// Draw contours + rotated rects + ellipses
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
// contour
drawContours( drawing, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
// ellipse
ellipse( drawing, minEllipse[i], color, 2, 8 );
// rotated rectangle
Point2f rect_points[4]; minRect[i].points( rect_points );
for( int j = 0; j < 4; j++ )
line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
}
/// Show in a window
namedWindow( "Contours", WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
/// Show in a window
imshow( "Contours", drawing );
}

View File

@ -12,9 +12,8 @@
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
@ -25,30 +24,31 @@ void thresh_callback(int, void* );
*/
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
Mat src = imread( parser.get<String>( "@input" ) );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window, WINDOW_AUTOSIZE );
imshow( source_window, src );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window );
imshow( source_window, src );
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
const int max_thresh = 255;
createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
waitKey();
return 0;
}
/**
@ -56,31 +56,30 @@ int main( int argc, char** argv )
*/
void thresh_callback(int, void* )
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Canny
Mat canny_output;
Canny( src_gray, canny_output, thresh, thresh*2 );
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
/// Find contours
vector<vector<Point> > contours;
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
/// Find contours
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the convex hull object for each contour
vector<vector<Point> >hull( contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{
convexHull( contours[i], hull[i] );
}
/// Find the convex hull object for each contour
vector<vector<Point> >hull( contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{ convexHull( contours[i], hull[i], false ); }
/// Draw contours + hull results
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
drawContours( drawing, contours, (int)i, color );
drawContours( drawing, hull, (int)i, color );
}
/// Draw contours + hull results
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
drawContours( drawing, hull, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
}
/// Show in a window
namedWindow( "Hull demo", WINDOW_AUTOSIZE );
imshow( "Hull demo", drawing );
/// Show in a window
imshow( "Hull demo", drawing );
}

View File

@ -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,31 +25,32 @@ void thresh_callback(int, void* );
*/
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | input image}" );
src = imread( parser.get<String>( "@input" ), IMREAD_COLOR );
/// Load source image
CommandLineParser parser( argc, argv, "{@input | ../data/stuff.jpg | 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;
exit(0);
}
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Convert image to gray and blur it
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window, WINDOW_AUTOSIZE );
imshow( source_window, src );
/// Create Window
const char* source_window = "Source";
namedWindow( source_window );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
const int max_thresh = 255;
createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
waitKey();
return 0;
}
/**
@ -57,44 +58,47 @@ int main( int argc, char** argv )
*/
void thresh_callback(int, void* )
{
Mat canny_output;
vector<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 );
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );
/// Get the moments
vector<Moments> mu(contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{
mu[i] = moments( contours[i] );
}
/// Get the moments
vector<Moments> mu(contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{ mu[i] = moments( contours[i], false ); }
/// Get the mass centers
vector<Point2f> mc( contours.size() );
for( size_t i = 0; i < contours.size(); i++ )
{
//add 1e-5 to avoid division by zero
mc[i] = Point2f( static_cast<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;
}
/// 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) ); }
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
drawContours( drawing, contours, (int)i, color, 2 );
circle( drawing, mc[i], 4, color, -1 );
}
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( size_t i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, (int)i, color, 2, LINE_8 );
circle( drawing, mc[i], 4, color, -1, 8, 0 );
}
/// Show in a window
imshow( "Contours", drawing );
/// Show in a window
namedWindow( "Contours", WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
/// Calculate the area with the moments 00 and compare with the result of the OpenCV function
printf("\t Info: Area and Contour Length \n");
for( size_t i = 0; i< contours.size(); i++ )
{
printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", (int)i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) );
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, (int)i, color, 2, LINE_8 );
circle( drawing, mc[i], 4, color, -1, 8, 0 );
}
/// Calculate the area with the moments 00 and compare with the result of the OpenCV function
cout << "\t Info: Area and Contour Length \n";
for( size_t i = 0; i < contours.size(); i++ )
{
cout << " * Contour[" << i << "] - Area (M_00) = " << std::fixed << std::setprecision(2) << mu[i].m00
<< " - Area OpenCV: " << contourArea(contours[i]) << " - Length: " << arcLength( contours[i], true ) << endl;
}
}

View File

@ -16,60 +16,71 @@ using namespace std;
*/
int main( void )
{
/// Create an image
const int r = 100;
Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8UC1 );
/// Create an image
const int r = 100;
Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U );
/// Create a sequence of points to make a contour:
vector<Point2f> vert(6);
/// 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) );
vert[3] = Point( 5*r/2, static_cast<int>(2.866*r) );
vert[4] = Point( 3*r, 2*r );
vert[5] = Point( 5*r/2, static_cast<int>(1.34*r) );
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) );
vert[3] = Point( 5*r/2, static_cast<int>(2.866*r) );
vert[4] = Point( 3*r, 2*r );
vert[5] = Point( 5*r/2, static_cast<int>(1.34*r) );
/// Draw it in src
for( int i = 0; i < 6; i++ )
{
line( src, vert[i], vert[(i+1)%6], Scalar( 255 ), 3 );
}
/// Draw it in src
for( int j = 0; j < 6; j++ )
{ line( src, vert[j], vert[(j+1)%6], Scalar( 255 ), 3, 8 ); }
/// Get the contours
vector<vector<Point> > contours;
findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
/// Get the contours
vector<vector<Point> > contours;
/// Calculate the distances to the contour
Mat raw_dist( src.size(), CV_32F );
for( int i = 0; i < src.rows; i++ )
{
for( int j = 0; j < src.cols; j++ )
{
raw_dist.at<float>(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true );
}
}
findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
double minVal, maxVal;
minMaxLoc( raw_dist, &minVal, &maxVal );
minVal = abs(minVal);
maxVal = abs(maxVal);
/// Calculate the distances to the contour
Mat raw_dist( src.size(), CV_32FC1 );
for( int j = 0; j < src.rows; j++ )
{ for( int i = 0; i < src.cols; i++ )
{ raw_dist.at<float>(j,i) = (float)pointPolygonTest( contours[0], Point2f((float)i,(float)j), true ); }
}
double minVal; double maxVal;
minMaxLoc( raw_dist, &minVal, &maxVal, 0, 0, Mat() );
minVal = abs(minVal); maxVal = abs(maxVal);
/// Depicting the distances graphically
Mat drawing = Mat::zeros( src.size(), CV_8UC3 );
for( int j = 0; j < src.rows; j++ )
{ for( int i = 0; i < src.cols; i++ )
{
if( raw_dist.at<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); }
/// Depicting the distances graphically
Mat drawing = Mat::zeros( src.size(), CV_8UC3 );
for( int i = 0; i < src.rows; i++ )
{
for( int j = 0; j < src.cols; j++ )
{
if( raw_dist.at<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;
}
}
}
/// Show your results
imshow( "Source", src );
imshow( "Distance", drawing );
/// Show your results
imshow( "Source", src );
imshow( "Distance", drawing );
waitKey(0);
return(0);
waitKey();
return 0;
}

View File

@ -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;
}

View File

@ -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]);
}

View File

@ -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]);
}

View File

@ -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

View File

@ -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;

View File

@ -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

View 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

View File

@ -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,18 +226,19 @@ void postprocess(Mat& frame, const std::vector<Mat>& outs, Net& net)
}
}
}
std::vector<int> indices;
NMSBoxes(boxes, confidences, confThreshold, 0.4f, indices);
for (size_t i = 0; i < indices.size(); ++i)
{
int idx = indices[i];
Rect box = boxes[idx];
drawPred(classIds[idx], confidences[idx], box.x, box.y,
box.x + box.width, box.y + box.height, frame);
}
}
else
CV_Error(Error::StsNotImplemented, "Unknown output layer type: " + outLayerType);
std::vector<int> indices;
NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
for (size_t i = 0; i < indices.size(); ++i)
{
int idx = indices[i];
Rect box = boxes[idx];
drawPred(classIds[idx], confidences[idx], box.x, box.y,
box.x + box.width, box.y + box.height, frame);
}
}
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)

View File

@ -31,6 +31,7 @@ parser.add_argument('--height', type=int,
parser.add_argument('--rgb', action='store_true',
help='Indicate that model works with RGB input images instead BGR ones.')
parser.add_argument('--thr', type=float, default=0.5, help='Confidence threshold')
parser.add_argument('--nms', type=float, default=0.4, help='Non-maximum suppression threshold')
parser.add_argument('--backend', choices=backends, default=cv.dnn.DNN_BACKEND_DEFAULT, type=int,
help="Choose one of computation backends: "
"%d: automatically (by default), "
@ -57,6 +58,7 @@ net.setPreferableBackend(args.backend)
net.setPreferableTarget(args.target)
confThreshold = args.thr
nmsThreshold = args.nms
def getOutputsNames(net):
layersNames = net.getLayerNames()
@ -86,36 +88,43 @@ def postprocess(frame, outs):
lastLayerId = net.getLayerId(layerNames[-1])
lastLayer = net.getLayer(lastLayerId)
classIds = []
confidences = []
boxes = []
if net.getLayer(0).outputNameToIndex('im_info') != -1: # Faster-RCNN or R-FCN
# Network produces output blob with a shape 1x1xNx7 where N is a number of
# detections and an every detection is a vector of values
# [batchId, classId, confidence, left, top, right, bottom]
assert(len(outs) == 1)
out = outs[0]
for detection in out[0, 0]:
confidence = detection[2]
if confidence > confThreshold:
left = int(detection[3])
top = int(detection[4])
right = int(detection[5])
bottom = int(detection[6])
classId = int(detection[1]) - 1 # Skip background label
drawPred(classId, confidence, left, top, right, bottom)
for out in outs:
for detection in out[0, 0]:
confidence = detection[2]
if confidence > confThreshold:
left = int(detection[3])
top = int(detection[4])
right = int(detection[5])
bottom = int(detection[6])
width = right - left + 1
height = bottom - top + 1
classIds.append(int(detection[1]) - 1) # Skip background label
confidences.append(float(confidence))
boxes.append([left, top, width, height])
elif lastLayer.type == 'DetectionOutput':
# Network produces output blob with a shape 1x1xNx7 where N is a number of
# detections and an every detection is a vector of values
# [batchId, classId, confidence, left, top, right, bottom]
assert(len(outs) == 1)
out = outs[0]
for detection in out[0, 0]:
confidence = detection[2]
if confidence > confThreshold:
left = int(detection[3] * frameWidth)
top = int(detection[4] * frameHeight)
right = int(detection[5] * frameWidth)
bottom = int(detection[6] * frameHeight)
classId = int(detection[1]) - 1 # Skip background label
drawPred(classId, confidence, left, top, right, bottom)
for out in outs:
for detection in out[0, 0]:
confidence = detection[2]
if confidence > confThreshold:
left = int(detection[3] * frameWidth)
top = int(detection[4] * frameHeight)
right = int(detection[5] * frameWidth)
bottom = int(detection[6] * frameHeight)
width = right - left + 1
height = bottom - top + 1
classIds.append(int(detection[1]) - 1) # Skip background label
confidences.append(float(confidence))
boxes.append([left, top, width, height])
elif lastLayer.type == 'Region':
# Network produces output blob with a shape NxC where N is a number of
# detected objects and C is a number of classes + 4 where the first 4
@ -138,15 +147,19 @@ def postprocess(frame, outs):
classIds.append(classId)
confidences.append(float(confidence))
boxes.append([left, top, width, height])
indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, 0.4)
for i in indices:
i = i[0]
box = boxes[i]
left = box[0]
top = box[1]
width = box[2]
height = box[3]
drawPred(classIds[i], confidences[i], left, top, left + width, top + height)
else:
print('Unknown output layer type: ' + lastLayer.type)
exit()
indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)
for i in indices:
i = i[0]
box = boxes[i]
left = box[0]
top = box[1]
width = box[2]
height = box[3]
drawPred(classIds[i], confidences[i], left, top, left + width, top + height)
# Process inputs
winName = 'Deep learning object detection in OpenCV'

View File

@ -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);
}
}

View File

@ -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);
}
});
}
}

View File

@ -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);
}
});
}
}

View File

@ -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);
}
});
}
}

View 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);
}
});
}
}

View File

@ -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);
}
});
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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]);
}
}

View File

@ -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]);
}
}

View File

@ -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);

View File

@ -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__

View File

@ -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()

View File

@ -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()

View File

@ -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