diff --git a/3rdparty/include/opencl/1.2/CL/cl_platform.h b/3rdparty/include/opencl/1.2/CL/cl_platform.h index 46b3d9dcdc..e94949a31c 100644 --- a/3rdparty/include/opencl/1.2/CL/cl_platform.h +++ b/3rdparty/include/opencl/1.2/CL/cl_platform.h @@ -454,7 +454,7 @@ typedef unsigned int cl_GLenum; /* Define alignment keys */ #if defined( __GNUC__ ) #define CL_ALIGNED(_x) __attribute__ ((aligned(_x))) -#elif defined( _WIN32) && (_MSC_VER) +#elif defined( _WIN32) && defined(_MSC_VER) /* Alignment keys neutered on windows because MSVC can't swallow function arguments with alignment requirements */ /* http://msdn.microsoft.com/en-us/library/373ak2y1%28VS.71%29.aspx */ /* #include */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 45e5b915fc..856a4d4f8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ endif() OCV_OPTION(WITH_1394 "Include IEEE1394 support" ON IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_AVFOUNDATION "Use AVFoundation for Video I/O" ON IF IOS) OCV_OPTION(WITH_CARBON "Use Carbon for UI instead of Cocoa" OFF IF APPLE ) +OCV_OPTION(WITH_VTK "Include VTK library support (and build opencv_viz module eiher)" OFF IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_CUDA "Include NVidia Cuda Runtime support" ON IF (NOT IOS) ) OCV_OPTION(WITH_CUFFT "Include NVidia Cuda Fast Fourier Transform (FFT) library support" ON IF (NOT IOS) ) OCV_OPTION(WITH_CUBLAS "Include NVidia Cuda Basic Linear Algebra Subprograms (BLAS) library support" OFF IF (NOT IOS) ) @@ -124,7 +125,7 @@ OCV_OPTION(WITH_EIGEN "Include Eigen2/Eigen3 support" ON) OCV_OPTION(WITH_VFW "Include Video for Windows support" ON IF WIN32 ) OCV_OPTION(WITH_FFMPEG "Include FFMPEG support" ON IF (NOT ANDROID AND NOT IOS)) OCV_OPTION(WITH_GSTREAMER "Include Gstreamer support" ON IF (UNIX AND NOT APPLE AND NOT ANDROID) ) -OCV_OPTION(WITH_GSTREAMER_1_X "Include Gstreamer 1.x support" OFF) +OCV_OPTION(WITH_GSTREAMER_0_10 "Enable Gstreamer 0.10 support (instead of 1.x)" OFF ) OCV_OPTION(WITH_GTK "Include GTK support" ON IF (UNIX AND NOT APPLE AND NOT ANDROID) ) OCV_OPTION(WITH_IPP "Include Intel IPP support" OFF IF (MSVC OR X86 OR X86_64) ) OCV_OPTION(WITH_JASPER "Include JPEG2K support" ON IF (NOT IOS) ) @@ -430,6 +431,8 @@ endif() # --- Matlab/Octave --- include(cmake/OpenCVFindMatlab.cmake) +include(cmake/OpenCVDetectVTK.cmake) + # ---------------------------------------------------------------------------- # Add CUDA libraries (needed for apps/tools, samples) # ---------------------------------------------------------------------------- @@ -659,6 +662,7 @@ else() endif() status(" OpenGL support:" HAVE_OPENGL THEN "YES (${OPENGL_LIBRARIES})" ELSE NO) +status(" VTK support:" HAVE_VTK THEN "YES (ver ${VTK_VERSION})" ELSE NO) # ========================== MEDIA IO ========================== status("") diff --git a/apps/traincascade/imagestorage.cpp b/apps/traincascade/imagestorage.cpp index 528f9c167d..e69a7df1ad 100644 --- a/apps/traincascade/imagestorage.cpp +++ b/apps/traincascade/imagestorage.cpp @@ -70,7 +70,7 @@ bool CvCascadeImageReader::NegReader::nextImg() _offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width ); _offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height ); if( !src.empty() && src.type() == CV_8UC1 - && offset.x >= 0 && offset.y >= 0 ) + && _offset.x >= 0 && _offset.y >= 0 ) break; } diff --git a/cmake/OpenCVDetectVTK.cmake b/cmake/OpenCVDetectVTK.cmake new file mode 100644 index 0000000000..f0d28d552a --- /dev/null +++ b/cmake/OpenCVDetectVTK.cmake @@ -0,0 +1,21 @@ +if(NOT WITH_VTK OR ANDROID OR IOS) + return() +endif() + +find_package(VTK 6.0 QUIET COMPONENTS vtkRenderingCore vtkInteractionWidgets vtkInteractionStyle vtkIOLegacy vtkIOPLY vtkRenderingFreeType vtkRenderingLOD vtkFiltersTexture NO_MODULE) + +if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND) + find_package(VTK 5.10 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE) +endif() + +if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND) + find_package(VTK 5.8 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE) +endif() + +if(VTK_FOUND) + set(HAVE_VTK ON) + message(STATUS "Found VTK ver. ${VTK_VERSION} (usefile: ${VTK_USE_FILE})") +else() + set(HAVE_VTK OFF) + message(STATUS "VTK is not found. Please set -DVTK_DIR in CMake to VTK build directory, or set $VTK_DIR enviroment variable to VTK install subdirectory with VTKConfig.cmake file (for windows)") +endif() \ No newline at end of file diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index 737331ecf5..807f4fbbf2 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -12,28 +12,8 @@ endif(WITH_VFW) # --- GStreamer --- ocv_clear_vars(HAVE_GSTREAMER) -# try to find gstreamer 0.10 first -if(WITH_GSTREAMER AND NOT WITH_GSTREAMER_1_X) - CHECK_MODULE(gstreamer-base-0.10 HAVE_GSTREAMER_BASE) - CHECK_MODULE(gstreamer-video-0.10 HAVE_GSTREAMER_VIDEO) - CHECK_MODULE(gstreamer-app-0.10 HAVE_GSTREAMER_APP) - CHECK_MODULE(gstreamer-riff-0.10 HAVE_GSTREAMER_RIFF) - CHECK_MODULE(gstreamer-pbutils-0.10 HAVE_GSTREAMER_PBUTILS) - - if(HAVE_GSTREAMER_BASE AND HAVE_GSTREAMER_VIDEO AND HAVE_GSTREAMER_APP AND HAVE_GSTREAMER_RIFF AND HAVE_GSTREAMER_PBUTILS) - set(HAVE_GSTREAMER TRUE) - set(GSTREAMER_BASE_VERSION ${ALIASOF_gstreamer-base-0.10_VERSION}) - set(GSTREAMER_VIDEO_VERSION ${ALIASOF_gstreamer-video-0.10_VERSION}) - set(GSTREAMER_APP_VERSION ${ALIASOF_gstreamer-app-0.10_VERSION}) - set(GSTREAMER_RIFF_VERSION ${ALIASOF_gstreamer-riff-0.10_VERSION}) - set(GSTREAMER_PBUTILS_VERSION ${ALIASOF_gstreamer-pbutils-0.10_VERSION}) - endif() - -endif(WITH_GSTREAMER AND NOT WITH_GSTREAMER_1_X) - -# if gstreamer 0.10 was not found, or we specified we wanted 1.x, try to find it -if(WITH_GSTREAMER_1_X OR NOT HAVE_GSTREAMER) - #check for 1.x +# try to find gstreamer 1.x first +if(WITH_GSTREAMER AND NOT WITH_GSTREAMER_0_10) CHECK_MODULE(gstreamer-base-1.0 HAVE_GSTREAMER_BASE) CHECK_MODULE(gstreamer-video-1.0 HAVE_GSTREAMER_VIDEO) CHECK_MODULE(gstreamer-app-1.0 HAVE_GSTREAMER_APP) @@ -49,7 +29,25 @@ if(WITH_GSTREAMER_1_X OR NOT HAVE_GSTREAMER) set(GSTREAMER_PBUTILS_VERSION ${ALIASOF_gstreamer-pbutils-1.0_VERSION}) endif() -endif(WITH_GSTREAMER_1_X OR NOT HAVE_GSTREAMER) +endif(WITH_GSTREAMER AND NOT WITH_GSTREAMER_0_10) + +# if gstreamer 1.x was not found, or we specified we wanted 0.10, try to find it +if(WITH_GSTREAMER_0_10 OR NOT HAVE_GSTREAMER) + CHECK_MODULE(gstreamer-base-0.10 HAVE_GSTREAMER_BASE) + CHECK_MODULE(gstreamer-video-0.10 HAVE_GSTREAMER_VIDEO) + CHECK_MODULE(gstreamer-app-0.10 HAVE_GSTREAMER_APP) + CHECK_MODULE(gstreamer-riff-0.10 HAVE_GSTREAMER_RIFF) + CHECK_MODULE(gstreamer-pbutils-0.10 HAVE_GSTREAMER_PBUTILS) + + if(HAVE_GSTREAMER_BASE AND HAVE_GSTREAMER_VIDEO AND HAVE_GSTREAMER_APP AND HAVE_GSTREAMER_RIFF AND HAVE_GSTREAMER_PBUTILS) + set(HAVE_GSTREAMER TRUE) + set(GSTREAMER_BASE_VERSION ${ALIASOF_gstreamer-base-0.10_VERSION}) + set(GSTREAMER_VIDEO_VERSION ${ALIASOF_gstreamer-video-0.10_VERSION}) + set(GSTREAMER_APP_VERSION ${ALIASOF_gstreamer-app-0.10_VERSION}) + set(GSTREAMER_RIFF_VERSION ${ALIASOF_gstreamer-riff-0.10_VERSION}) + set(GSTREAMER_PBUTILS_VERSION ${ALIASOF_gstreamer-pbutils-0.10_VERSION}) + endif() +endif(WITH_GSTREAMER_0_10 OR NOT HAVE_GSTREAMER) # --- unicap --- ocv_clear_vars(HAVE_UNICAP) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 011529d651..c445e3fe59 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -485,6 +485,9 @@ macro(ocv_glob_module_sources) file(GLOB lib_hdrs "include/opencv2/*.hpp" "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h") file(GLOB lib_hdrs_detail "include/opencv2/${name}/detail/*.hpp" "include/opencv2/${name}/detail/*.h") + ocv_source_group("Src" DIRBASE "${CMAKE_CURRENT_SOURCE_DIR}/src" FILES ${lib_srcs} ${lib_int_hdrs}) + ocv_source_group("Include" DIRBASE "${CMAKE_CURRENT_SOURCE_DIR}/include" FILES ${lib_hdrs} ${lib_hdrs_detail}) + file(GLOB lib_cuda_srcs "src/cuda/*.cu") set(cuda_objs "") set(lib_cuda_hdrs "") @@ -493,11 +496,9 @@ macro(ocv_glob_module_sources) file(GLOB lib_cuda_hdrs "src/cuda/*.hpp") ocv_cuda_compile(cuda_objs ${lib_cuda_srcs} ${lib_cuda_hdrs}) - source_group("Src\\Cuda" FILES ${lib_cuda_srcs} ${lib_cuda_hdrs}) + source_group("Src\\Cuda" FILES ${lib_cuda_srcs} ${lib_cuda_hdrs}) endif() - source_group("Src" FILES ${lib_srcs} ${lib_int_hdrs}) - file(GLOB cl_kernels "src/opencl/*.cl") if(cl_kernels) ocv_include_directories(${OPENCL_INCLUDE_DIRS}) @@ -506,15 +507,13 @@ macro(ocv_glob_module_sources) OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp" COMMAND ${CMAKE_COMMAND} -DMODULE_NAME="${the_module_barename}" -DCL_DIR="${CMAKE_CURRENT_SOURCE_DIR}/src/opencl" -DOUTPUT="${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" -P "${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake" DEPENDS ${cl_kernels} "${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake") - source_group("OpenCL" FILES ${cl_kernels} "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp") + ocv_source_group("Src\\opencl\\kernels" FILES ${cl_kernels}) + ocv_source_group("Src\\opencl\\kernels\\autogenerated" FILES "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp") list(APPEND lib_srcs ${cl_kernels} "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp") endif() ocv_set_module_sources(${ARGN} HEADERS ${lib_hdrs} ${lib_hdrs_detail} SOURCES ${lib_srcs} ${lib_int_hdrs} ${cuda_objs} ${lib_cuda_srcs} ${lib_cuda_hdrs}) - - source_group("Include" FILES ${lib_hdrs}) - source_group("Include\\detail" FILES ${lib_hdrs_detail}) endmacro() # creates OpenCV module in current folder @@ -692,8 +691,8 @@ function(ocv_add_perf_tests) if(NOT OPENCV_PERF_${the_module}_SOURCES) file(GLOB_RECURSE perf_srcs "${perf_path}/*.cpp") file(GLOB_RECURSE perf_hdrs "${perf_path}/*.hpp" "${perf_path}/*.h") - source_group("Src" FILES ${perf_srcs}) - source_group("Include" FILES ${perf_hdrs}) + ocv_source_group("Src" DIRBASE "${perf_path}" FILES ${perf_srcs}) + ocv_source_group("Include" DIRBASE "${perf_path}" FILES ${perf_hdrs}) set(OPENCV_PERF_${the_module}_SOURCES ${perf_srcs} ${perf_hdrs}) endif() @@ -742,8 +741,8 @@ function(ocv_add_accuracy_tests) if(NOT OPENCV_TEST_${the_module}_SOURCES) file(GLOB_RECURSE test_srcs "${test_path}/*.cpp") file(GLOB_RECURSE test_hdrs "${test_path}/*.hpp" "${test_path}/*.h") - source_group("Src" FILES ${test_srcs}) - source_group("Include" FILES ${test_hdrs}) + ocv_source_group("Src" DIRBASE "${test_path}" FILES ${test_srcs}) + ocv_source_group("Include" DIRBASE "${test_path}" FILES ${test_hdrs}) set(OPENCV_TEST_${the_module}_SOURCES ${test_srcs} ${test_hdrs}) endif() diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 13461e82c1..677d7f5d5c 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1,3 +1,22 @@ +# Debugging function +function(ocv_cmake_dump_vars) + cmake_parse_arguments(DUMP "" "TOFILE" "" ${ARGN}) + set(regex "${DUMP_UNPARSED_ARGUMENTS}") + get_cmake_property(_variableNames VARIABLES) + set(VARS "") + foreach(_variableName ${_variableNames}) + if(_variableName MATCHES "${regex}") + set(VARS "${VARS}${_variableName}=${${_variableName}}\n") + endif() + endforeach() + if(DUMP_TOFILE) + file(WRITE ${CMAKE_BINARY_DIR}/${DUMP_TOFILE} "${VARS}") + else() + message(AUTHOR_WARNING "${VARS}") + endif() +endfunction() + + # Search packages for host system instead of packages for target system # in case of cross compilation thess macro should be defined by toolchain file if(NOT COMMAND find_host_package) @@ -601,7 +620,35 @@ endmacro() ################################################################################################ # short command to setup source group function(ocv_source_group group) - cmake_parse_arguments(OCV_SOURCE_GROUP "" "" "GLOB" ${ARGN}) - file(GLOB srcs ${OCV_SOURCE_GROUP_GLOB}) - source_group(${group} FILES ${srcs}) + cmake_parse_arguments(SG "" "DIRBASE" "GLOB;GLOB_RECURSE;FILES" ${ARGN}) + set(files "") + if(SG_FILES) + list(APPEND files ${SG_FILES}) + endif() + if(SG_GLOB) + file(GLOB srcs ${SG_GLOB}) + list(APPEND files ${srcs}) + endif() + if(SG_GLOB_RECURSE) + file(GLOB_RECURSE srcs ${SG_GLOB_RECURSE}) + list(APPEND files ${srcs}) + endif() + if(SG_DIRBASE) + foreach(f ${files}) + file(RELATIVE_PATH fpart "${SG_DIRBASE}" "${f}") + if(fpart MATCHES "^\\.\\.") + message(AUTHOR_WARNING "Can't detect subpath for source_group command: Group=${group} FILE=${f} DIRBASE=${SG_DIRBASE}") + set(fpart "") + else() + get_filename_component(fpart "${fpart}" PATH) + if(fpart) + set(fpart "/${fpart}") # add '/' + string(REPLACE "/" "\\" fpart "${fpart}") + endif() + endif() + source_group("${group}${fpart}" FILES ${f}) + endforeach() + else() + source_group(${group} FILES ${files}) + endif() endfunction() diff --git a/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst b/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst index c40b86c974..0b2253acea 100644 --- a/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst +++ b/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.rst @@ -105,7 +105,7 @@ Building OpenCV Enable hardware optimizations ----------------------------- -Depending on target platfrom architecture different instruction sets can be used. By default +Depending on target platform architecture different instruction sets can be used. By default compiler generates code for armv5l without VFPv3 and NEON extensions. Add ``-DUSE_VFPV3=ON`` to cmake command line to enable code generation for VFPv3 and ``-DUSE_NEON=ON`` for using NEON SIMD extensions. diff --git a/modules/calib3d/test/test_affine3.cpp b/modules/calib3d/test/test_affine3.cpp index 62326e9203..cc94d99c19 100644 --- a/modules/calib3d/test/test_affine3.cpp +++ b/modules/calib3d/test/test_affine3.cpp @@ -79,3 +79,30 @@ TEST(Calib3d_Affine3f, accuracy) ASSERT_LT(cv::norm(diff, cv::NORM_INF), 1e-15); } + +TEST(Calib3d_Affine3f, accuracy_rvec) +{ + cv::RNG rng; + typedef float T; + + cv::Affine3::Vec3 w; + cv::Affine3::Mat3 u, vt, R; + + for(int i = 0; i < 100; ++i) + { + rng.fill(R, cv::RNG::UNIFORM, -10, 10, true); + cv::SVD::compute(R, w, u, vt, cv::SVD::FULL_UV + cv::SVD::MODIFY_A); + R = u * vt; + + //double s = (double)cv::getTickCount(); + cv::Affine3::Vec3 va = cv::Affine3(R).rvec(); + //std::cout << "M:" <<(cv::getTickCount() - s)*1000/cv::getTickFrequency() << std::endl; + + cv::Affine3::Vec3 vo; + //s = (double)cv::getTickCount(); + cv::Rodrigues(R, vo); + //std::cout << "O:" <<(cv::getTickCount() - s)*1000/cv::getTickFrequency() << std::endl; + + ASSERT_LT(cv::norm(va - vo), 1e-9); + } +} diff --git a/modules/core/include/opencv2/core/affine.hpp b/modules/core/include/opencv2/core/affine.hpp index ed8bd29a18..fefcef8f12 100644 --- a/modules/core/include/opencv2/core/affine.hpp +++ b/modules/core/include/opencv2/core/affine.hpp @@ -51,7 +51,7 @@ namespace cv { template - class CV_EXPORTS Affine3 + class Affine3 { public: typedef T float_type; @@ -97,6 +97,9 @@ namespace cv Mat3 linear() const; Vec3 translation() const; + //Rodrigues vector + Vec3 rvec() const; + Affine3 inv(int method = cv::DECOMP_SVD) const; // a.rotate(R) is equivalent to Affine(R, 0) * a; @@ -158,9 +161,9 @@ cv::Affine3::Affine3(const Mat3& R, const Vec3& t) } template inline -cv::Affine3::Affine3(const Vec3& rvec, const Vec3& t) +cv::Affine3::Affine3(const Vec3& _rvec, const Vec3& t) { - rotation(rvec); + rotation(_rvec); translation(t); matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; matrix.val[15] = 1; @@ -205,9 +208,9 @@ void cv::Affine3::rotation(const Mat3& R) } template inline -void cv::Affine3::rotation(const Vec3& rvec) +void cv::Affine3::rotation(const Vec3& _rvec) { - double rx = rvec[0], ry = rvec[1], rz = rvec[2]; + double rx = _rvec[0], ry = _rvec[1], rz = _rvec[2]; double theta = std::sqrt(rx*rx + ry*ry + rz*rz); if (theta < DBL_EPSILON) @@ -250,9 +253,9 @@ void cv::Affine3::rotation(const cv::Mat& data) } else if ((data.cols == 3 && data.rows == 1) || (data.cols == 1 && data.rows == 3)) { - Vec3 rvec; - data.reshape(1, 3).copyTo(rvec); - rotation(rvec); + Vec3 _rvec; + data.reshape(1, 3).copyTo(_rvec); + rotation(_rvec); } else CV_Assert(!"Input marix can be 3x3, 1x3 or 3x1"); @@ -300,6 +303,55 @@ typename cv::Affine3::Vec3 cv::Affine3::translation() const return Vec3(matrix.val[3], matrix.val[7], matrix.val[11]); } +template inline +typename cv::Affine3::Vec3 cv::Affine3::rvec() const +{ + cv::Vec3d w; + cv::Matx33d u, vt, R = rotation(); + cv::SVD::compute(R, w, u, vt, cv::SVD::FULL_UV + cv::SVD::MODIFY_A); + R = u * vt; + + double rx = R.val[7] - R.val[5]; + double ry = R.val[2] - R.val[6]; + double rz = R.val[3] - R.val[1]; + + double s = std::sqrt((rx*rx + ry*ry + rz*rz)*0.25); + double c = (R.val[0] + R.val[4] + R.val[8] - 1) * 0.5; + c = c > 1.0 ? 1.0 : c < -1.0 ? -1.0 : c; + double theta = acos(c); + + if( s < 1e-5 ) + { + if( c > 0 ) + rx = ry = rz = 0; + else + { + double t; + t = (R.val[0] + 1) * 0.5; + rx = std::sqrt(std::max(t, 0.0)); + t = (R.val[4] + 1) * 0.5; + ry = std::sqrt(std::max(t, 0.0)) * (R.val[1] < 0 ? -1.0 : 1.0); + t = (R.val[8] + 1) * 0.5; + rz = std::sqrt(std::max(t, 0.0)) * (R.val[2] < 0 ? -1.0 : 1.0); + + if( fabs(rx) < fabs(ry) && fabs(rx) < fabs(rz) && (R.val[5] > 0) != (ry*rz > 0) ) + rz = -rz; + theta /= std::sqrt(rx*rx + ry*ry + rz*rz); + rx *= theta; + ry *= theta; + rz *= theta; + } + } + else + { + double vth = 1/(2*s); + vth *= theta; + rx *= vth; ry *= vth; rz *= vth; + } + + return cv::Vec3d(rx, ry, rz); +} + template inline cv::Affine3 cv::Affine3::inv(int method) const { diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index f864510de6..401467534b 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -129,6 +129,8 @@ public: virtual bool isContinuous(int i=-1) const; virtual bool empty() const; virtual void copyTo(const _OutputArray& arr) const; + virtual size_t offset(int i=-1) const; + virtual size_t step(int i=-1) const; bool isMat() const; bool isUMat() const; bool isMatVectot() const; diff --git a/modules/core/include/opencv2/core/matx.hpp b/modules/core/include/opencv2/core/matx.hpp index 86a35cd756..d7d4859573 100644 --- a/modules/core/include/opencv2/core/matx.hpp +++ b/modules/core/include/opencv2/core/matx.hpp @@ -153,8 +153,8 @@ public: //! transpose the matrix Matx<_Tp, n, m> t() const; - //! invert matrix the matrix - Matx<_Tp, n, m> inv(int method=DECOMP_LU) const; + //! invert the matrix + Matx<_Tp, n, m> inv(int method=DECOMP_LU, bool *p_is_ok = NULL) const; //! solve linear system template Matx<_Tp, n, l> solve(const Matx<_Tp, m, l>& rhs, int flags=DECOMP_LU) const; diff --git a/modules/core/include/opencv2/core/operations.hpp b/modules/core/include/opencv2/core/operations.hpp index f8aeddfb11..954604a9d8 100644 --- a/modules/core/include/opencv2/core/operations.hpp +++ b/modules/core/include/opencv2/core/operations.hpp @@ -186,7 +186,7 @@ Matx<_Tp,m,n> Matx<_Tp,m,n>::randn(_Tp a, _Tp b) } template inline -Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method) const +Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method, bool *p_is_ok /*= NULL*/) const { Matx<_Tp, n, m> b; bool ok; @@ -197,6 +197,7 @@ Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method) const Mat A(*this, false), B(b, false); ok = (invert(A, B, method) != 0); } + if( NULL != p_is_ok ) { *p_is_ok = ok; } return ok ? b : Matx<_Tp, n, m>::zeros(); } @@ -435,7 +436,7 @@ int print(const std::vector >& vec, FILE* stream = stdout) template static inline int print(const Matx<_Tp, m, n>& matx, FILE* stream = stdout) { - return print(Formatter::get()->format(matx), stream); + return print(Formatter::get()->format(cv::Mat(matx)), stream); } diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp index af7e042e18..05c1a6e402 100644 --- a/modules/core/src/convert.cpp +++ b/modules/core/src/convert.cpp @@ -264,8 +264,50 @@ void cv::split(const Mat& src, Mat* mv) } } +namespace cv { + +static bool ocl_split( InputArray _m, OutputArrayOfArrays _mv ) +{ + int type = _m.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + + String dstargs, dstdecl, processelem; + for (int i = 0; i < cn; ++i) + { + dstargs += format("DECLARE_DST_PARAM(%d)", i); + dstdecl += format("DECLARE_DATA(%d)", i); + processelem += format("PROCESS_ELEM(%d)", i); + } + + ocl::Kernel k("split", ocl::core::split_merge_oclsrc, + format("-D T=%s -D OP_SPLIT -D cn=%d -D DECLARE_DST_PARAMS=%s " + "-D DECLARE_DATA_N=%s -D PROCESS_ELEMS_N=%s", + ocl::memopTypeToStr(depth), cn, dstargs.c_str(), + dstdecl.c_str(), processelem.c_str())); + if (k.empty()) + return false; + + Size size = _m.size(); + std::vector & dst = *(std::vector *)_mv.getObj(); + dst.resize(cn); + for (int i = 0; i < cn; ++i) + dst[i].create(size, depth); + + int argidx = k.set(0, ocl::KernelArg::ReadOnly(_m.getUMat())); + for (int i = 0; i < cn; ++i) + argidx = k.set(argidx, ocl::KernelArg::WriteOnlyNoSize(dst[i])); + + size_t globalsize[2] = { size.width, size.height }; + return k.run(2, globalsize, NULL, false); +} + +} + void cv::split(InputArray _m, OutputArrayOfArrays _mv) { + if (ocl::useOpenCL() && _m.dims() <= 2 && _mv.isUMatVector() && + ocl_split(_m, _mv)) + return; + Mat m = _m.getMat(); if( m.empty() ) { @@ -353,8 +395,58 @@ void cv::merge(const Mat* mv, size_t n, OutputArray _dst) } } +namespace cv { + +static bool ocl_merge( InputArrayOfArrays _mv, OutputArray _dst ) +{ + const std::vector & src = *(const std::vector *)(_mv.getObj()); + CV_Assert(!src.empty()); + + int type = src[0].type(), depth = CV_MAT_DEPTH(type); + Size size = src[0].size(); + + size_t srcsize = src.size(); + for (size_t i = 0; i < srcsize; ++i) + { + int itype = src[i].type(), icn = CV_MAT_CN(itype), idepth = CV_MAT_DEPTH(itype); + if (src[i].dims > 2 || icn != 1) + return false; + CV_Assert(size == src[i].size() && depth == idepth); + } + + String srcargs, srcdecl, processelem; + for (size_t i = 0; i < srcsize; ++i) + { + srcargs += format("DECLARE_SRC_PARAM(%d)", i); + srcdecl += format("DECLARE_DATA(%d)", i); + processelem += format("PROCESS_ELEM(%d)", i); + } + + ocl::Kernel k("merge", ocl::core::split_merge_oclsrc, + format("-D OP_MERGE -D cn=%d -D T=%s -D DECLARE_SRC_PARAMS_N=%s -D DECLARE_DATA_N=%s -D PROCESS_ELEMS_N=%s", + (int)srcsize, ocl::memopTypeToStr(depth), srcargs.c_str(), srcdecl.c_str(), processelem.c_str())); + if (k.empty()) + return false; + + _dst.create(size, CV_MAKE_TYPE(depth, (int)srcsize)); + UMat dst = _dst.getUMat(); + + int argidx = 0; + for (size_t i = 0; i < srcsize; ++i) + argidx = k.set(argidx, ocl::KernelArg::ReadOnlyNoSize(src[i])); + k.set(argidx, ocl::KernelArg::WriteOnly(dst)); + + size_t globalsize[2] = { dst.cols, dst.rows }; + return k.run(2, globalsize, NULL, false); +} + +} + void cv::merge(InputArrayOfArrays _mv, OutputArray _dst) { + if (ocl::useOpenCL() && _mv.isUMatVector() && _dst.isUMat() && ocl_merge(_mv, _dst)) + return; + std::vector mv; _mv.getMatVector(mv); merge(!mv.empty() ? &mv[0] : 0, mv.size(), _dst); @@ -1214,9 +1306,10 @@ namespace cv { static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst) { - int dcn = _dst.channels(), lcn = _lut.channels(), dtype = _dst.type(); + int dtype = _dst.type(), lcn = _lut.channels(), dcn = CV_MAT_CN(dtype), ddepth = CV_MAT_DEPTH(dtype); + bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; - if (_src.dims() > 2) + if (_src.dims() > 2 || (!doubleSupport && ddepth == CV_64F)) return false; UMat src = _src.getUMat(), lut = _lut.getUMat(); @@ -1224,8 +1317,9 @@ static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst) UMat dst = _dst.getUMat(); ocl::Kernel k("LUT", ocl::core::lut_oclsrc, - format("-D dcn=%d -D lcn=%d -D srcT=%s -D dstT=%s", dcn, lcn, - ocl::typeToStr(src.depth()), ocl::typeToStr(dst.depth()))); + format("-D dcn=%d -D lcn=%d -D srcT=%s -D dstT=%s%s", dcn, lcn, + ocl::typeToStr(src.depth()), ocl::typeToStr(ddepth), + doubleSupport ? " -D DOUBLE_SUPPORT" : "")); k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::ReadOnlyNoSize(lut), ocl::KernelArg::WriteOnly(dst)); diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index fa6fa69f13..0c690bde4c 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -6,7 +6,6 @@ // 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 // @@ -478,11 +477,59 @@ flipVert( const uchar* src0, size_t sstep, uchar* dst0, size_t dstep, Size size, } } +enum { FLIP_COLS = 1 << 0, FLIP_ROWS = 1 << 1, FLIP_BOTH = FLIP_ROWS | FLIP_COLS }; + +static bool ocl_flip(InputArray _src, OutputArray _dst, int flipCode ) +{ + int type = _src.type(), cn = CV_MAT_CN(type); + + if (cn > 4 || cn == 3) + return false; + + const char * kernelName; + int flipType; + + if (flipCode == 0) + kernelName = "arithm_flip_rows", flipType = FLIP_ROWS; + else if (flipCode > 0) + kernelName = "arithm_flip_cols", flipType = FLIP_COLS; + else + kernelName = "arithm_flip_rows_cols", flipType = FLIP_BOTH; + + Size size = _src.size(); + int cols = size.width, rows = size.height; + if ((cols == 1 && flipType == FLIP_COLS) || + (rows == 1 && flipType == FLIP_ROWS) || + (rows == 1 && cols == 1 && flipType == FLIP_BOTH)) + { + _src.copyTo(_dst); + return true; + } + + ocl::Kernel k(kernelName, ocl::core::flip_oclsrc, + format( "-D type=%s", ocl::memopTypeToStr(type))); + if (k.empty()) + return false; + + _dst.create(size, type); + UMat src = _src.getUMat(), dst = _dst.getUMat(); + + cols = flipType == FLIP_COLS ? ((cols+1)/2) : cols; + rows = flipType & FLIP_ROWS ? ((rows+1)/2) : rows; + + size_t globalsize[2] = { cols, rows }; + return k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(dst), rows, cols).run(2, globalsize, NULL, false); +} + void flip( InputArray _src, OutputArray _dst, int flip_mode ) { - Mat src = _src.getMat(); + CV_Assert( _src.dims() <= 2 ); - CV_Assert( src.dims <= 2 ); + bool use_opencl = ocl::useOpenCL() && _dst.isUMat(); + if ( use_opencl && ocl_flip(_src,_dst, flip_mode)) + return; + + Mat src = _src.getMat(); _dst.create( src.size(), src.type() ); Mat dst = _dst.getMat(); size_t esz = src.elemSize(); diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 4e9be9807c..871fb385d6 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -1792,6 +1792,99 @@ bool _InputArray::isContinuous(int i) const return false; } +size_t _InputArray::offset(int i) const +{ + int k = kind(); + + if( k == MAT ) + { + CV_Assert( i < 0 ); + const Mat * const m = ((const Mat*)obj); + return (size_t)(m->data - m->datastart); + } + + if( k == UMAT ) + { + CV_Assert( i < 0 ); + return ((const UMat*)obj)->offset; + } + + if( k == EXPR || k == MATX || k == STD_VECTOR || k == NONE || k == STD_VECTOR_VECTOR) + return 0; + + if( k == STD_VECTOR_MAT ) + { + const std::vector& vv = *(const std::vector*)obj; + if( i < 0 ) + return 1; + CV_Assert( i < (int)vv.size() ); + + return (size_t)(vv[i].data - vv[i].datastart); + } + + if( k == STD_VECTOR_UMAT ) + { + const std::vector& vv = *(const std::vector*)obj; + CV_Assert((size_t)i < vv.size()); + return vv[i].offset; + } + + if( k == GPU_MAT ) + { + CV_Assert( i < 0 ); + const cuda::GpuMat * const m = ((const cuda::GpuMat*)obj); + return (size_t)(m->data - m->datastart); + } + + CV_Error(Error::StsNotImplemented, ""); + return 0; +} + +size_t _InputArray::step(int i) const +{ + int k = kind(); + + if( k == MAT ) + { + CV_Assert( i < 0 ); + return ((const Mat*)obj)->step; + } + + if( k == UMAT ) + { + CV_Assert( i < 0 ); + return ((const UMat*)obj)->step; + } + + if( k == EXPR || k == MATX || k == STD_VECTOR || k == NONE || k == STD_VECTOR_VECTOR) + return 0; + + if( k == STD_VECTOR_MAT ) + { + const std::vector& vv = *(const std::vector*)obj; + if( i < 0 ) + return 1; + CV_Assert( i < (int)vv.size() ); + return vv[i].step; + } + + if( k == STD_VECTOR_UMAT ) + { + const std::vector& vv = *(const std::vector*)obj; + CV_Assert((size_t)i < vv.size()); + return vv[i].step; + } + + if( k == GPU_MAT ) + { + CV_Assert( i < 0 ); + return ((const cuda::GpuMat*)obj)->step; + } + + CV_Error(Error::StsNotImplemented, ""); + return 0; +} + void _InputArray::copyTo(const _OutputArray& arr) const { int k = kind(); diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index f733dd11fb..96a006f1c5 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -1932,10 +1932,15 @@ struct Queue::Impl ~Impl() { - if(handle) +#ifdef _WIN32 + if (!cv::__termination) +#endif { - clFinish(handle); - clReleaseCommandQueue(handle); + if(handle) + { + clFinish(handle); + clReleaseCommandQueue(handle); + } } } @@ -2379,7 +2384,7 @@ struct Program::Impl size_t retsz = 0; retval = clGetProgramBuildInfo(handle, (cl_device_id)deviceList[0], CL_PROGRAM_BUILD_LOG, 0, 0, &retsz); - if( retval >= 0 && retsz > 0 ) + if( retval >= 0 && retsz > 1 ) { AutoBuffer bufbuf(retsz + 16); char* buf = bufbuf; diff --git a/modules/core/src/opencl/arithm.cl b/modules/core/src/opencl/arithm.cl index b4cdb53f2c..9c86057caa 100644 --- a/modules/core/src/opencl/arithm.cl +++ b/modules/core/src/opencl/arithm.cl @@ -58,10 +58,10 @@ */ #ifdef DOUBLE_SUPPORT -#ifdef cl_khr_fp64 -#pragma OPENCL EXTENSION cl_khr_fp64:enable -#elif defined (cl_amd_fp64) +#ifdef cl_amd_fp64 #pragma OPENCL EXTENSION cl_amd_fp64:enable +#elif defined cl_khr_fp64 +#pragma OPENCL EXTENSION cl_khr_fp64:enable #endif #define CV_EPSILON DBL_EPSILON #define CV_PI M_PI @@ -76,12 +76,18 @@ #ifndef workT + #ifndef srcT1 #define srcT1 dstT + #endif + #ifndef srcT2 #define srcT2 dstT + #endif #define workT dstT - #define srcelem1 *(__global dstT*)(srcptr1 + src1_index) - #define srcelem2 *(__global dstT*)(srcptr2 + src2_index) + #define srcelem1 *(__global srcT1*)(srcptr1 + src1_index) + #define srcelem2 *(__global srcT2*)(srcptr2 + src2_index) + #ifndef convertToDT #define convertToDT noconvert + #endif #else @@ -160,6 +166,11 @@ #elif defined OP_MAG #define PROCESS_ELEM dstelem = hypot(srcelem1, srcelem2) +#elif defined OP_ABS_NOSAT +#define PROCESS_ELEM \ + dstT v = convertToDT(srcelem1); \ + dstelem = v >= 0 ? v : -v + #elif defined OP_PHASE_RADIANS #define PROCESS_ELEM \ workT tmp = atan2(srcelem2, srcelem1); \ diff --git a/modules/core/src/opencl/flip.cl b/modules/core/src/opencl/flip.cl new file mode 100644 index 0000000000..4e53041539 --- /dev/null +++ b/modules/core/src/opencl/flip.cl @@ -0,0 +1,102 @@ +/*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) 2013, 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 OpenCV Foundation 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*/ + +#define sizeoftype ((int)sizeof(type)) + +__kernel void arithm_flip_rows(__global const uchar* srcptr, int srcstep, int srcoffset, + __global uchar* dstptr, int dststep, int dstoffset, + int rows, int cols, int thread_rows, int thread_cols) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x < cols && y < thread_rows) + { + __global const type* src0 = (__global const type*)(srcptr + mad24(y, srcstep, srcoffset + x * sizeoftype)); + __global const type* src1 = (__global const type*)(srcptr + mad24(rows - y - 1, srcstep, srcoffset + x * sizeoftype)); + + __global type* dst0 = (__global type*)(dstptr + mad24(y, dststep, dstoffset + x * sizeoftype)); + __global type* dst1 = (__global type*)(dstptr + mad24(rows - y - 1, dststep, dstoffset + x * sizeoftype)); + + dst0[0] = src1[0]; + dst1[0] = src0[0]; + } +} + +__kernel void arithm_flip_rows_cols(__global const uchar* srcptr, int srcstep, int srcoffset, + __global uchar* dstptr, int dststep, int dstoffset, + int rows, int cols, int thread_rows, int thread_cols) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x < cols && y < thread_rows) + { + __global const type* src0 = (__global const type*)(srcptr + mad24(y, srcstep, x*sizeoftype + srcoffset)); + __global const type* src1 = (__global const type*)(srcptr + mad24(rows - y - 1, srcstep, (cols - x - 1)*sizeoftype + srcoffset)); + + __global type* dst0 = (__global type*)(dstptr + mad24(rows - y - 1, dststep, (cols - x - 1)*sizeoftype + dstoffset)); + __global type* dst1 = (__global type*)(dstptr + mad24(y, dststep, x * sizeoftype + dstoffset)); + + dst0[0] = src0[0]; + dst1[0] = src1[0]; + } +} + +__kernel void arithm_flip_cols(__global const uchar* srcptr, int srcstep, int srcoffset, + __global uchar* dstptr, int dststep, int dstoffset, + int rows, int cols, int thread_rows, int thread_cols) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x < thread_cols && y < rows) + { + __global const type* src0 = (__global const type*)(srcptr + mad24(y, srcstep, x * sizeoftype + srcoffset)); + __global const type* src1 = (__global const type*)(srcptr + mad24(y, srcstep, (cols - x - 1)*sizeoftype + srcoffset)); + + __global type* dst0 = (__global type*)(dstptr + mad24(y, dststep, (cols - x - 1)*sizeoftype + dstoffset)); + __global type* dst1 = (__global type*)(dstptr + mad24(y, dststep, x * sizeoftype + dstoffset)); + + dst1[0] = src1[0]; + dst0[0] = src0[0]; + } +} diff --git a/modules/core/src/opencl/split_merge.cl b/modules/core/src/opencl/split_merge.cl new file mode 100644 index 0000000000..d2462750ce --- /dev/null +++ b/modules/core/src/opencl/split_merge.cl @@ -0,0 +1,88 @@ +/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Copyright (C) 2013, 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 copyright holders 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*/ + +#ifdef OP_MERGE + +#define DECLARE_SRC_PARAM(index) __global const uchar * src##index##ptr, int src##index##_step, int src##index##_offset, +#define DECLARE_DATA(index) __global const T * src##index = \ + (__global T *)(src##index##ptr + mad24(src##index##_step, y, x * (int)sizeof(T) + src##index##_offset)); +#define PROCESS_ELEM(index) dst[index] = src##index[0]; + +__kernel void merge(DECLARE_SRC_PARAMS_N + __global uchar * dstptr, int dst_step, int dst_offset, + int rows, int cols) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x < cols && y < rows) + { + DECLARE_DATA_N + __global T * dst = (__global T *)(dstptr + mad24(dst_step, y, x * (int)sizeof(T) * cn + dst_offset)); + PROCESS_ELEMS_N + } +} + +#elif defined OP_SPLIT + +#define DECLARE_DST_PARAM(index) , __global uchar * dst##index##ptr, int dst##index##_step, int dst##index##_offset +#define DECLARE_DATA(index) __global T * dst##index = \ + (__global T *)(dst##index##ptr + mad24(y, dst##index##_step, x * (int)sizeof(T) + dst##index##_offset)); +#define PROCESS_ELEM(index) dst##index[0] = src[index]; + +__kernel void split(__global uchar* srcptr, int src_step, int src_offset, int rows, int cols DECLARE_DST_PARAMS) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x < cols && y < rows) + { + DECLARE_DATA_N + __global const T * src = (__global const T *)(srcptr + mad24(y, src_step, x * cn * (int)sizeof(T) + src_offset)); + PROCESS_ELEMS_N + } +} + +#else +#error "No operation" +#endif diff --git a/modules/core/src/precomp.hpp b/modules/core/src/precomp.hpp index 7465685fd6..87104aff80 100644 --- a/modules/core/src/precomp.hpp +++ b/modules/core/src/precomp.hpp @@ -249,6 +249,9 @@ namespace ocl MatAllocator* getOpenCLAllocator(); } +extern bool __termination; // skip some cleanups, because process is terminating + // (for example, if ExitProcess() was already called) + } #endif /*_CXCORE_INTERNAL_H_*/ diff --git a/modules/core/src/stat.cpp b/modules/core/src/stat.cpp index b19be3b476..d04857ce81 100644 --- a/modules/core/src/stat.cpp +++ b/modules/core/src/stat.cpp @@ -1760,15 +1760,76 @@ static NormDiffFunc getNormDiffFunc(int normType, int depth) } +namespace cv { + +static bool ocl_norm( InputArray _src, int normType, double & result ) +{ + int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; + + if ( !(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) || + (!doubleSupport && depth == CV_64F)) + return false; + + UMat src = _src.getUMat(); + + if (normType == NORM_INF) + { + UMat abssrc; + + if (depth != CV_8U && depth != CV_16U) + { + int wdepth = std::max(CV_32S, depth); + char cvt[50]; + + ocl::Kernel kabs("KF", ocl::core::arithm_oclsrc, + format("-D UNARY_OP -D OP_ABS_NOSAT -D dstT=%s -D srcT1=%s -D convertToDT=%s%s", + ocl::typeToStr(wdepth), ocl::typeToStr(depth), + ocl::convertTypeStr(depth, wdepth, 1, cvt), + doubleSupport ? " -D DOUBLE_SUPPORT" : "")); + if (kabs.empty()) + return false; + + abssrc.create(src.size(), CV_MAKE_TYPE(wdepth, cn)); + kabs.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::WriteOnly(abssrc, cn)); + + size_t globalsize[2] = { src.cols * cn, src.rows }; + if (!kabs.run(2, globalsize, NULL, false)) + return false; + } + else + abssrc = src; + + cv::minMaxIdx(abssrc.reshape(1), NULL, &result); + } + else if (normType == NORM_L1 || normType == NORM_L2) + { + Scalar s; + bool unstype = depth == CV_8U || depth == CV_16U; + + ocl_sum(src.reshape(1), s, normType == NORM_L2 ? + OCL_OP_SUM_SQR : (unstype ? OCL_OP_SUM : OCL_OP_SUM_ABS) ); + result = normType == NORM_L1 ? s[0] : std::sqrt(s[0]); + } + + return true; +} + +} + double cv::norm( InputArray _src, int normType, InputArray _mask ) { - Mat src = _src.getMat(), mask = _mask.getMat(); - int depth = src.depth(), cn = src.channels(); - - normType &= 7; + normType &= NORM_TYPE_MASK; CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 || normType == NORM_L2SQR || - ((normType == NORM_HAMMING || normType == NORM_HAMMING2) && src.type() == CV_8U) ); + ((normType == NORM_HAMMING || normType == NORM_HAMMING2) && _src.type() == CV_8U) ); + + double _result = 0; + if (ocl::useOpenCL() && _mask.empty() && _src.isUMat() && _src.dims() <= 2 && ocl_norm(_src, normType, _result)) + return _result; + + Mat src = _src.getMat(), mask = _mask.getMat(); + int depth = src.depth(), cn = src.channels(); #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) size_t total_size = src.total(); @@ -2047,9 +2108,56 @@ double cv::norm( InputArray _src, int normType, InputArray _mask ) return result.d; } +namespace cv { + +static bool ocl_norm( InputArray _src1, InputArray _src2, int normType, double & result ) +{ + int type = _src1.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; + bool relative = (normType & NORM_RELATIVE) != 0; + normType &= ~NORM_RELATIVE; + + if ( !(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) || + (!doubleSupport && depth == CV_64F)) + return false; + + int wdepth = std::max(CV_32S, depth); + char cvt[50]; + ocl::Kernel k("KF", ocl::core::arithm_oclsrc, + format("-D BINARY_OP -D OP_ABSDIFF -D dstT=%s -D workT=dstT -D srcT1=%s -D srcT2=srcT1" + " -D convertToDT=%s -D convertToWT1=convertToDT -D convertToWT2=convertToDT%s", + ocl::typeToStr(wdepth), ocl::typeToStr(depth), + ocl::convertTypeStr(depth, wdepth, 1, cvt), + doubleSupport ? " -D DOUBLE_SUPPORT" : "")); + if (k.empty()) + return false; + + UMat src1 = _src1.getUMat(), src2 = _src2.getUMat(), diff(src1.size(), CV_MAKE_TYPE(wdepth, cn)); + k.args(ocl::KernelArg::ReadOnlyNoSize(src1), ocl::KernelArg::ReadOnlyNoSize(src2), + ocl::KernelArg::WriteOnly(diff, cn)); + + size_t globalsize[2] = { diff.cols * cn, diff.rows }; + if (!k.run(2, globalsize, NULL, false)) + return false; + + result = cv::norm(diff, normType); + if (relative) + result /= cv::norm(src2, normType) + DBL_EPSILON; + + return true; +} + +} double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask ) { + CV_Assert( _src1.size() == _src2.size() && _src1.type() == _src2.type() ); + + double _result = 0; + if (ocl::useOpenCL() && _mask.empty() && _src1.isUMat() && _src2.isUMat() && + _src1.dims() <= 2 && _src2.dims() <= 2 && ocl_norm(_src1, _src2, normType, _result)) + return _result; + if( normType & CV_RELATIVE ) { #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) @@ -2135,7 +2243,7 @@ double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _m Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); int depth = src1.depth(), cn = src1.channels(); - CV_Assert( src1.size == src2.size && src1.type() == src2.type() ); + CV_Assert( src1.size == src2.size ); normType &= 7; CV_Assert( normType == NORM_INF || normType == NORM_L1 || diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index eee06e2905..27865971b7 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -734,18 +734,23 @@ cvErrorFromIppStatus( int status ) } } +namespace cv { +bool __termination = false; +} #if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE #ifdef HAVE_WINRT #pragma warning(disable:4447) // Disable warning 'main' signature found without threading model #endif -BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID ); +BOOL WINAPI DllMain( HINSTANCE, DWORD, LPVOID ); -BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID ) +BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID lpReserved ) { if( fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH ) { + if (lpReserved != NULL) // called after ExitProcess() call + cv::__termination = true; cv::deleteThreadAllocData(); cv::deleteThreadData(); } diff --git a/modules/core/test/ocl/test_arithm.cpp b/modules/core/test/ocl/test_arithm.cpp index 10cec7bc00..e14fd67f55 100644 --- a/modules/core/test/ocl/test_arithm.cpp +++ b/modules/core/test/ocl/test_arithm.cpp @@ -92,8 +92,7 @@ PARAM_TEST_CASE(Lut, MatDepth, MatDepth, Channels, bool, bool) void Near(double threshold = 0.) { - EXPECT_MAT_NEAR(dst, udst, threshold); - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst, threshold) } }; @@ -165,14 +164,12 @@ PARAM_TEST_CASE(ArithmTestBase, MatDepth, Channels, bool) void Near(double threshold = 0.) { - EXPECT_MAT_NEAR(dst1, udst1, threshold); - EXPECT_MAT_NEAR(dst1_roi, udst1_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst1, threshold) } void Near1(double threshold = 0.) { - EXPECT_MAT_NEAR(dst2, udst2, threshold); - EXPECT_MAT_NEAR(dst2_roi, udst2_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst2, threshold) } }; @@ -532,8 +529,7 @@ OCL_TEST_P(Transpose, SquareInplace) OCL_OFF(cv::transpose(src1_roi, src1_roi)); OCL_ON(cv::transpose(usrc1_roi, usrc1_roi)); - EXPECT_MAT_NEAR(src1, usrc1, 0.0); - EXPECT_MAT_NEAR(src1_roi, usrc1_roi, 0.0); + OCL_EXPECT_MATS_NEAR(src1, 0) } } @@ -795,8 +791,8 @@ struct RepeatTestCase : { const int type = CV_MAKE_TYPE(depth, cn); - nx = 2;//randomInt(1, 4); - ny = 2;//randomInt(1, 4); + nx = randomInt(1, 4); + ny = randomInt(1, 4); Size srcRoiSize = randomSize(1, MAX_VALUE); Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0); @@ -813,7 +809,7 @@ struct RepeatTestCase : typedef RepeatTestCase Repeat; -OCL_TEST_P(Repeat, DISABLED_Mat) +OCL_TEST_P(Repeat, Mat) { for (int i = 0; i < test_loop_times; ++i) { @@ -964,6 +960,148 @@ OCL_TEST_P(Magnitude, Mat) } } +//////////////////////////////// Flip ///////////////////////////////////////////////// + +typedef ArithmTestBase Flip; + +OCL_TEST_P(Flip, X) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::flip(src1_roi, dst1_roi, 0)); + OCL_ON(cv::flip(usrc1_roi, udst1_roi, 0)); + Near(0); + } +} + +OCL_TEST_P(Flip, Y) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::flip(src1_roi, dst1_roi, 1)); + OCL_ON(cv::flip(usrc1_roi, udst1_roi, 1)); + Near(0); + } +} + +OCL_TEST_P(Flip, BOTH) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(cv::flip(src1_roi, dst1_roi, -1)); + OCL_ON(cv::flip(usrc1_roi, udst1_roi, -1)); + Near(0); + } +} + +//////////////////////////////// Norm ///////////////////////////////////////////////// + +static bool relativeError(double actual, double expected, double eps) +{ + return std::abs(actual - expected) / actual < eps; +} + +typedef ArithmTestBase Norm; + +OCL_TEST_P(Norm, NORM_INF_1arg) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(const double cpuRes = cv::norm(src1_roi, NORM_INF)); + OCL_ON(const double gpuRes = cv::norm(usrc1_roi, NORM_INF)); + + EXPECT_NEAR(cpuRes, gpuRes, 0.1); + } +} + +OCL_TEST_P(Norm, NORM_L1_1arg) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(const double cpuRes = cv::norm(src1_roi, NORM_L1)); + OCL_ON(const double gpuRes = cv::norm(usrc1_roi, NORM_L1)); + + EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6); + } +} + +OCL_TEST_P(Norm, NORM_L2_1arg) +{ + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + OCL_OFF(const double cpuRes = cv::norm(src1_roi, NORM_L2)); + OCL_ON(const double gpuRes = cv::norm(usrc1_roi, NORM_L2)); + + EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6); + } +} + +OCL_TEST_P(Norm, NORM_INF_2args) +{ + for (int relative = 0; relative < 2; ++relative) + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + int type = NORM_INF; + if (relative == 1) + type |= NORM_RELATIVE; + + OCL_OFF(const double cpuRes = cv::norm(src1_roi, src2_roi, type)); + OCL_ON(const double gpuRes = cv::norm(usrc1_roi, usrc2_roi, type)); + + EXPECT_NEAR(cpuRes, gpuRes, 0.1); + } +} + +OCL_TEST_P(Norm, NORM_L1_2args) +{ + for (int relative = 0; relative < 2; ++relative) + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + int type = NORM_L1; + if (relative == 1) + type |= NORM_RELATIVE; + + OCL_OFF(const double cpuRes = cv::norm(src1_roi, src2_roi, type)); + OCL_ON(const double gpuRes = cv::norm(usrc1_roi, usrc2_roi, type)); + + EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6); + } +} + +OCL_TEST_P(Norm, NORM_L2_2args) +{ + for (int relative = 0; relative < 2; ++relative) + for (int j = 0; j < test_loop_times; j++) + { + generateTestData(); + + int type = NORM_L2; + if (relative == 1) + type |= NORM_RELATIVE; + + OCL_OFF(const double cpuRes = cv::norm(src1_roi, src2_roi, type)); + OCL_ON(const double gpuRes = cv::norm(usrc1_roi, usrc2_roi, type)); + + EXPECT_PRED3(relativeError, cpuRes, gpuRes, 1e-6); + } +} + //////////////////////////////////////// Instantiation ///////////////////////////////////////// OCL_INSTANTIATE_TEST_CASE_P(Arithm, Lut, Combine(::testing::Values(CV_8U, CV_8S), OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool(), Bool())); @@ -977,10 +1115,10 @@ OCL_INSTANTIATE_TEST_CASE_P(Arithm, Absdiff, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHA OCL_INSTANTIATE_TEST_CASE_P(Arithm, CartToPolar, Combine(testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, PolarToCart, Combine(testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Transpose, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); -//OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_and, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); -//OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_not, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); -//OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_xor, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); -//OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_or, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_and, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_not, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_xor, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Bitwise_or, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Pow, Combine(testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Compare, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, AddWeighted, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); @@ -993,6 +1131,8 @@ OCL_INSTANTIATE_TEST_CASE_P(Arithm, Log, Combine(::testing::Values(CV_32F, CV_64 OCL_INSTANTIATE_TEST_CASE_P(Arithm, Exp, Combine(::testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Phase, Combine(::testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); OCL_INSTANTIATE_TEST_CASE_P(Arithm, Magnitude, Combine(::testing::Values(CV_32F, CV_64F), OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Flip, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Arithm, Norm, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); } } // namespace cvtest::ocl diff --git a/modules/core/test/ocl/test_split_merge.cpp b/modules/core/test/ocl/test_split_merge.cpp new file mode 100644 index 0000000000..0fa0b1958a --- /dev/null +++ b/modules/core/test/ocl/test_split_merge.cpp @@ -0,0 +1,222 @@ +/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Jia Haipeng, jiahaipeng95@gmail.com +// +// 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/ts/ocl_test.hpp" + +#ifdef HAVE_OPENCL + +namespace cvtest { +namespace ocl { + +PARAM_TEST_CASE(MergeTestBase, MatDepth, Channels, bool) +{ + int depth, cn; + bool use_roi; + + TEST_DECLARE_INPUT_PARAMETER(src1) + TEST_DECLARE_INPUT_PARAMETER(src2) + TEST_DECLARE_INPUT_PARAMETER(src3) + TEST_DECLARE_INPUT_PARAMETER(src4) + TEST_DECLARE_OUTPUT_PARAMETER(dst) + + std::vector src_roi; + std::vector usrc_roi; + + virtual void SetUp() + { + depth = GET_PARAM(0); + cn = GET_PARAM(1); + use_roi = GET_PARAM(2); + + CV_Assert(cn >= 1 && cn <= 4); + } + + void random_roi() + { + Size roiSize = randomSize(1, MAX_VALUE); + + { + Border src1Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(src1, src1_roi, roiSize, src1Border, depth, 2, 11); + + Border src2Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(src2, src2_roi, roiSize, src2Border, depth, -1540, 1740); + + Border src3Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(src3, src3_roi, roiSize, src3Border, depth, -1540, 1740); + + Border src4Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(src4, src4_roi, roiSize, src4Border, depth, -1540, 1740); + } + + Border dstBorder = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(dst, dst_roi, roiSize, dstBorder, CV_MAKE_TYPE(depth, cn), 5, 16); + + UMAT_UPLOAD_INPUT_PARAMETER(src1) + UMAT_UPLOAD_INPUT_PARAMETER(src2) + UMAT_UPLOAD_INPUT_PARAMETER(src3) + UMAT_UPLOAD_INPUT_PARAMETER(src4) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst) + + src_roi.push_back(src1_roi), usrc_roi.push_back(usrc1_roi); + if (cn >= 2) + src_roi.push_back(src2_roi), usrc_roi.push_back(usrc2_roi); + if (cn >= 3) + src_roi.push_back(src3_roi), usrc_roi.push_back(usrc3_roi); + if (cn >= 4) + src_roi.push_back(src4_roi), usrc_roi.push_back(usrc4_roi); + } + + void Near(double threshold = 0.) + { + OCL_EXPECT_MATS_NEAR(dst, threshold); + } +}; + +typedef MergeTestBase Merge; + +OCL_TEST_P(Merge, Accuracy) +{ + for(int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::merge(src_roi, dst_roi)); + OCL_ON(cv::merge(usrc_roi, udst_roi)); + + Near(); + } +} + +PARAM_TEST_CASE(SplitTestBase, MatType, Channels, bool) +{ + int depth, cn; + bool use_roi; + + TEST_DECLARE_INPUT_PARAMETER(src) + TEST_DECLARE_OUTPUT_PARAMETER(dst1) + TEST_DECLARE_OUTPUT_PARAMETER(dst2) + TEST_DECLARE_OUTPUT_PARAMETER(dst3) + TEST_DECLARE_OUTPUT_PARAMETER(dst4) + + std::vector dst_roi, dst; + std::vector udst_roi, udst; + + virtual void SetUp() + { + depth = GET_PARAM(0); + cn = GET_PARAM(1); + use_roi = GET_PARAM(2); + + CV_Assert(cn >= 1 && cn <= 4); + } + + void random_roi() + { + Size roiSize = randomSize(1, MAX_VALUE); + Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(src, src_roi, roiSize, srcBorder, CV_MAKE_TYPE(depth, cn), 5, 16); + + { + Border dst1Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(dst1, dst1_roi, roiSize, dst1Border, depth, 2, 11); + + Border dst2Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(dst2, dst2_roi, roiSize, dst2Border, depth, -1540, 1740); + + Border dst3Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(dst3, dst3_roi, roiSize, dst3Border, depth, -1540, 1740); + + Border dst4Border = randomBorder(0, use_roi ? MAX_VALUE : 0); + randomSubMat(dst4, dst4_roi, roiSize, dst4Border, depth, -1540, 1740); + } + + UMAT_UPLOAD_INPUT_PARAMETER(src) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst1) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst2) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst3) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst4) + + dst_roi.push_back(dst1_roi), udst_roi.push_back(udst1_roi), + dst.push_back(dst1), udst.push_back(udst1); + if (cn >= 2) + dst_roi.push_back(dst2_roi), udst_roi.push_back(udst2_roi), + dst.push_back(dst2), udst.push_back(udst2); + if (cn >= 3) + dst_roi.push_back(dst3_roi), udst_roi.push_back(udst3_roi), + dst.push_back(dst3), udst.push_back(udst3); + if (cn >= 4) + dst_roi.push_back(dst4_roi), udst_roi.push_back(udst4_roi), + dst.push_back(dst4), udst.push_back(udst4); + } +}; + +typedef SplitTestBase Split; + +OCL_TEST_P(Split, Accuracy) +{ + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::split(src_roi, dst_roi)); + OCL_ON(cv::split(usrc_roi, udst_roi)); + + for (int i = 0; i < cn; ++i) + { + EXPECT_MAT_NEAR(dst[i], udst[i], 0.0); + EXPECT_MAT_NEAR(dst_roi[i], udst_roi[i], 0.0); + } + } +} + +OCL_INSTANTIATE_TEST_CASE_P(SplitMerge, Merge, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); +OCL_INSTANTIATE_TEST_CASE_P(SplitMerge, Split, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, Bool())); + +} } // namespace cvtest::ocl + +#endif // HAVE_OPENCL diff --git a/modules/cudaimgproc/src/color.cpp b/modules/cudaimgproc/src/color.cpp index 955c5ef374..a06b746a7f 100644 --- a/modules/cudaimgproc/src/color.cpp +++ b/modules/cudaimgproc/src/color.cpp @@ -2110,6 +2110,8 @@ void cv::cuda::cvtColor(InputArray src, OutputArray dst, int code, int dcn, Stre void cv::cuda::demosaicing(InputArray _src, OutputArray _dst, int code, int dcn, Stream& stream) { + CV_Assert( !_src.empty() ); + switch (code) { case cv::COLOR_BayerBG2GRAY: case cv::COLOR_BayerGB2GRAY: case cv::COLOR_BayerRG2GRAY: case cv::COLOR_BayerGR2GRAY: diff --git a/modules/cudaimgproc/test/test_color.cpp b/modules/cudaimgproc/test/test_color.cpp index 6816cc8fd8..9188725020 100644 --- a/modules/cudaimgproc/test/test_color.cpp +++ b/modules/cudaimgproc/test/test_color.cpp @@ -2357,6 +2357,7 @@ struct Demosaicing : testing::TestWithParam CUDA_TEST_P(Demosaicing, BayerBG2BGR) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(1, 1)); @@ -2370,6 +2371,7 @@ CUDA_TEST_P(Demosaicing, BayerBG2BGR) CUDA_TEST_P(Demosaicing, BayerGB2BGR) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(0, 1)); @@ -2383,6 +2385,7 @@ CUDA_TEST_P(Demosaicing, BayerGB2BGR) CUDA_TEST_P(Demosaicing, BayerRG2BGR) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(0, 0)); @@ -2396,6 +2399,7 @@ CUDA_TEST_P(Demosaicing, BayerRG2BGR) CUDA_TEST_P(Demosaicing, BayerGR2BGR) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(1, 0)); @@ -2409,6 +2413,7 @@ CUDA_TEST_P(Demosaicing, BayerGR2BGR) CUDA_TEST_P(Demosaicing, BayerBG2BGR_MHT) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(1, 1)); @@ -2422,6 +2427,7 @@ CUDA_TEST_P(Demosaicing, BayerBG2BGR_MHT) CUDA_TEST_P(Demosaicing, BayerGB2BGR_MHT) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(0, 1)); @@ -2435,6 +2441,7 @@ CUDA_TEST_P(Demosaicing, BayerGB2BGR_MHT) CUDA_TEST_P(Demosaicing, BayerRG2BGR_MHT) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(0, 0)); @@ -2448,6 +2455,7 @@ CUDA_TEST_P(Demosaicing, BayerRG2BGR_MHT) CUDA_TEST_P(Demosaicing, BayerGR2BGR_MHT) { cv::Mat img = readImage("stereobm/aloe-L.png"); + ASSERT_FALSE(img.empty()) << "Can't load input image"; cv::Mat_ src; mosaic(img, src, cv::Point(1, 0)); diff --git a/modules/features2d/src/orb.cpp b/modules/features2d/src/orb.cpp index a6e8ffab3c..263c27350b 100644 --- a/modules/features2d/src/orb.cpp +++ b/modules/features2d/src/orb.cpp @@ -141,12 +141,12 @@ static void computeOrbDescriptor(const KeyPoint& kpt, float x, y; int ix, iy; #if 1 -#define GET_VALUE(idx) \ - (x = pattern[idx].x*a - pattern[idx].y*b, \ - y = pattern[idx].x*b + pattern[idx].y*a, \ - ix = cvRound(x), \ - iy = cvRound(y), \ - *(center + iy*step + ix) ) + #define GET_VALUE(idx) \ + (x = pattern[idx].x*a - pattern[idx].y*b, \ + y = pattern[idx].x*b + pattern[idx].y*a, \ + ix = cvRound(x), \ + iy = cvRound(y), \ + *(center + iy*step + ix) ) #else #define GET_VALUE(idx) \ (x = pattern[idx].x*a - pattern[idx].y*b, \ diff --git a/modules/highgui/src/cap_openni.cpp b/modules/highgui/src/cap_openni.cpp index c509c1e657..cc68a23bfa 100644 --- a/modules/highgui/src/cap_openni.cpp +++ b/modules/highgui/src/cap_openni.cpp @@ -152,7 +152,7 @@ public: task = new( tbb::task::allocate_root() ) TBBApproximateSynchronizerTask( *this ); tbb::task::enqueue(*task); #else - task->reset( new ApproximateSynchronizer( *this ) ); + task.reset( new ApproximateSynchronizer( *this ) ); #endif } diff --git a/modules/highgui/src/window_gtk.cpp b/modules/highgui/src/window_gtk.cpp index 79ae638cfc..02c2564446 100644 --- a/modules/highgui/src/window_gtk.cpp +++ b/modules/highgui/src/window_gtk.cpp @@ -1552,9 +1552,9 @@ static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_da // image origin is not necessarily at (0,0) int x0 = (widget->allocation.width - image_widget->scaled_image->cols)/2; int y0 = (widget->allocation.height - image_widget->scaled_image->rows)/2; - pt.x = cvRound( ((pt32f.x-x0)*image_widget->original_image->cols)/ + pt.x = cvFloor( ((pt32f.x-x0)*image_widget->original_image->cols)/ image_widget->scaled_image->cols ); - pt.y = cvRound( ((pt32f.y-y0)*image_widget->original_image->rows)/ + pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/ image_widget->scaled_image->rows ); } else{ diff --git a/modules/imgproc/doc/miscellaneous_transformations.rst b/modules/imgproc/doc/miscellaneous_transformations.rst index 47de0b442d..df63c929b5 100644 --- a/modules/imgproc/doc/miscellaneous_transformations.rst +++ b/modules/imgproc/doc/miscellaneous_transformations.rst @@ -596,15 +596,15 @@ Calculates the integral of an image. .. ocv:function:: void integral( InputArray src, OutputArray sum, int sdepth=-1 ) -.. ocv:function:: void integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth=-1 ) +.. ocv:function:: void integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth=-1, int sqdepth=-1 ) -.. ocv:function:: void integral( InputArray src, OutputArray sum, OutputArray sqsum, OutputArray tilted, int sdepth=-1 ) +.. ocv:function:: void integral( InputArray src, OutputArray sum, OutputArray sqsum, OutputArray tilted, int sdepth=-1, int sqdepth=-1 ) .. ocv:pyfunction:: cv2.integral(src[, sum[, sdepth]]) -> sum -.. ocv:pyfunction:: cv2.integral2(src[, sum[, sqsum[, sdepth]]]) -> sum, sqsum +.. ocv:pyfunction:: cv2.integral2(src[, sum[, sqsum[, sdepth[, sqdepth]]]]) -> sum, sqsum -.. ocv:pyfunction:: cv2.integral3(src[, sum[, sqsum[, tilted[, sdepth]]]]) -> sum, sqsum, tilted +.. ocv:pyfunction:: cv2.integral3(src[, sum[, sqsum[, tilted[, sdepth[, sqdepth]]]]]) -> sum, sqsum, tilted .. ocv:cfunction:: void cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum=NULL, CvArr* tilted_sum=NULL ) @@ -618,6 +618,8 @@ Calculates the integral of an image. :param sdepth: desired depth of the integral and the tilted integral images, ``CV_32S``, ``CV_32F``, or ``CV_64F``. + :param sqdepth: desired depth of the integral image of squared pixel values, ``CV_32F`` or ``CV_64F``. + The functions calculate one or more integral images for the source image as follows: .. math:: diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 25f9797299..8980f3a9cc 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1241,12 +1241,12 @@ CV_EXPORTS_W void integral( InputArray src, OutputArray sum, int sdepth = -1 ); //! computes the integral image and integral for the squared image CV_EXPORTS_AS(integral2) void integral( InputArray src, OutputArray sum, - OutputArray sqsum, int sdepth = -1 ); + OutputArray sqsum, int sdepth = -1, int sqdepth = -1 ); //! computes the integral image, integral for the squared image and the tilted integral image CV_EXPORTS_AS(integral3) void integral( InputArray src, OutputArray sum, OutputArray sqsum, OutputArray tilted, - int sdepth = -1 ); + int sdepth = -1, int sqdepth = -1 ); //! adds image to the accumulator (dst += src). Unlike cv::add, dst and src can have different types. CV_EXPORTS_W void accumulate( InputArray src, InputOutputArray dst, @@ -1512,6 +1512,9 @@ CV_EXPORTS Ptr createGeneralizedHoughBallard(); //! Detects position, traslation and rotation CV_EXPORTS Ptr createGeneralizedHoughGuil(); +//! Performs linear blending of two images +CV_EXPORTS void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst); + } // cv #endif diff --git a/modules/imgproc/src/blend.cpp b/modules/imgproc/src/blend.cpp new file mode 100644 index 0000000000..91b261dfa6 --- /dev/null +++ b/modules/imgproc/src/blend.cpp @@ -0,0 +1,145 @@ +/*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) 2010-2012, Multicoreware, Inc., all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Nathan, liujun@multicorewareinc.com +// +// 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 "opencl_kernels.hpp" + +namespace cv { + +template +class BlendLinearInvoker : + public ParallelLoopBody +{ +public: + BlendLinearInvoker(const Mat & _src1, const Mat & _src2, const Mat & _weights1, + const Mat & _weights2, Mat & _dst) : + src1(&_src1), src2(&_src2), weights1(&_weights1), weights2(&_weights2), dst(&_dst) + { + } + + virtual void operator() (const Range & range) const + { + int cn = src1->channels(), width = src1->cols * cn; + + for (int y = range.start; y < range.end; ++y) + { + const float * const weights1_row = weights1->ptr(y); + const float * const weights2_row = weights2->ptr(y); + const T * const src1_row = src1->ptr(y); + const T * const src2_row = src2->ptr(y); + T * const dst_row = dst->ptr(y); + + for (int x = 0; x < width; ++x) + { + int x1 = x / cn; + float w1 = weights1_row[x1], w2 = weights2_row[x1]; + float den = (w1 + w2 + 1e-5f); + float num = (src1_row[x] * w1 + src2_row[x] * w2); + + dst_row[x] = saturate_cast(num / den); + } + } + } + +private: + const BlendLinearInvoker & operator= (const BlendLinearInvoker &); + BlendLinearInvoker(const BlendLinearInvoker &); + + const Mat * src1, * src2, * weights1, * weights2; + Mat * dst; +}; + +static bool ocl_blendLinear( InputArray _src1, InputArray _src2, InputArray _weights1, InputArray _weights2, OutputArray _dst ) +{ + int type = _src1.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); + + char cvt[30]; + ocl::Kernel k("blendLinear", ocl::imgproc::blend_linear_oclsrc, + format("-D T=%s -D cn=%d -D convertToT=%s", ocl::typeToStr(depth), + cn, ocl::convertTypeStr(CV_32F, depth, 1, cvt))); + if (k.empty()) + return false; + + UMat src1 = _src1.getUMat(), src2 = _src2.getUMat(), weights1 = _weights1.getUMat(), + weights2 = _weights2.getUMat(), dst = _dst.getUMat(); + + k.args(ocl::KernelArg::ReadOnlyNoSize(src1), ocl::KernelArg::ReadOnlyNoSize(src2), + ocl::KernelArg::ReadOnlyNoSize(weights1), ocl::KernelArg::ReadOnlyNoSize(weights2), + ocl::KernelArg::WriteOnly(dst)); + + size_t globalsize[2] = { dst.cols, dst.rows }; + return k.run(2, globalsize, NULL, false); +} + +} + +void cv::blendLinear( InputArray _src1, InputArray _src2, InputArray _weights1, InputArray _weights2, OutputArray _dst ) +{ + int type = _src1.type(), depth = CV_MAT_DEPTH(type); + Size size = _src1.size(); + + CV_Assert(depth == CV_8U || depth == CV_32F); + CV_Assert(size == _src2.size() && size == _weights1.size() && size == _weights2.size()); + CV_Assert(type == _src2.type() && _weights1.type() == CV_32FC1 && _weights2.type() == CV_32FC1); + + _dst.create(size, type); + + if (ocl::useOpenCL() && _dst.isUMat() && ocl_blendLinear(_src1, _src2, _weights1, _weights2, _dst)) + return; + + Mat src1 = _src1.getMat(), src2 = _src2.getMat(), weights1 = _weights1.getMat(), + weights2 = _weights2.getMat(), dst = _dst.getMat(); + + if (depth == CV_8U) + { + BlendLinearInvoker invoker(src1, src2, weights1, weights2, dst); + parallel_for_(Range(0, src1.rows), invoker, dst.total()/(double)(1<<16)); + } + else if (depth == CV_32F) + { + BlendLinearInvoker invoker(src1, src2, weights1, weights2, dst); + parallel_for_(Range(0, src1.rows), invoker, dst.total()/(double)(1<<16)); + } +} diff --git a/modules/imgproc/src/deriv.cpp b/modules/imgproc/src/deriv.cpp index eca0db3fde..bc11b24635 100644 --- a/modules/imgproc/src/deriv.cpp +++ b/modules/imgproc/src/deriv.cpp @@ -413,15 +413,15 @@ static bool IPPDeriv(const Mat& src, Mat& dst, int ddepth, int dx, int dy, int k void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType ) { - Mat src = _src.getMat(); + int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype); if (ddepth < 0) - ddepth = src.depth(); - _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); - Mat dst = _dst.getMat(); + ddepth = sdepth; + _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) ); #ifdef HAVE_TEGRA_OPTIMIZATION if (scale == 1.0 && delta == 0) { + Mat src = _src.getMat(), dst = _dst.getMat(); if (ksize == 3 && tegra::sobel3x3(src, dst, dx, dy, borderType)) return; if (ksize == -1 && tegra::scharr(src, dst, dx, dy, borderType)) @@ -430,13 +430,14 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, #endif #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) - if(dx < 3 && dy < 3 && src.channels() == 1 && borderType == 1) + if(dx < 3 && dy < 3 && cn == 1 && borderType == BORDER_REPLICATE) { + Mat src = _src.getMat(), dst = _dst.getMat(); if(IPPDeriv(src, dst, ddepth, dx, dy, ksize,scale)) return; } #endif - int ktype = std::max(CV_32F, std::max(ddepth, src.depth())); + int ktype = std::max(CV_32F, std::max(ddepth, sdepth)); Mat kx, ky; getDerivKernels( kx, ky, dx, dy, ksize, false, ktype ); @@ -449,33 +450,36 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, else ky *= scale; } - sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType ); + sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType ); } void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType ) { - Mat src = _src.getMat(); + int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype); if (ddepth < 0) - ddepth = src.depth(); - _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); - Mat dst = _dst.getMat(); + ddepth = sdepth; + _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) ); #ifdef HAVE_TEGRA_OPTIMIZATION if (scale == 1.0 && delta == 0) + { + Mat src = _src.getMat(), dst = _dst.getMat(); if (tegra::scharr(src, dst, dx, dy, borderType)) return; + } #endif #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) if(dx < 2 && dy < 2 && src.channels() == 1 && borderType == 1) { + Mat src = _src.getMat(), dst = _dst.getMat(); if(IPPDerivScharr(src, dst, ddepth, dx, dy, scale)) return; } #endif - int ktype = std::max(CV_32F, std::max(ddepth, src.depth())); + int ktype = std::max(CV_32F, std::max(ddepth, sdepth)); Mat kx, ky; getScharrKernels( kx, ky, dx, dy, false, ktype ); @@ -488,22 +492,22 @@ void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, else ky *= scale; } - sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType ); + sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType ); } void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize, double scale, double delta, int borderType ) { - Mat src = _src.getMat(); + int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype); if (ddepth < 0) - ddepth = src.depth(); - _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) ); - Mat dst = _dst.getMat(); + ddepth = sdepth; + _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) ); #ifdef HAVE_TEGRA_OPTIMIZATION if (scale == 1.0 && delta == 0) { + Mat src = _src.getMat(), dst = _dst.getMat(); if (ksize == 1 && tegra::laplace1(src, dst, borderType)) return; if (ksize == 3 && tegra::laplace3(src, dst, borderType)) @@ -516,15 +520,18 @@ void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize, if( ksize == 1 || ksize == 3 ) { float K[2][9] = - {{0, 1, 0, 1, -4, 1, 0, 1, 0}, - {2, 0, 2, 0, -8, 0, 2, 0, 2}}; + { + { 0, 1, 0, 1, -4, 1, 0, 1, 0 }, + { 2, 0, 2, 0, -8, 0, 2, 0, 2 } + }; Mat kernel(3, 3, CV_32F, K[ksize == 3]); if( scale != 1 ) kernel *= scale; - filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType ); + filter2D( _src, _dst, ddepth, kernel, Point(-1, -1), delta, borderType ); } else { + Mat src = _src.getMat(), dst = _dst.getMat(); const size_t STRIPE_SIZE = 1 << 14; int depth = src.depth(); diff --git a/modules/imgproc/src/filter.cpp b/modules/imgproc/src/filter.cpp index fbf1de2479..d548168491 100644 --- a/modules/imgproc/src/filter.cpp +++ b/modules/imgproc/src/filter.cpp @@ -41,6 +41,7 @@ //M*/ #include "precomp.hpp" +#include "opencl_kernels.hpp" /****************************************************************************************\ Base Image Filter @@ -3115,6 +3116,206 @@ template struct Filter2D : public BaseFi } +namespace cv +{ + +#define DIVUP(total, grain) (((total) + (grain) - 1) / (grain)) +#define ROUNDUP(sz, n) ((sz) + (n) - 1 - (((sz) + (n) - 1) % (n))) + +// prepare kernel: transpose and make double rows (+align). Returns size of aligned row +// Samples: +// a b c +// Input: d e f +// g h i +// Output, last two zeros is the alignment: +// a d g a d g 0 0 +// b e h b e h 0 0 +// c f i c f i 0 0 +template +static int _prepareKernelFilter2D(std::vector& data, const Mat &kernel) +{ + Mat _kernel; kernel.convertTo(_kernel, DataDepth::value); + int size_y_aligned = ROUNDUP(kernel.rows * 2, 4); + data.clear(); data.resize(size_y_aligned * kernel.cols, 0); + for (int x = 0; x < kernel.cols; x++) + { + for (int y = 0; y < kernel.rows; y++) + { + data[x * size_y_aligned + y] = _kernel.at(y, x); + data[x * size_y_aligned + y + kernel.rows] = _kernel.at(y, x); + } + } + return size_y_aligned; +} + +static bool ocl_filter2D( InputArray _src, OutputArray _dst, int ddepth, + InputArray _kernel, Point anchor, + double delta, int borderType ) +{ + if (abs(delta) > FLT_MIN) + return false; + + int type = _src.type(); + int cn = CV_MAT_CN(type); + if ((1 != cn) && (2 != cn) && (4 != cn)) + return false;//TODO + + int sdepth = CV_MAT_DEPTH(type); + Size ksize = _kernel.size(); + if( anchor.x < 0 ) + anchor.x = ksize.width / 2; + if( anchor.y < 0 ) + anchor.y = ksize.height / 2; + if( ddepth < 0 ) + ddepth = sdepth; + else if (ddepth != sdepth) + return false; + + bool isIsolatedBorder = (borderType & BORDER_ISOLATED) != 0; + bool useDouble = (CV_64F == sdepth); + const cv::ocl::Device &device = cv::ocl::Device::getDefault(); + int doubleFPConfig = device.doubleFPConfig(); + if (useDouble && (0 == doubleFPConfig)) + return false; + + const char* btype = NULL; + switch (borderType & ~BORDER_ISOLATED) + { + case BORDER_CONSTANT: + btype = "BORDER_CONSTANT"; + break; + case BORDER_REPLICATE: + btype = "BORDER_REPLICATE"; + break; + case BORDER_REFLECT: + btype = "BORDER_REFLECT"; + break; + case BORDER_WRAP: + return false; + case BORDER_REFLECT101: + btype = "BORDER_REFLECT_101"; + break; + } + + cv::Mat kernelMat = _kernel.getMat(); + std::vector kernelMatDataFloat; + std::vector kernelMatDataDouble; + int kernel_size_y2_aligned = useDouble ? + _prepareKernelFilter2D(kernelMatDataDouble, kernelMat) + : _prepareKernelFilter2D(kernelMatDataFloat, kernelMat); + + + cv::Size sz = _src.size(); + size_t globalsize[2] = {sz.width, sz.height}; + size_t localsize[2] = {0, 1}; + + ocl::Kernel kernel; + UMat src; Size wholeSize; + if (!isIsolatedBorder) + { + src = _src.getUMat(); + Point ofs; + src.locateROI(wholeSize, ofs); + } + + size_t maxWorkItemSizes[32]; device.maxWorkItemSizes(maxWorkItemSizes); + size_t tryWorkItems = maxWorkItemSizes[0]; + for (;;) + { + size_t BLOCK_SIZE = tryWorkItems; + while (BLOCK_SIZE > 32 && BLOCK_SIZE >= (size_t)ksize.width * 2 && BLOCK_SIZE > (size_t)sz.width * 2) + BLOCK_SIZE /= 2; +#if 1 // TODO Mode with several blocks requires a much more VGPRs, so this optimization is not actual for the current devices + size_t BLOCK_SIZE_Y = 1; +#else + size_t BLOCK_SIZE_Y = 8; // TODO Check heuristic value on devices + while (BLOCK_SIZE_Y < BLOCK_SIZE / 8 && BLOCK_SIZE_Y * src.clCxt->getDeviceInfo().maxComputeUnits * 32 < (size_t)src.rows) + BLOCK_SIZE_Y *= 2; +#endif + + if ((size_t)ksize.width > BLOCK_SIZE) + return false; + + int requiredTop = anchor.y; + int requiredLeft = (int)BLOCK_SIZE; // not this: anchor.x; + int requiredBottom = ksize.height - 1 - anchor.y; + int requiredRight = (int)BLOCK_SIZE; // not this: ksize.width - 1 - anchor.x; + int h = isIsolatedBorder ? sz.height : wholeSize.height; + int w = isIsolatedBorder ? sz.width : wholeSize.width; + bool extra_extrapolation = h < requiredTop || h < requiredBottom || w < requiredLeft || w < requiredRight; + + if ((w < ksize.width) || (h < ksize.height)) + return false; + + char build_options[1024]; + sprintf(build_options, "-D LOCAL_SIZE=%d -D BLOCK_SIZE_Y=%d -D DATA_DEPTH=%d -D DATA_CHAN=%d -D USE_DOUBLE=%d " + "-D ANCHOR_X=%d -D ANCHOR_Y=%d -D KERNEL_SIZE_X=%d -D KERNEL_SIZE_Y=%d -D KERNEL_SIZE_Y2_ALIGNED=%d " + "-D %s -D %s -D %s", + (int)BLOCK_SIZE, (int)BLOCK_SIZE_Y, + sdepth, cn, useDouble ? 1 : 0, + anchor.x, anchor.y, ksize.width, ksize.height, kernel_size_y2_aligned, + btype, + extra_extrapolation ? "EXTRA_EXTRAPOLATION" : "NO_EXTRA_EXTRAPOLATION", + isIsolatedBorder ? "BORDER_ISOLATED" : "NO_BORDER_ISOLATED"); + + localsize[0] = BLOCK_SIZE; + globalsize[0] = DIVUP(sz.width, BLOCK_SIZE - (ksize.width - 1)) * BLOCK_SIZE; + globalsize[1] = DIVUP(sz.height, BLOCK_SIZE_Y); + + cv::String errmsg; + if (!kernel.create("filter2D", cv::ocl::imgproc::filter2D_oclsrc, build_options)) + return false; + size_t kernelWorkGroupSize = kernel.workGroupSize(); + if (localsize[0] <= kernelWorkGroupSize) + break; + if (BLOCK_SIZE < kernelWorkGroupSize) + return false; + tryWorkItems = kernelWorkGroupSize; + } + + _dst.create(sz, CV_MAKETYPE(ddepth, cn)); + UMat dst = _dst.getUMat(); + if (src.empty()) + src = _src.getUMat(); + + int idxArg = 0; + idxArg = kernel.set(idxArg, ocl::KernelArg::PtrReadOnly(src)); + idxArg = kernel.set(idxArg, (int)src.step); + + int srcOffsetX = (int)((src.offset % src.step) / src.elemSize()); + int srcOffsetY = (int)(src.offset / src.step); + int srcEndX = (isIsolatedBorder ? (srcOffsetX + sz.width) : wholeSize.width); + int srcEndY = (isIsolatedBorder ? (srcOffsetY + sz.height) : wholeSize.height); + idxArg = kernel.set(idxArg, srcOffsetX); + idxArg = kernel.set(idxArg, srcOffsetY); + idxArg = kernel.set(idxArg, srcEndX); + idxArg = kernel.set(idxArg, srcEndY); + + idxArg = kernel.set(idxArg, ocl::KernelArg::WriteOnly(dst)); + float borderValue[4] = {0, 0, 0, 0}; + double borderValueDouble[4] = {0, 0, 0, 0}; + if ((borderType & ~BORDER_ISOLATED) == BORDER_CONSTANT) + { + int cnocl = (3 == cn) ? 4 : cn; + if (useDouble) + idxArg = kernel.set(idxArg, (void *)&borderValueDouble[0], sizeof(double) * cnocl); + else + idxArg = kernel.set(idxArg, (void *)&borderValue[0], sizeof(float) * cnocl); + } + if (useDouble) + { + UMat kernalDataUMat(kernelMatDataDouble, true); + idxArg = kernel.set(idxArg, ocl::KernelArg::PtrReadOnly(kernalDataUMat)); + } + else + { + UMat kernalDataUMat(kernelMatDataFloat, true); + idxArg = kernel.set(idxArg, ocl::KernelArg::PtrReadOnly(kernalDataUMat)); + } + return kernel.run(2, globalsize, localsize, true); +} +} + cv::Ptr cv::getLinearFilter(int srcType, int dstType, InputArray filter_kernel, Point anchor, double delta, int bits) @@ -3230,6 +3431,10 @@ void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth, InputArray _kernel, Point anchor, double delta, int borderType ) { + bool use_opencl = ocl::useOpenCL() && _dst.isUMat(); + if( use_opencl && ocl_filter2D(_src, _dst, ddepth, _kernel, anchor, delta, borderType)) + return; + Mat src = _src.getMat(), kernel = _kernel.getMat(); if( ddepth < 0 ) diff --git a/modules/imgproc/src/opencl/bilateral.cl b/modules/imgproc/src/opencl/bilateral.cl new file mode 100644 index 0000000000..f459cfc850 --- /dev/null +++ b/modules/imgproc/src/opencl/bilateral.cl @@ -0,0 +1,59 @@ +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Rock Li, Rock.li@amd.com +// +// 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. + +__kernel void bilateral(__global const uchar * src, int src_step, int src_offset, + __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols, + __constant float * color_weight, __constant float * space_weight, __constant int * space_ofs) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (y < dst_rows && x < dst_cols) + { + int src_index = mad24(y + radius, src_step, x + radius + src_offset); + int dst_index = mad24(y, dst_step, x + dst_offset); + float sum = 0.f, wsum = 0.f; + int val0 = convert_int(src[src_index]); + + #pragma unroll + for (int k = 0; k < maxk; k++ ) + { + int val = convert_int(src[src_index + space_ofs[k]]); + float w = space_weight[k] * color_weight[abs(val - val0)]; + sum += (float)(val) * w; + wsum += w; + } + dst[dst_index] = convert_uchar_rtz(sum / wsum + 0.5f); + } +} diff --git a/modules/imgproc/src/opencl/blend_linear.cl b/modules/imgproc/src/opencl/blend_linear.cl new file mode 100644 index 0000000000..0644cae802 --- /dev/null +++ b/modules/imgproc/src/opencl/blend_linear.cl @@ -0,0 +1,88 @@ +/*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) 2010-2012, MulticoreWare Inc., all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Liu Liujun, liujun@multicorewareinc.com +// +// 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*/ + +#ifdef DOUBLE_SUPPORT +#ifdef cl_amd_fp64 +#pragma OPENCL EXTENSION cl_amd_fp64:enable +#elif defined (cl_khr_fp64) +#pragma OPENCL EXTENSION cl_khr_fp64:enable +#endif +#endif + +#define noconvert + +__kernel void blendLinear(__global const uchar * src1ptr, int src1_step, int src1_offset, + __global const uchar * src2ptr, int src2_step, int src2_offset, + __global const uchar * weight1, int weight1_step, int weight1_offset, + __global const uchar * weight2, int weight2_step, int weight2_offset, + __global uchar * dstptr, int dst_step, int dst_offset, int dst_rows, int dst_cols) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x < dst_cols && y < dst_rows) + { + int src1_index = mad24(y, src1_step, src1_offset + x * cn * (int)sizeof(T)); + int src2_index = mad24(y, src2_step, src2_offset + x * cn * (int)sizeof(T)); + int weight1_index = mad24(y, weight1_step, weight1_offset + x * (int)sizeof(float)); + int weight2_index = mad24(y, weight2_step, weight2_offset + x * (int)sizeof(float)); + int dst_index = mad24(y, dst_step, dst_offset + x * cn * (int)sizeof(T)); + + float w1 = *(__global const float *)(weight1 + weight1_index), + w2 = *(__global const float *)(weight2 + weight2_index); + float den = w1 + w2 + 1e-5f; + + __global const T * src1 = (__global const T *)(src1ptr + src1_index); + __global const T * src2 = (__global const T *)(src2ptr + src2_index); + __global T * dst = (__global T *)(dstptr + dst_index); + + #pragma unroll + for (int i = 0; i < cn; ++i) + { + float num = w1 * convert_float(src1[i]) + w2 * convert_float(src2[i]); + dst[i] = convertToT(num / den); + } + } +} diff --git a/modules/imgproc/src/opencl/filter2D.cl b/modules/imgproc/src/opencl/filter2D.cl new file mode 100644 index 0000000000..d360714971 --- /dev/null +++ b/modules/imgproc/src/opencl/filter2D.cl @@ -0,0 +1,375 @@ +/*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) 2010-2013, Advanced Micro Devices, Inc., 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*/ + +#ifdef BORDER_REPLICATE +//BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh +#define ADDR_L(i, l_edge, r_edge) ((i) < (l_edge) ? (l_edge) : (i)) +#define ADDR_R(i, r_edge, addr) ((i) >= (r_edge) ? (r_edge)-1 : (addr)) +#define ADDR_H(i, t_edge, b_edge) ((i) < (t_edge) ? (t_edge) :(i)) +#define ADDR_B(i, b_edge, addr) ((i) >= (b_edge) ? (b_edge)-1 :(addr)) +#endif + +#ifdef BORDER_REFLECT +//BORDER_REFLECT: fedcba|abcdefgh|hgfedcb +#define ADDR_L(i, l_edge, r_edge) ((i) < (l_edge) ? -(i)-1 : (i)) +#define ADDR_R(i, r_edge, addr) ((i) >= (r_edge) ? -(i)-1+((r_edge)<<1) : (addr)) +#define ADDR_H(i, t_edge, b_edge) ((i) < (t_edge) ? -(i)-1 : (i)) +#define ADDR_B(i, b_edge, addr) ((i) >= (b_edge) ? -(i)-1+((b_edge)<<1) : (addr)) +#endif + +#ifdef BORDER_REFLECT_101 +//BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba +#define ADDR_L(i, l_edge, r_edge) ((i) < (l_edge) ? -(i) : (i)) +#define ADDR_R(i, r_edge, addr) ((i) >= (r_edge) ? -(i)-2+((r_edge)<<1) : (addr)) +#define ADDR_H(i, t_edge, b_edge) ((i) < (t_edge) ? -(i) : (i)) +#define ADDR_B(i, b_edge, addr) ((i) >= (b_edge) ? -(i)-2+((b_edge)<<1) : (addr)) +#endif + +//blur function does not support BORDER_WRAP +#ifdef BORDER_WRAP +//BORDER_WRAP: cdefgh|abcdefgh|abcdefg +#define ADDR_L(i, l_edge, r_edge) ((i) < (l_edge) ? (i)+(r_edge) : (i)) +#define ADDR_R(i, r_edge, addr) ((i) >= (r_edge) ? (i)-(r_edge) : (addr)) +#define ADDR_H(i, t_edge, b_edge) ((i) < (t_edge) ? (i)+(b_edge) : (i)) +#define ADDR_B(i, b_edge, addr) ((i) >= (b_edge) ? (i)-(b_edge) : (addr)) +#endif + +#ifdef EXTRA_EXTRAPOLATION // border > src image size +#ifdef BORDER_CONSTANT +// None +#elif defined BORDER_REPLICATE +#define EXTRAPOLATE(x, y, minX, minY, maxX, maxY) \ + { \ + x = max(min(x, maxX - 1), minX); \ + y = max(min(y, maxY - 1), minY); \ + } +#elif defined BORDER_WRAP +#define EXTRAPOLATE(x, y, minX, minY, maxX, maxY) \ + { \ + if (x < minX) \ + x -= ((x - maxX + 1) / maxX) * maxX; \ + if (x >= maxX) \ + x %= maxX; \ + if (y < minY) \ + y -= ((y - maxY + 1) / maxY) * maxY; \ + if (y >= maxY) \ + y %= maxY; \ + } +#elif defined(BORDER_REFLECT) || defined(BORDER_REFLECT_101) +#define EXTRAPOLATE_(x, y, minX, minY, maxX, maxY, delta) \ + { \ + if (maxX - minX == 1) \ + x = minX; \ + else \ + do \ + { \ + if (x < minX) \ + x = minX - (x - minX) - 1 + delta; \ + else \ + x = maxX - 1 - (x - maxX) - delta; \ + } \ + while (x >= maxX || x < minX); \ + \ + if (maxY - minY == 1) \ + y = minY; \ + else \ + do \ + { \ + if (y < minY) \ + y = minY - (y - minY) - 1 + delta; \ + else \ + y = maxY - 1 - (y - maxY) - delta; \ + } \ + while (y >= maxY || y < minY); \ + } +#ifdef BORDER_REFLECT +#define EXTRAPOLATE(x, y, minX, minY, maxX, maxY) EXTRAPOLATE_(x, y, minX, minY, maxX, maxY, 0) +#elif defined(BORDER_REFLECT_101) +#define EXTRAPOLATE(x, y, minX, minY, maxX, maxY) EXTRAPOLATE_(x, y, minX, minY, maxX, maxY, 1) +#endif +#else +#error No extrapolation method +#endif +#else +#define EXTRAPOLATE(x, y, minX, minY, maxX, maxY) \ + { \ + int _row = y - minY, _col = x - minX; \ + _row = ADDR_H(_row, 0, maxY - minY); \ + _row = ADDR_B(_row, maxY - minY, _row); \ + y = _row + minY; \ + \ + _col = ADDR_L(_col, 0, maxX - minX); \ + _col = ADDR_R(_col, maxX - minX, _col); \ + x = _col + minX; \ + } +#endif + +#if USE_DOUBLE +#ifdef cl_amd_fp64 +#pragma OPENCL EXTENSION cl_amd_fp64:enable +#elif defined (cl_khr_fp64) +#pragma OPENCL EXTENSION cl_khr_fp64:enable +#endif +#define FPTYPE double +#define CONVERT_TO_FPTYPE CAT(convert_double, VEC_SIZE) +#else +#define FPTYPE float +#define CONVERT_TO_FPTYPE CAT(convert_float, VEC_SIZE) +#endif + +#if DATA_DEPTH == 0 +#define BASE_TYPE uchar +#elif DATA_DEPTH == 1 +#define BASE_TYPE char +#elif DATA_DEPTH == 2 +#define BASE_TYPE ushort +#elif DATA_DEPTH == 3 +#define BASE_TYPE short +#elif DATA_DEPTH == 4 +#define BASE_TYPE int +#elif DATA_DEPTH == 5 +#define BASE_TYPE float +#elif DATA_DEPTH == 6 +#define BASE_TYPE double +#else +#error data_depth +#endif + +#define __CAT(x, y) x##y +#define CAT(x, y) __CAT(x, y) + +#define uchar1 uchar +#define char1 char +#define ushort1 ushort +#define short1 short +#define int1 int +#define float1 float +#define double1 double + +#define convert_uchar1_sat_rte convert_uchar_sat_rte +#define convert_char1_sat_rte convert_char_sat_rte +#define convert_ushort1_sat_rte convert_ushort_sat_rte +#define convert_short1_sat_rte convert_short_sat_rte +#define convert_int1_sat_rte convert_int_sat_rte +#define convert_float1 +#define convert_double1 + +#if DATA_DEPTH == 5 || DATA_DEPTH == 6 +#define CONVERT_TO_TYPE CAT(CAT(convert_, BASE_TYPE), VEC_SIZE) +#else +#define CONVERT_TO_TYPE CAT(CAT(CAT(convert_, BASE_TYPE), VEC_SIZE), _sat_rte) +#endif + +#define VEC_SIZE DATA_CHAN + +#define VEC_TYPE CAT(BASE_TYPE, VEC_SIZE) +#define TYPE VEC_TYPE + +#define SCALAR_TYPE CAT(FPTYPE, VEC_SIZE) + +#define INTERMEDIATE_TYPE CAT(FPTYPE, VEC_SIZE) + +struct RectCoords +{ + int x1, y1, x2, y2; +}; + +//#define DEBUG +#ifdef DEBUG +#define DEBUG_ONLY(x) x +#define ASSERT(condition) do { if (!(condition)) { printf("BUG in boxFilter kernel (global=%d,%d): " #condition "\n", get_global_id(0), get_global_id(1)); } } while (0) +#else +#define DEBUG_ONLY(x) (void)0 +#define ASSERT(condition) (void)0 +#endif + + +inline INTERMEDIATE_TYPE readSrcPixel(int2 pos, __global const uchar* srcptr, int srcstep, const struct RectCoords srcCoords +#ifdef BORDER_CONSTANT + , SCALAR_TYPE borderValue +#endif + ) +{ +#ifdef BORDER_ISOLATED + if(pos.x >= srcCoords.x1 && pos.y >= srcCoords.y1 && pos.x < srcCoords.x2 && pos.y < srcCoords.y2) +#else + if(pos.x >= 0 && pos.y >= 0 && pos.x < srcCoords.x2 && pos.y < srcCoords.y2) +#endif + { + //__global TYPE* ptr = (__global TYPE*)((__global char*)src + pos.x * sizeof(TYPE) + pos.y * srcStepBytes); + __global TYPE* ptr = (__global TYPE*)(srcptr + pos.y * srcstep + pos.x * sizeof(TYPE)); + return CONVERT_TO_FPTYPE(*ptr); + } + else + { +#ifdef BORDER_CONSTANT + return borderValue; +#else + int selected_col = pos.x; + int selected_row = pos.y; + + EXTRAPOLATE(selected_col, selected_row, +#ifdef BORDER_ISOLATED + srcCoords.x1, srcCoords.y1, +#else + 0, 0, +#endif + srcCoords.x2, srcCoords.y2 + ); + + // debug border mapping + //printf("pos=%d,%d --> %d, %d\n", pos.x, pos.y, selected_col, selected_row); + + pos = (int2)(selected_col, selected_row); + if(pos.x >= 0 && pos.y >= 0 && pos.x < srcCoords.x2 && pos.y < srcCoords.y2) + { + //__global TYPE* ptr = (__global TYPE*)((__global char*)src + pos.x * sizeof(TYPE) + pos.y * srcStepBytes); + __global TYPE* ptr = (__global TYPE*)(srcptr + pos.y * srcstep + pos.x * sizeof(TYPE)); + return CONVERT_TO_FPTYPE(*ptr); + } + else + { + // for debug only + DEBUG_ONLY(printf("BUG in boxFilter kernel\n")); + return (FPTYPE)(0.0f); + } +#endif + } +} + +// INPUT PARAMETER: BLOCK_SIZE_Y (via defines) + +__kernel +__attribute__((reqd_work_group_size(LOCAL_SIZE, 1, 1))) +void filter2D(__global const uchar* srcptr, int srcstep, int srcOffsetX, int srcOffsetY, int srcEndX, int srcEndY, + __global uchar* dstptr, int dststep, int dstoffset, + int rows, int cols, +#ifdef BORDER_CONSTANT + SCALAR_TYPE borderValue, +#endif + __constant FPTYPE* kernelData // transposed: [KERNEL_SIZE_X][KERNEL_SIZE_Y2_ALIGNED] + ) +{ + const struct RectCoords srcCoords = {srcOffsetX, srcOffsetY, srcEndX, srcEndY}; // for non-isolated border: offsetX, offsetY, wholeX, wholeY + + const int local_id = get_local_id(0); + const int x = local_id + (LOCAL_SIZE - (KERNEL_SIZE_X - 1)) * get_group_id(0) - ANCHOR_X; + const int y = get_global_id(1) * BLOCK_SIZE_Y; + + INTERMEDIATE_TYPE data[KERNEL_SIZE_Y]; + __local INTERMEDIATE_TYPE sumOfCols[LOCAL_SIZE]; + + int2 srcPos = (int2)(srcCoords.x1 + x, srcCoords.y1 + y - ANCHOR_Y); + + int2 pos = (int2)(x, y); + __global TYPE* dstPtr = (__global TYPE*)((__global char*)dstptr + pos.y * dststep + dstoffset + pos.x * sizeof(TYPE)); // Pointer can be out of bounds! + bool writeResult = ((local_id >= ANCHOR_X) && (local_id < LOCAL_SIZE - (KERNEL_SIZE_X - 1 - ANCHOR_X)) && + (pos.x >= 0) && (pos.x < cols)); + +#if BLOCK_SIZE_Y > 1 + bool readAllpixels = true; + int sy_index = 0; // current index in data[] array + + dstRowsMax = min(rows, pos.y + BLOCK_SIZE_Y); + for (; + pos.y < dstRowsMax; + pos.y++, + dstPtr = (__global TYPE*)((__global char*)dstptr + dststep)) +#endif + { + ASSERT(pos.y < dstRowsMax); + + for ( +#if BLOCK_SIZE_Y > 1 + int sy = readAllpixels ? 0 : -1; sy < (readAllpixels ? KERNEL_SIZE_Y : 0); +#else + int sy = 0, sy_index = 0; sy < KERNEL_SIZE_Y; +#endif + sy++, srcPos.y++) + { + data[sy + sy_index] = readSrcPixel(srcPos, srcptr, srcstep, srcCoords +#ifdef BORDER_CONSTANT + , borderValue +#endif + ); + } + + INTERMEDIATE_TYPE total_sum = 0; + for (int sx = 0; sx < KERNEL_SIZE_X; sx++) + { + { + __constant FPTYPE* k = &kernelData[KERNEL_SIZE_Y2_ALIGNED * sx +#if BLOCK_SIZE_Y > 1 + + KERNEL_SIZE_Y - sy_index +#endif + ]; + INTERMEDIATE_TYPE tmp_sum = 0; + for (int sy = 0; sy < KERNEL_SIZE_Y; sy++) + { + tmp_sum += data[sy] * k[sy]; + } + + sumOfCols[local_id] = tmp_sum; + barrier(CLK_LOCAL_MEM_FENCE); + } + + int id = local_id + sx - ANCHOR_X; + if (id >= 0 && id < LOCAL_SIZE) + total_sum += sumOfCols[id]; + + barrier(CLK_LOCAL_MEM_FENCE); + } + + if (writeResult) + { + *dstPtr = CONVERT_TO_TYPE(total_sum); + } + +#if BLOCK_SIZE_Y > 1 + readAllpixels = false; +#if BLOCK_SIZE_Y > KERNEL_SIZE_Y + sy_index = (sy_index + 1 <= KERNEL_SIZE_Y) ? sy_index + 1 : 1; +#else + sy_index++; +#endif +#endif // BLOCK_SIZE_Y == 1 + } +} diff --git a/modules/imgproc/src/opencl/integral_sqrsum.cl b/modules/imgproc/src/opencl/integral_sqrsum.cl new file mode 100644 index 0000000000..8b5d2452b8 --- /dev/null +++ b/modules/imgproc/src/opencl/integral_sqrsum.cl @@ -0,0 +1,512 @@ +/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Shengen Yan,yanshengen@gmail.com +// +// 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*/ + +#ifdef DOUBLE_SUPPORT +#ifdef cl_amd_fp64 +#pragma OPENCL EXTENSION cl_amd_fp64:enable +#elif defined (cl_khr_fp64) +#pragma OPENCL EXTENSION cl_khr_fp64:enable +#endif +#endif + +#if sqdepth == 6 +#define CONVERT(step) ((step)>>1) +#else +#define CONVERT(step) ((step)) +#endif + +#define LSIZE 256 +#define LSIZE_1 255 +#define LSIZE_2 254 +#define HF_LSIZE 128 +#define LOG_LSIZE 8 +#define LOG_NUM_BANKS 5 +#define NUM_BANKS 32 +#define GET_CONFLICT_OFFSET(lid) ((lid) >> LOG_NUM_BANKS) + +#define noconvert + +#if sdepth == 4 + +kernel void integral_cols(__global uchar4 *src, __global int *sum, __global TYPE *sqsum, + int src_offset, int pre_invalid, int rows, int cols, int src_step, int dst_step, int dst1_step) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + int4 src_t[2], sum_t[2]; + TYPE4 sqsum_t[2]; + __local int4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local TYPE4 lm_sqsum[2][LSIZE + LOG_LSIZE]; + __local int* sum_p; + __local TYPE* sqsum_p; + src_step = src_step >> 2; + gid = gid << 1; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = (i + lid < rows ? convert_int4(src[src_offset + (lid+i) * src_step + min(gid, cols - 1)]) : 0); + src_t[1] = (i + lid < rows ? convert_int4(src[src_offset + (lid+i) * src_step + min(gid + 1, cols - 1)]) : 0); + + sum_t[0] = (i == 0 ? 0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sqsum_t[0] = (i == 0 ? (TYPE4)0 : lm_sqsum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? 0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + sqsum_t[1] = (i == 0 ? (TYPE4)0 : lm_sqsum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + lm_sqsum[0][bf_loc] = convert_TYPE4(src_t[0] * src_t[0]); + + lm_sum[1][bf_loc] = src_t[1]; + lm_sqsum[1][bf_loc] = convert_TYPE4(src_t[1] * src_t[1]); + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + lm_sqsum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + lm_sqsum[lid >> 7][ai] = lm_sqsum[lid >> 7][bi] - lm_sqsum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + int loc_s0 = gid * dst_step + i + lid - 1 - pre_invalid * dst_step /4, loc_s1 = loc_s0 + dst_step ; + int loc_sq0 = gid * CONVERT(dst1_step) + i + lid - 1 - pre_invalid * dst1_step / sizeof(TYPE),loc_sq1 = loc_sq0 + CONVERT(dst1_step); + if(lid > 0 && (i+lid) <= rows) + { + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + lm_sqsum[0][bf_loc] += sqsum_t[0]; + lm_sqsum[1][bf_loc] += sqsum_t[1]; + sum_p = (__local int*)(&(lm_sum[0][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k >= cols + pre_invalid || gid * 4 + k < pre_invalid) continue; + sum[loc_s0 + k * dst_step / 4] = sum_p[k]; + sqsum[loc_sq0 + k * dst1_step / sizeof(TYPE)] = sqsum_p[k]; + } + sum_p = (__local int*)(&(lm_sum[1][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k + 4 >= cols + pre_invalid) break; + sum[loc_s1 + k * dst_step / 4] = sum_p[k]; + sqsum[loc_sq1 + k * dst1_step / sizeof(TYPE)] = sqsum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +kernel void integral_rows(__global int4 *srcsum, __global TYPE4 * srcsqsum,__global int *sum, + __global TYPE *sqsum, int rows, int cols, int src_step, int src1_step, int sum_step, + int sqsum_step, int sum_offset, int sqsum_offset) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + int4 src_t[2], sum_t[2]; + TYPE4 sqsrc_t[2],sqsum_t[2]; + __local int4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local TYPE4 lm_sqsum[2][LSIZE + LOG_LSIZE]; + __local int *sum_p; + __local TYPE *sqsum_p; + src_step = src_step >> 4; + src1_step = (src1_step / sizeof(TYPE)) >> 2 ; + gid <<= 1; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = i + lid < rows ? srcsum[(lid+i) * src_step + gid ] : (int4)0; + sqsrc_t[0] = i + lid < rows ? srcsqsum[(lid+i) * src1_step + gid ] : (TYPE4)0; + src_t[1] = i + lid < rows ? srcsum[(lid+i) * src_step + gid + 1] : (int4)0; + sqsrc_t[1] = i + lid < rows ? srcsqsum[(lid+i) * src1_step + gid + 1] : (TYPE4)0; + + sum_t[0] = (i == 0 ? 0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sqsum_t[0] = (i == 0 ? (TYPE4)0 : lm_sqsum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? 0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + sqsum_t[1] = (i == 0 ? (TYPE4)0 : lm_sqsum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + lm_sqsum[0][bf_loc] = sqsrc_t[0]; + + lm_sum[1][bf_loc] = src_t[1]; + lm_sqsum[1][bf_loc] = sqsrc_t[1]; + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + lm_sqsum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + lm_sqsum[lid >> 7][ai] = lm_sqsum[lid >> 7][bi] - lm_sqsum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(gid == 0 && (i + lid) <= rows) + { + sum[sum_offset + i + lid] = 0; + sqsum[sqsum_offset + i + lid] = 0; + } + if(i + lid == 0) + { + int loc0 = gid * sum_step; + int loc1 = gid * CONVERT(sqsum_step); + for(int k = 1; k <= 8; k++) + { + if(gid * 4 + k > cols) break; + sum[sum_offset + loc0 + k * sum_step / 4] = 0; + sqsum[sqsum_offset + loc1 + k * sqsum_step / sizeof(TYPE)] = 0; + } + } + int loc_s0 = sum_offset + gid * sum_step + sum_step / 4 + i + lid, loc_s1 = loc_s0 + sum_step ; + int loc_sq0 = sqsum_offset + gid * CONVERT(sqsum_step) + sqsum_step / sizeof(TYPE) + i + lid, loc_sq1 = loc_sq0 + CONVERT(sqsum_step) ; + + if(lid > 0 && (i+lid) <= rows) + { + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + lm_sqsum[0][bf_loc] += sqsum_t[0]; + lm_sqsum[1][bf_loc] += sqsum_t[1]; + sum_p = (__local int*)(&(lm_sum[0][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k >= cols) break; + sum[loc_s0 + k * sum_step / 4] = sum_p[k]; + sqsum[loc_sq0 + k * sqsum_step / sizeof(TYPE)] = sqsum_p[k]; + } + sum_p = (__local int*)(&(lm_sum[1][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + 4 + k >= cols) break; + sum[loc_s1 + k * sum_step / 4] = sum_p[k]; + sqsum[loc_sq1 + k * sqsum_step / sizeof(TYPE)] = sqsum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +#elif sdepth == 5 + +kernel void integral_cols(__global uchar4 *src, __global float *sum, __global TYPE *sqsum, + int src_offset, int pre_invalid, int rows, int cols, int src_step, int dst_step, int dst1_step) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + float4 src_t[2], sum_t[2]; + TYPE4 sqsum_t[2]; + __local float4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local TYPE4 lm_sqsum[2][LSIZE + LOG_LSIZE]; + __local float* sum_p; + __local TYPE* sqsum_p; + src_step = src_step >> 2; + gid = gid << 1; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = (i + lid < rows ? convert_float4(src[src_offset + (lid+i) * src_step + min(gid, cols - 1)]) : (float4)0); + src_t[1] = (i + lid < rows ? convert_float4(src[src_offset + (lid+i) * src_step + min(gid + 1, cols - 1)]) : (float4)0); + + sum_t[0] = (i == 0 ? (float4)0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sqsum_t[0] = (i == 0 ? (TYPE4)0 : lm_sqsum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? (float4)0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + sqsum_t[1] = (i == 0 ? (TYPE4)0 : lm_sqsum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + lm_sqsum[0][bf_loc] = convert_TYPE4(src_t[0] * src_t[0]); +// printf("%f\n", src_t[0].s0); + + lm_sum[1][bf_loc] = src_t[1]; + lm_sqsum[1][bf_loc] = convert_TYPE4(src_t[1] * src_t[1]); + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + lm_sqsum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + lm_sqsum[lid >> 7][ai] = lm_sqsum[lid >> 7][bi] - lm_sqsum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + int loc_s0 = gid * dst_step + i + lid - 1 - pre_invalid * dst_step / 4, loc_s1 = loc_s0 + dst_step ; + int loc_sq0 = gid * CONVERT(dst1_step) + i + lid - 1 - pre_invalid * dst1_step / sizeof(TYPE), loc_sq1 = loc_sq0 + CONVERT(dst1_step); + if(lid > 0 && (i+lid) <= rows) + { + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + lm_sqsum[0][bf_loc] += sqsum_t[0]; + lm_sqsum[1][bf_loc] += sqsum_t[1]; + sum_p = (__local float*)(&(lm_sum[0][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k >= cols + pre_invalid || gid * 4 + k < pre_invalid) continue; + sum[loc_s0 + k * dst_step / 4] = sum_p[k]; + sqsum[loc_sq0 + k * dst1_step / sizeof(TYPE)] = sqsum_p[k]; + } + sum_p = (__local float*)(&(lm_sum[1][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k + 4 >= cols + pre_invalid) break; + sum[loc_s1 + k * dst_step / 4] = sum_p[k]; + sqsum[loc_sq1 + k * dst1_step / sizeof(TYPE)] = sqsum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +kernel void integral_rows(__global float4 *srcsum, __global TYPE4 * srcsqsum, __global float *sum , + __global TYPE *sqsum, int rows, int cols, int src_step, int src1_step, int sum_step, + int sqsum_step, int sum_offset, int sqsum_offset) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + float4 src_t[2], sum_t[2]; + TYPE4 sqsrc_t[2],sqsum_t[2]; + __local float4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local TYPE4 lm_sqsum[2][LSIZE + LOG_LSIZE]; + __local float *sum_p; + __local TYPE *sqsum_p; + src_step = src_step >> 4; + src1_step = (src1_step / sizeof(TYPE)) >> 2; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = i + lid < rows ? srcsum[(lid+i) * src_step + gid * 2] : (float4)0; + sqsrc_t[0] = i + lid < rows ? srcsqsum[(lid+i) * src1_step + gid * 2] : (TYPE4)0; + src_t[1] = i + lid < rows ? srcsum[(lid+i) * src_step + gid * 2 + 1] : (float4)0; + sqsrc_t[1] = i + lid < rows ? srcsqsum[(lid+i) * src1_step + gid * 2 + 1] : (TYPE4)0; + + sum_t[0] = (i == 0 ? (float4)0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sqsum_t[0] = (i == 0 ? (TYPE4)0 : lm_sqsum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? (float4)0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + sqsum_t[1] = (i == 0 ? (TYPE4)0 : lm_sqsum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + lm_sqsum[0][bf_loc] = sqsrc_t[0]; + + lm_sum[1][bf_loc] = src_t[1]; + lm_sqsum[1][bf_loc] = sqsrc_t[1]; + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + lm_sqsum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + + lm_sqsum[lid >> 7][bi] += lm_sqsum[lid >> 7][ai]; + lm_sqsum[lid >> 7][ai] = lm_sqsum[lid >> 7][bi] - lm_sqsum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(gid == 0 && (i + lid) <= rows) + { + sum[sum_offset + i + lid] = 0; + sqsum[sqsum_offset + i + lid] = 0; + } + if(i + lid == 0) + { + int loc0 = gid * 2 * sum_step; + int loc1 = gid * 2 * CONVERT(sqsum_step); + for(int k = 1; k <= 8; k++) + { + if(gid * 8 + k > cols) break; + sum[sum_offset + loc0 + k * sum_step / 4] = 0; + sqsum[sqsum_offset + loc1 + k * sqsum_step / sizeof(TYPE)] = 0; + } + } + int loc_s0 = sum_offset + gid * 2 * sum_step + sum_step / 4 + i + lid, loc_s1 = loc_s0 + sum_step ; + int loc_sq0 = sqsum_offset + gid * 2 * CONVERT(sqsum_step) + sqsum_step / sizeof(TYPE) + i + lid, loc_sq1 = loc_sq0 + CONVERT(sqsum_step) ; + if(lid > 0 && (i+lid) <= rows) + { + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + lm_sqsum[0][bf_loc] += sqsum_t[0]; + lm_sqsum[1][bf_loc] += sqsum_t[1]; + sum_p = (__local float*)(&(lm_sum[0][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 8 + k >= cols) break; + sum[loc_s0 + k * sum_step / 4] = sum_p[k]; + sqsum[loc_sq0 + k * sqsum_step / sizeof(TYPE)] = sqsum_p[k]; + } + sum_p = (__local float*)(&(lm_sum[1][bf_loc])); + sqsum_p = (__local TYPE*)(&(lm_sqsum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 8 + 4 + k >= cols) break; + sum[loc_s1 + k * sum_step / 4] = sum_p[k]; + sqsum[loc_sq1 + k * sqsum_step / sizeof(TYPE)] = sqsum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +#endif diff --git a/modules/imgproc/src/opencl/integral_sum.cl b/modules/imgproc/src/opencl/integral_sum.cl new file mode 100644 index 0000000000..dda0e60186 --- /dev/null +++ b/modules/imgproc/src/opencl/integral_sum.cl @@ -0,0 +1,413 @@ +/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Shengen Yan,yanshengen@gmail.com +// +// 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*/ + +#ifdef DOUBLE_SUPPORT +#ifdef cl_amd_fp64 +#pragma OPENCL EXTENSION cl_amd_fp64:enable +#elif defined (cl_khr_fp64) +#pragma OPENCL EXTENSION cl_khr_fp64:enable +#endif +#endif + +#define LSIZE 256 +#define LSIZE_1 255 +#define LSIZE_2 254 +#define HF_LSIZE 128 +#define LOG_LSIZE 8 +#define LOG_NUM_BANKS 5 +#define NUM_BANKS 32 +#define GET_CONFLICT_OFFSET(lid) ((lid) >> LOG_NUM_BANKS) + +#if sdepth == 4 + +kernel void integral_sum_cols(__global uchar4 *src, __global int *sum, + int src_offset, int pre_invalid, int rows, int cols, int src_step, int dst_step) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + int4 src_t[2], sum_t[2]; + __local int4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local int* sum_p; + src_step = src_step >> 2; + gid = gid << 1; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = (i + lid < rows ? convert_int4(src[src_offset + (lid+i) * src_step + gid]) : 0); + src_t[1] = (i + lid < rows ? convert_int4(src[src_offset + (lid+i) * src_step + gid + 1]) : 0); + + sum_t[0] = (i == 0 ? 0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? 0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + + lm_sum[1][bf_loc] = src_t[1]; + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid > 0 && (i+lid) <= rows) + { + int loc_s0 = gid * dst_step + i + lid - 1 - pre_invalid * dst_step / 4, loc_s1 = loc_s0 + dst_step ; + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + sum_p = (__local int*)(&(lm_sum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k >= cols + pre_invalid || gid * 4 + k < pre_invalid) continue; + sum[loc_s0 + k * dst_step / 4] = sum_p[k]; + } + sum_p = (__local int*)(&(lm_sum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k + 4 >= cols + pre_invalid) break; + sum[loc_s1 + k * dst_step / 4] = sum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +kernel void integral_sum_rows(__global int4 *srcsum, __global int *sum, + int rows, int cols, int src_step, int sum_step, int sum_offset) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + int4 src_t[2], sum_t[2]; + __local int4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local int *sum_p; + src_step = src_step >> 4; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = i + lid < rows ? srcsum[(lid+i) * src_step + gid * 2] : 0; + src_t[1] = i + lid < rows ? srcsum[(lid+i) * src_step + gid * 2 + 1] : 0; + + sum_t[0] = (i == 0 ? 0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? 0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + + lm_sum[1][bf_loc] = src_t[1]; + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(gid == 0 && (i + lid) <= rows) + { + sum[sum_offset + i + lid] = 0; + } + if(i + lid == 0) + { + int loc0 = gid * 2 * sum_step; + for(int k = 1; k <= 8; k++) + { + if(gid * 8 + k > cols) break; + sum[sum_offset + loc0 + k * sum_step / 4] = 0; + } + } + + if(lid > 0 && (i+lid) <= rows) + { + int loc_s0 = sum_offset + gid * 2 * sum_step + sum_step / 4 + i + lid, loc_s1 = loc_s0 + sum_step ; + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + sum_p = (__local int*)(&(lm_sum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 8 + k >= cols) break; + sum[loc_s0 + k * sum_step / 4] = sum_p[k]; + } + sum_p = (__local int*)(&(lm_sum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 8 + 4 + k >= cols) break; + sum[loc_s1 + k * sum_step / 4] = sum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +#elif sdepth == 5 + +kernel void integral_sum_cols(__global uchar4 *src, __global float *sum, + int src_offset, int pre_invalid, int rows, int cols, int src_step, int dst_step) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + float4 src_t[2], sum_t[2]; + __local float4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local float* sum_p; + src_step = src_step >> 2; + gid = gid << 1; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = (i + lid < rows ? convert_float4(src[src_offset + (lid+i) * src_step + gid]) : (float4)0); + src_t[1] = (i + lid < rows ? convert_float4(src[src_offset + (lid+i) * src_step + gid + 1]) : (float4)0); + + sum_t[0] = (i == 0 ? (float4)0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? (float4)0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + + lm_sum[1][bf_loc] = src_t[1]; + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid > 0 && (i+lid) <= rows) + { + int loc_s0 = gid * dst_step + i + lid - 1 - pre_invalid * dst_step / 4, loc_s1 = loc_s0 + dst_step ; + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + sum_p = (__local float*)(&(lm_sum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k >= cols + pre_invalid || gid * 4 + k < pre_invalid) continue; + sum[loc_s0 + k * dst_step / 4] = sum_p[k]; + } + sum_p = (__local float*)(&(lm_sum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 4 + k + 4 >= cols + pre_invalid) break; + sum[loc_s1 + k * dst_step / 4] = sum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +kernel void integral_sum_rows(__global float4 *srcsum, __global float *sum, + int rows, int cols, int src_step, int sum_step, int sum_offset) +{ + int lid = get_local_id(0); + int gid = get_group_id(0); + float4 src_t[2], sum_t[2]; + __local float4 lm_sum[2][LSIZE + LOG_LSIZE]; + __local float *sum_p; + src_step = src_step >> 4; + for(int i = 0; i < rows; i =i + LSIZE_1) + { + src_t[0] = i + lid < rows ? srcsum[(lid+i) * src_step + gid * 2] : (float4)0; + src_t[1] = i + lid < rows ? srcsum[(lid+i) * src_step + gid * 2 + 1] : (float4)0; + + sum_t[0] = (i == 0 ? (float4)0 : lm_sum[0][LSIZE_2 + LOG_LSIZE]); + sum_t[1] = (i == 0 ? (float4)0 : lm_sum[1][LSIZE_2 + LOG_LSIZE]); + barrier(CLK_LOCAL_MEM_FENCE); + + int bf_loc = lid + GET_CONFLICT_OFFSET(lid); + lm_sum[0][bf_loc] = src_t[0]; + + lm_sum[1][bf_loc] = src_t[1]; + + int offset = 1; + for(int d = LSIZE >> 1 ; d > 0; d>>=1) + { + barrier(CLK_LOCAL_MEM_FENCE); + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + } + offset <<= 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + if(lid < 2) + { + lm_sum[lid][LSIZE_2 + LOG_LSIZE] = 0; + } + for(int d = 1; d < LSIZE; d <<= 1) + { + barrier(CLK_LOCAL_MEM_FENCE); + offset >>= 1; + int ai = offset * (((lid & 127)<<1) +1) - 1,bi = ai + offset; + ai += GET_CONFLICT_OFFSET(ai); + bi += GET_CONFLICT_OFFSET(bi); + + if((lid & 127) < d) + { + lm_sum[lid >> 7][bi] += lm_sum[lid >> 7][ai]; + lm_sum[lid >> 7][ai] = lm_sum[lid >> 7][bi] - lm_sum[lid >> 7][ai]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(gid == 0 && (i + lid) <= rows) + { + sum[sum_offset + i + lid] = 0; + } + if(i + lid == 0) + { + int loc0 = gid * 2 * sum_step; + for(int k = 1; k <= 8; k++) + { + if(gid * 8 + k > cols) break; + sum[sum_offset + loc0 + k * sum_step / 4] = 0; + } + } + + if(lid > 0 && (i+lid) <= rows) + { + int loc_s0 = sum_offset + gid * 2 * sum_step + sum_step / 4 + i + lid, loc_s1 = loc_s0 + sum_step ; + lm_sum[0][bf_loc] += sum_t[0]; + lm_sum[1][bf_loc] += sum_t[1]; + sum_p = (__local float*)(&(lm_sum[0][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 8 + k >= cols) break; + sum[loc_s0 + k * sum_step / 4] = sum_p[k]; + } + sum_p = (__local float*)(&(lm_sum[1][bf_loc])); + for(int k = 0; k < 4; k++) + { + if(gid * 8 + 4 + k >= cols) break; + sum[loc_s1 + k * sum_step / 4] = sum_p[k]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + } +} + +#endif diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp index 81cd23afc0..d6cc8a56fe 100644 --- a/modules/imgproc/src/samplers.cpp +++ b/modules/imgproc/src/samplers.cpp @@ -64,7 +64,7 @@ adjustRect( const uchar* src, size_t src_step, int pix_size, rect.x = win_size.width; } - if( ip.x + win_size.width < src_size.width ) + if( ip.x < src_size.width - win_size.width ) rect.width = win_size.width; else { @@ -85,7 +85,7 @@ adjustRect( const uchar* src, size_t src_step, int pix_size, else rect.y = -ip.y; - if( ip.y + win_size.height < src_size.height ) + if( ip.y < src_size.height - win_size.height ) rect.height = win_size.height; else { @@ -155,8 +155,8 @@ void getRectSubPix_Cn_(const _Tp* src, size_t src_step, Size src_size, src_step /= sizeof(src[0]); dst_step /= sizeof(dst[0]); - if( 0 <= ip.x && ip.x + win_size.width < src_size.width && - 0 <= ip.y && ip.y + win_size.height < src_size.height ) + if( 0 <= ip.x && ip.x < src_size.width - win_size.width && + 0 <= ip.y && ip.y < src_size.height - win_size.height) { // extracted rectangle is totally inside the image src += ip.y * src_step + ip.x*cn; diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp index 2e2eabf4e1..9d280c9878 100644 --- a/modules/imgproc/src/smooth.cpp +++ b/modules/imgproc/src/smooth.cpp @@ -41,6 +41,7 @@ //M*/ #include "precomp.hpp" +#include "opencl_kernels.hpp" /* * This file includes the code, contributed by Simon Perreault @@ -797,10 +798,10 @@ cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype ) return kernel; } +namespace cv { -cv::Ptr cv::createGaussianFilter( int type, Size ksize, - double sigma1, double sigma2, - int borderType ) +static void createGaussianKernels( Mat & kx, Mat & ky, int type, Size ksize, + double sigma1, double sigma2 ) { int depth = CV_MAT_DEPTH(type); if( sigma2 <= 0 ) @@ -818,12 +819,21 @@ cv::Ptr cv::createGaussianFilter( int type, Size ksize, sigma1 = std::max( sigma1, 0. ); sigma2 = std::max( sigma2, 0. ); - Mat kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) ); - Mat ky; + kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) ); if( ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON ) ky = kx; else ky = getGaussianKernel( ksize.height, sigma2, std::max(depth, CV_32F) ); +} + +} + +cv::Ptr cv::createGaussianFilter( int type, Size ksize, + double sigma1, double sigma2, + int borderType ) +{ + Mat kx, ky; + createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2); return createSeparableLinearFilter( type, type, kx, ky, Point(-1,-1), 0, borderType ); } @@ -833,33 +843,34 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, double sigma1, double sigma2, int borderType ) { - Mat src = _src.getMat(); - _dst.create( src.size(), src.type() ); - Mat dst = _dst.getMat(); + int type = _src.type(); + Size size = _src.size(); + _dst.create( size, type ); if( borderType != BORDER_CONSTANT ) { - if( src.rows == 1 ) + if( size.height == 1 ) ksize.height = 1; - if( src.cols == 1 ) + if( size.width == 1 ) ksize.width = 1; } if( ksize.width == 1 && ksize.height == 1 ) { - src.copyTo(dst); + _src.copyTo(_dst); return; } #ifdef HAVE_TEGRA_OPTIMIZATION - if(sigma1 == 0 && sigma2 == 0 && tegra::gaussian(src, dst, ksize, borderType)) + if(sigma1 == 0 && sigma2 == 0 && tegra::gaussian(_src.getMat(), _dst.getMat(), ksize, borderType)) return; #endif #if defined HAVE_IPP && (IPP_VERSION_MAJOR >= 7) - if(src.type() == CV_32FC1 && sigma1 == sigma2 && ksize.width == ksize.height && sigma1 != 0.0 ) + if( type == CV_32FC1 && sigma1 == sigma2 && ksize.width == ksize.height && sigma1 != 0.0 ) { - IppiSize roi = {src.cols, src.rows}; + Mat src = _src.getMat(), dst = _dst.getMat(); + IppiSize roi = { src.cols, src.rows }; int bufSize = 0; ippiFilterGaussGetBufferSize_32f_C1R(roi, ksize.width, &bufSize); AutoBuffer buf(bufSize+128); @@ -872,11 +883,11 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, } #endif - Ptr f = createGaussianFilter( src.type(), ksize, sigma1, sigma2, borderType ); - f->apply( src, dst ); + Mat kx, ky; + createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2); + sepFilter2D(_src, _dst, CV_MAT_DEPTH(type), kx, ky, Point(-1,-1), 0, borderType ); } - /****************************************************************************************\ Median Filter \****************************************************************************************/ @@ -1914,19 +1925,91 @@ private: }; #endif +static bool ocl_bilateralFilter_8u(InputArray _src, OutputArray _dst, int d, + double sigma_color, double sigma_space, + int borderType) +{ + int type = _src.type(), cn = CV_MAT_CN(type); + int i, j, maxk, radius; + + if ( type != CV_8UC1 ) + return false; + + if (sigma_color <= 0) + sigma_color = 1; + if (sigma_space <= 0) + sigma_space = 1; + + double gauss_color_coeff = -0.5 / (sigma_color * sigma_color); + double gauss_space_coeff = -0.5 / (sigma_space * sigma_space); + + if ( d <= 0 ) + radius = cvRound(sigma_space * 1.5); + else + radius = d / 2; + radius = MAX(radius, 1); + d = radius * 2 + 1; + + UMat src = _src.getUMat(), dst = _dst.getUMat(), temp; + if (src.u == dst.u) + return false; + + copyMakeBorder(src, temp, radius, radius, radius, radius, borderType); + + std::vector _color_weight(cn * 256); + std::vector _space_weight(d * d); + std::vector _space_ofs(d * d); + float *color_weight = &_color_weight[0]; + float *space_weight = &_space_weight[0]; + int *space_ofs = &_space_ofs[0]; + + // initialize color-related bilateral filter coefficients + for( i = 0; i < 256 * cn; i++ ) + color_weight[i] = (float)std::exp(i * i * gauss_color_coeff); + + // initialize space-related bilateral filter coefficients + for( i = -radius, maxk = 0; i <= radius; i++ ) + for( j = -radius; j <= radius; j++ ) + { + double r = std::sqrt((double)i * i + (double)j * j); + if ( r > radius ) + continue; + space_weight[maxk] = (float)std::exp(r * r * gauss_space_coeff); + space_ofs[maxk++] = (int)(i * temp.step + j); + } + + ocl::Kernel k("bilateral", ocl::imgproc::bilateral_oclsrc, + format("-D radius=%d -D maxk=%d", radius, maxk)); + if (k.empty()) + return false; + + Mat mcolor_weight(1, cn * 256, CV_32FC1, color_weight); + Mat mspace_weight(1, d * d, CV_32FC1, space_weight); + Mat mspace_ofs(1, d * d, CV_32SC1, space_ofs); + UMat ucolor_weight, uspace_weight, uspace_ofs; + mcolor_weight.copyTo(ucolor_weight); + mspace_weight.copyTo(uspace_weight); + mspace_ofs.copyTo(uspace_ofs); + + k.args(ocl::KernelArg::ReadOnlyNoSize(temp), ocl::KernelArg::WriteOnly(dst), + ocl::KernelArg::PtrReadOnly(ucolor_weight), + ocl::KernelArg::PtrReadOnly(uspace_weight), + ocl::KernelArg::PtrReadOnly(uspace_ofs)); + + size_t globalsize[2] = { dst.cols, dst.rows }; + return k.run(2, globalsize, NULL, false); +} + static void bilateralFilter_8u( const Mat& src, Mat& dst, int d, double sigma_color, double sigma_space, int borderType ) { - int cn = src.channels(); int i, j, maxk, radius; Size size = src.size(); - CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) && - src.type() == dst.type() && src.size() == dst.size() && - src.data != dst.data ); + CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) && src.data != dst.data ); if( sigma_color <= 0 ) sigma_color = 1; @@ -1973,7 +2056,7 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d, { j = -radius; - for( ;j <= radius; j++ ) + for( ; j <= radius; j++ ) { double r = std::sqrt((double)i*i + (double)j*j); if( r > radius ) @@ -2184,9 +2267,7 @@ bilateralFilter_32f( const Mat& src, Mat& dst, int d, float len, scale_index; Size size = src.size(); - CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) && - src.type() == dst.type() && src.size() == dst.size() && - src.data != dst.data ); + CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) && src.data != dst.data ); if( sigma_color <= 0 ) sigma_color = 1; @@ -2267,9 +2348,13 @@ void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d, double sigmaColor, double sigmaSpace, int borderType ) { - Mat src = _src.getMat(); - _dst.create( src.size(), src.type() ); - Mat dst = _dst.getMat(); + _dst.create( _src.size(), _src.type() ); + + if (ocl::useOpenCL() && _src.dims() <= 2 && _dst.isUMat() && + ocl_bilateralFilter_8u(_src, _dst, d, sigmaColor, sigmaSpace, borderType)) + return; + + Mat src = _src.getMat(), dst = _dst.getMat(); if( src.depth() == CV_8U ) bilateralFilter_8u( src, dst, d, sigmaColor, sigmaSpace, borderType ); diff --git a/modules/imgproc/src/sumpixels.cpp b/modules/imgproc/src/sumpixels.cpp index 2db3b921d8..6beae4adaf 100755 --- a/modules/imgproc/src/sumpixels.cpp +++ b/modules/imgproc/src/sumpixels.cpp @@ -41,6 +41,8 @@ //M*/ #include "precomp.hpp" +#include "opencl_kernels.hpp" + #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) static IppStatus sts = ippInit(); #endif @@ -215,30 +217,140 @@ static void integral_##suffix( T* src, size_t srcstep, ST* sum, size_t sumstep, { integral_(src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tiltedstep, size, cn); } DEF_INTEGRAL_FUNC(8u32s, uchar, int, double) -DEF_INTEGRAL_FUNC(8u32f, uchar, float, double) -DEF_INTEGRAL_FUNC(8u64f, uchar, double, double) -DEF_INTEGRAL_FUNC(16u64f, ushort, double, double) -DEF_INTEGRAL_FUNC(16s64f, short, double, double) -DEF_INTEGRAL_FUNC(32f, float, float, double) -DEF_INTEGRAL_FUNC(32f64f, float, double, double) -DEF_INTEGRAL_FUNC(64f, double, double, double) +DEF_INTEGRAL_FUNC(8u32f64f, uchar, float, double) +DEF_INTEGRAL_FUNC(8u64f64f, uchar, double, double) +DEF_INTEGRAL_FUNC(16u64f64f, ushort, double, double) +DEF_INTEGRAL_FUNC(16s64f64f, short, double, double) +DEF_INTEGRAL_FUNC(32f32f64f, float, float, double) +DEF_INTEGRAL_FUNC(32f64f64f, float, double, double) +DEF_INTEGRAL_FUNC(64f64f64f, double, double, double) + +DEF_INTEGRAL_FUNC(8u32s32f, uchar, int, float) +DEF_INTEGRAL_FUNC(8u32f32f, uchar, float, float) +DEF_INTEGRAL_FUNC(32f32f32f, float, float, float) typedef void (*IntegralFunc)(const uchar* src, size_t srcstep, uchar* sum, size_t sumstep, uchar* sqsum, size_t sqsumstep, uchar* tilted, size_t tstep, Size size, int cn ); +enum { vlen = 4 }; + +static bool ocl_integral( InputArray _src, OutputArray _sum, int sdepth ) +{ + if ( _src.type() != CV_8UC1 || _src.step() % vlen != 0 || _src.offset() % vlen != 0 || + !(sdepth == CV_32S || sdepth == CV_32F) ) + return false; + + ocl::Kernel k1("integral_sum_cols", ocl::imgproc::integral_sum_oclsrc, + format("-D sdepth=%d", sdepth)); + if (k1.empty()) + return false; + + Size size = _src.size(), t_size = Size(((size.height + vlen - 1) / vlen) * vlen, size.width), + ssize(size.width + 1, size.height + 1); + _sum.create(ssize, sdepth); + UMat src = _src.getUMat(), t_sum(t_size, sdepth), sum = _sum.getUMat(); + t_sum = t_sum(Range::all(), Range(0, size.height)); + + int offset = (int)src.offset / vlen, pre_invalid = (int)src.offset % vlen; + int vcols = (pre_invalid + src.cols + vlen - 1) / vlen; + int sum_offset = (int)sum.offset / vlen; + + k1.args(ocl::KernelArg::PtrReadOnly(src), ocl::KernelArg::PtrWriteOnly(t_sum), + offset, pre_invalid, src.rows, src.cols, (int)src.step, (int)t_sum.step); + size_t gt = ((vcols + 1) / 2) * 256, lt = 256; + if (!k1.run(1, >, <, false)) + return false; + + ocl::Kernel k2("integral_sum_rows", ocl::imgproc::integral_sum_oclsrc, + format("-D sdepth=%d", sdepth)); + k2.args(ocl::KernelArg::PtrReadWrite(t_sum), ocl::KernelArg::PtrWriteOnly(sum), + t_sum.rows, t_sum.cols, (int)t_sum.step, (int)sum.step, sum_offset); + + size_t gt2 = t_sum.cols * 32, lt2 = 256; + return k2.run(1, >2, <2, false); +} + +static bool ocl_integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, int sdepth, int sqdepth ) +{ + bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; + + if ( _src.type() != CV_8UC1 || _src.step() % vlen != 0 || _src.offset() % vlen != 0 || + (!doubleSupport && (sdepth == CV_64F || sqdepth == CV_64F)) ) + return false; + + char cvt[40]; + String opts = format("-D sdepth=%d -D sqdepth=%d -D TYPE=%s -D TYPE4=%s4 -D convert_TYPE4=%s%s", + sdepth, sqdepth, ocl::typeToStr(sqdepth), ocl::typeToStr(sqdepth), + ocl::convertTypeStr(sdepth, sqdepth, 4, cvt), + doubleSupport ? " -D DOUBLE_SUPPORT" : ""); + + ocl::Kernel k1("integral_cols", ocl::imgproc::integral_sqrsum_oclsrc, opts); + if (k1.empty()) + return false; + + Size size = _src.size(), dsize = Size(size.width + 1, size.height + 1), + t_size = Size(((size.height + vlen - 1) / vlen) * vlen, size.width); + UMat src = _src.getUMat(), t_sum(t_size, sdepth), t_sqsum(t_size, sqdepth); + t_sum = t_sum(Range::all(), Range(0, size.height)); + t_sqsum = t_sqsum(Range::all(), Range(0, size.height)); + + _sum.create(dsize, sdepth); + _sqsum.create(dsize, sqdepth); + UMat sum = _sum.getUMat(), sqsum = _sqsum.getUMat(); + + int offset = (int)src.offset / vlen; + int pre_invalid = src.offset % vlen; + int vcols = (pre_invalid + src.cols + vlen - 1) / vlen; + int sum_offset = (int)(sum.offset / sum.elemSize()); + int sqsum_offset = (int)(sqsum.offset / sqsum.elemSize()); + + k1.args(ocl::KernelArg::PtrReadOnly(src), ocl::KernelArg::PtrWriteOnly(t_sum), + ocl::KernelArg::PtrWriteOnly(t_sqsum), offset, pre_invalid, src.rows, + src.cols, (int)src.step, (int)t_sum.step, (int)t_sqsum.step); + + size_t gt = ((vcols + 1) / 2) * 256, lt = 256; + if (!k1.run(1, >, <, false)) + return false; + + ocl::Kernel k2("integral_rows", ocl::imgproc::integral_sqrsum_oclsrc, opts); + if (k2.empty()) + return false; + + k2.args(ocl::KernelArg::PtrReadOnly(t_sum), ocl::KernelArg::PtrReadOnly(t_sqsum), + ocl::KernelArg::PtrWriteOnly(sum), ocl::KernelArg::PtrWriteOnly(sqsum), + t_sum.rows, t_sum.cols, (int)t_sum.step, (int)t_sqsum.step, + (int)sum.step, (int)sqsum.step, sum_offset, sqsum_offset); + + size_t gt2 = t_sum.cols * 32, lt2 = 256; + return k2.run(1, >2, <2, false); +} + } -void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, OutputArray _tilted, int sdepth ) +void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, OutputArray _tilted, int sdepth, int sqdepth ) { - Mat src = _src.getMat(), sum, sqsum, tilted; - int depth = src.depth(), cn = src.channels(); - Size isize(src.cols + 1, src.rows+1); - + int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); if( sdepth <= 0 ) sdepth = depth == CV_8U ? CV_32S : CV_64F; - sdepth = CV_MAT_DEPTH(sdepth); + if ( sqdepth <= 0 ) + sqdepth = CV_64F; + sdepth = CV_MAT_DEPTH(sdepth), sqdepth = CV_MAT_DEPTH(sqdepth); + + if (ocl::useOpenCL() && _sum.isUMat() && !_tilted.needed()) + { + if (!_sqsum.needed()) + { + if (ocl_integral(_src, _sum, sdepth)) + return; + } + else if (_sqsum.isUMat()) + { + if (ocl_integral(_src, _sum, _sqsum, sdepth, sqdepth)) + return; + } + } #if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7) if( ( depth == CV_8U ) && ( !_tilted.needed() ) ) @@ -250,9 +362,9 @@ void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, Output IppiSize srcRoiSize = ippiSize( src.cols, src.rows ); _sum.create( isize, CV_MAKETYPE( sdepth, cn ) ); sum = _sum.getMat(); - if( _sqsum.needed() ) + if( _sqsum.needed() && sqdepth == CV_64F ) { - _sqsum.create( isize, CV_MAKETYPE( CV_64F, cn ) ); + _sqsum.create( isize, CV_MAKETYPE( sqdepth, cn ) ); sqsum = _sqsum.getMat(); ippiSqrIntegral_8u32f64f_C1R( (const Ipp8u*)src.data, (int)src.step, (Ipp32f*)sum.data, (int)sum.step, (Ipp64f*)sqsum.data, (int)sqsum.step, srcRoiSize, 0, 0 ); } @@ -270,9 +382,9 @@ void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, Output IppiSize srcRoiSize = ippiSize( src.cols, src.rows ); _sum.create( isize, CV_MAKETYPE( sdepth, cn ) ); sum = _sum.getMat(); - if( _sqsum.needed() ) + if( _sqsum.needed() && sqdepth == CV_64F ) { - _sqsum.create( isize, CV_MAKETYPE( CV_64F, cn ) ); + _sqsum.create( isize, CV_MAKETYPE( sqdepth, cn ) ); sqsum = _sqsum.getMat(); ippiSqrIntegral_8u32s64f_C1R( (const Ipp8u*)src.data, (int)src.step, (Ipp32s*)sum.data, (int)sum.step, (Ipp64f*)sqsum.data, (int)sqsum.step, srcRoiSize, 0, 0 ); } @@ -286,8 +398,15 @@ void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, Output } #endif + Size ssize = _src.size(), isize(ssize.width + 1, ssize.height + 1); _sum.create( isize, CV_MAKETYPE(sdepth, cn) ); - sum = _sum.getMat(); + Mat src = _src.getMat(), sum =_sum.getMat(), sqsum, tilted; + + if( _sqsum.needed() ) + { + _sqsum.create( isize, CV_MAKETYPE(sqdepth, cn) ); + sqsum = _sqsum.getMat(); + } if( _tilted.needed() ) { @@ -295,30 +414,29 @@ void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, Output tilted = _tilted.getMat(); } - if( _sqsum.needed() ) - { - _sqsum.create( isize, CV_MAKETYPE(CV_64F, cn) ); - sqsum = _sqsum.getMat(); - } - IntegralFunc func = 0; - - if( depth == CV_8U && sdepth == CV_32S ) + if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_64F ) func = (IntegralFunc)GET_OPTIMIZED(integral_8u32s); - else if( depth == CV_8U && sdepth == CV_32F ) - func = (IntegralFunc)integral_8u32f; - else if( depth == CV_8U && sdepth == CV_64F ) - func = (IntegralFunc)integral_8u64f; - else if( depth == CV_16U && sdepth == CV_64F ) - func = (IntegralFunc)integral_16u64f; - else if( depth == CV_16S && sdepth == CV_64F ) - func = (IntegralFunc)integral_16s64f; - else if( depth == CV_32F && sdepth == CV_32F ) - func = (IntegralFunc)integral_32f; - else if( depth == CV_32F && sdepth == CV_64F ) - func = (IntegralFunc)integral_32f64f; - else if( depth == CV_64F && sdepth == CV_64F ) - func = (IntegralFunc)integral_64f; + else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32F ) + func = (IntegralFunc)integral_8u32s32f; + else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_8u32f64f; + else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_32F ) + func = (IntegralFunc)integral_8u32f32f; + else if( depth == CV_8U && sdepth == CV_64F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_8u64f64f; + else if( depth == CV_16U && sdepth == CV_64F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_16u64f64f; + else if( depth == CV_16S && sdepth == CV_64F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_16s64f64f; + else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_32f32f64f; + else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_32F ) + func = (IntegralFunc)integral_32f32f32f; + else if( depth == CV_32F && sdepth == CV_64F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_32f64f64f; + else if( depth == CV_64F && sdepth == CV_64F && sqdepth == CV_64F ) + func = (IntegralFunc)integral_64f64f64f; else CV_Error( CV_StsUnsupportedFormat, "" ); @@ -331,9 +449,9 @@ void cv::integral( InputArray src, OutputArray sum, int sdepth ) integral( src, sum, noArray(), noArray(), sdepth ); } -void cv::integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth ) +void cv::integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth, int sqdepth ) { - integral( src, sum, sqsum, noArray(), sdepth ); + integral( src, sum, sqsum, noArray(), sdepth, sqdepth ); } diff --git a/modules/imgproc/test/ocl/test_blend.cpp b/modules/imgproc/test/ocl/test_blend.cpp new file mode 100644 index 0000000000..4cfe486d2f --- /dev/null +++ b/modules/imgproc/test/ocl/test_blend.cpp @@ -0,0 +1,129 @@ +/*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) 2010-2012, Multicoreware, Inc., all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Nathan, liujun@multicorewareinc.com +// +// 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 "cvconfig.h" +#include "opencv2/ts/ocl_test.hpp" + +#ifdef HAVE_OPENCL + +namespace cvtest { +namespace ocl { + +PARAM_TEST_CASE(BlendLinear, MatDepth, Channels, bool) +{ + int depth, channels; + bool useRoi; + + TEST_DECLARE_INPUT_PARAMETER(src1) + TEST_DECLARE_INPUT_PARAMETER(src2) + TEST_DECLARE_INPUT_PARAMETER(weights2) + TEST_DECLARE_INPUT_PARAMETER(weights1) + TEST_DECLARE_OUTPUT_PARAMETER(dst) + + virtual void SetUp() + { + depth = GET_PARAM(0); + channels = GET_PARAM(1); + useRoi = GET_PARAM(2); + } + + void random_roi() + { + const int type = CV_MAKE_TYPE(depth, channels); + const double upValue = 256; + + Size roiSize = randomSize(1, 20); + Border src1Border = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(src1, src1_roi, roiSize, src1Border, type, -upValue, upValue); + + Border src2Border = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(src2, src2_roi, roiSize, src2Border, type, -upValue, upValue); + + Border weights1Border = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(weights1, weights1_roi, roiSize, weights1Border, CV_32FC1, -upValue, upValue); + + Border weights2Border = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(weights2, weights2_roi, roiSize, weights2Border, CV_32FC1, 1e-2, upValue); + + weights2_roi -= weights1_roi; + CV_Assert(checkNorm(weights2_roi, weights2(Rect(weights2Border.lef, weights2Border.top, + roiSize.width, roiSize.height))) < 1e-6); + + Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(dst, dst_roi, roiSize, dstBorder, type, 5, 16); + + UMAT_UPLOAD_INPUT_PARAMETER(src1) + UMAT_UPLOAD_INPUT_PARAMETER(src2) + UMAT_UPLOAD_INPUT_PARAMETER(weights1) + UMAT_UPLOAD_INPUT_PARAMETER(weights2) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst) + } + + void Near(double eps = 0.0) + { + EXPECT_MAT_NEAR(dst, udst, eps); + EXPECT_MAT_NEAR(dst_roi, udst_roi, eps); + } +}; + +OCL_TEST_P(BlendLinear, Accuracy) +{ + for (int i = 0; i < test_loop_times; ++i) + { + random_roi(); + + OCL_OFF(cv::blendLinear(src1_roi, src2_roi, weights1_roi, weights2_roi, dst_roi)); + OCL_ON(cv::blendLinear(usrc1_roi, usrc2_roi, uweights1_roi, uweights2_roi, udst_roi)); + + Near(depth <= CV_32S ? 1.0 : 0.2); + } +} + +OCL_INSTANTIATE_TEST_CASE_P(ImgProc, BlendLinear, Combine(testing::Values(CV_8U, CV_32F), OCL_ALL_CHANNELS, Bool())); + +} } // namespace cvtest::ocl + +#endif diff --git a/modules/imgproc/test/ocl/test_color.cpp b/modules/imgproc/test/ocl/test_color.cpp index 5bcfa1bac9..4c0f8b3113 100644 --- a/modules/imgproc/test/ocl/test_color.cpp +++ b/modules/imgproc/test/ocl/test_color.cpp @@ -86,8 +86,7 @@ PARAM_TEST_CASE(CvtColor, MatDepth, bool) void Near(double threshold) { - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); - EXPECT_MAT_NEAR(dst, udst, threshold); + OCL_EXPECT_MATS_NEAR(dst, threshold) } void performTest(int channelsIn, int channelsOut, int code, double threshold = 1e-3) diff --git a/modules/imgproc/test/ocl/test_filter2d.cpp b/modules/imgproc/test/ocl/test_filter2d.cpp new file mode 100644 index 0000000000..54d65459c5 --- /dev/null +++ b/modules/imgproc/test/ocl/test_filter2d.cpp @@ -0,0 +1,135 @@ +/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Copyright (C) 2010-2012, Multicoreware, Inc., 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/ts/ocl_test.hpp" + +#ifdef HAVE_OPENCL + +namespace cvtest { +namespace ocl { + +///////////////////////////////////////////////////////////////////////////////////////////////// +// Filter2D +PARAM_TEST_CASE(Filter2D, MatDepth, Channels, BorderType, bool, bool) +{ + static const int kernelMinSize = 2; + static const int kernelMaxSize = 10; + + int type; + Size dsize; + Point anchor; + int borderType; + bool useRoi; + Mat kernel; + + TEST_DECLARE_INPUT_PARAMETER(src) + TEST_DECLARE_OUTPUT_PARAMETER(dst) + + virtual void SetUp() + { + type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1)); + borderType = GET_PARAM(2) | (GET_PARAM(3) ? BORDER_ISOLATED : 0); + useRoi = GET_PARAM(4); + } + + void random_roi() + { + dsize = randomSize(1, MAX_VALUE); + + Size ksize = randomSize(kernelMinSize, kernelMaxSize); + Mat temp = randomMat(ksize, CV_MAKE_TYPE(((CV_64F == CV_MAT_DEPTH(type)) ? CV_64F : CV_32F), 1), -MAX_VALUE, MAX_VALUE); + cv::normalize(temp, kernel, 1.0, 0.0, NORM_L1); + + Size roiSize = randomSize(ksize.width, MAX_VALUE, ksize.height, MAX_VALUE); + Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE); + + Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE); + + anchor.x = randomInt(-1, ksize.width); + anchor.y = randomInt(-1, ksize.height); + + UMAT_UPLOAD_INPUT_PARAMETER(src) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst) + } + + void Near(double threshold = 0.0) + { + EXPECT_MAT_NEAR(dst, udst, threshold); + EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + } +}; + +OCL_TEST_P(Filter2D, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::filter2D(src_roi, dst_roi, -1, kernel, anchor, 0.0, borderType)); + OCL_ON(cv::filter2D(usrc_roi, udst_roi, -1, kernel, anchor, 0.0, borderType)); + + Near(1.0); + } +} + + +OCL_INSTANTIATE_TEST_CASE_P(ImageProc, Filter2D, + Combine( + Values(CV_8U, CV_16U, CV_16S, CV_32F, CV_64F), + Values(1, 2, 4), + Values((BorderType)BORDER_CONSTANT, + (BorderType)BORDER_REPLICATE, + (BorderType)BORDER_REFLECT, + (BorderType)BORDER_REFLECT_101), + Bool(), // BORDER_ISOLATED + Bool() // ROI + ) + ); + + +} } // namespace cvtest::ocl + +#endif // HAVE_OPENCL diff --git a/modules/imgproc/test/ocl/test_filters.cpp b/modules/imgproc/test/ocl/test_filters.cpp new file mode 100644 index 0000000000..5953d80701 --- /dev/null +++ b/modules/imgproc/test/ocl/test_filters.cpp @@ -0,0 +1,290 @@ +/*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) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Niko Li, newlife20080214@gmail.com +// Jia Haipeng, jiahaipeng95@gmail.com +// Zero Lin, Zero.Lin@amd.com +// Zhang Ying, zhangying913@gmail.com +// Yao Wang, bitwangyaoyao@gmail.com +// +// 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 "cvconfig.h" +#include "opencv2/ts/ocl_test.hpp" + +#ifdef HAVE_OPENCL + +namespace cvtest { +namespace ocl { + +PARAM_TEST_CASE(FilterTestBase, MatType, + int, // kernel size + Size, // dx, dy + BorderType, // border type + double, // optional parameter + bool) // roi or not +{ + int type, borderType, ksize; + Size size; + double param; + bool useRoi; + + TEST_DECLARE_INPUT_PARAMETER(src) + TEST_DECLARE_OUTPUT_PARAMETER(dst) + + virtual void SetUp() + { + type = GET_PARAM(0); + ksize = GET_PARAM(1); + size = GET_PARAM(2); + borderType = GET_PARAM(3); + param = GET_PARAM(4); + useRoi = GET_PARAM(5); + } + + void random_roi(int minSize = 1) + { + if (minSize == 0) + minSize = ksize; + + Size roiSize = randomSize(minSize, MAX_VALUE); + Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256); + + Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70); + + UMAT_UPLOAD_INPUT_PARAMETER(src) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst) + } + + void Near() + { + int depth = CV_MAT_DEPTH(type); + bool isFP = depth >= CV_32F; + + if (isFP) + Near(1e-6, true); + else + Near(1, false); + } + + void Near(double threshold, bool relative) + { + if (relative) + { + EXPECT_MAT_NEAR_RELATIVE(dst, udst, threshold); + EXPECT_MAT_NEAR_RELATIVE(dst_roi, udst_roi, threshold); + } + else + { + EXPECT_MAT_NEAR(dst, udst, threshold); + EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Bilateral + +typedef FilterTestBase Bilateral; + +OCL_TEST_P(Bilateral, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + double sigmacolor = rng.uniform(20, 100); + double sigmaspace = rng.uniform(10, 40); + + OCL_OFF(cv::bilateralFilter(src_roi, dst_roi, ksize, sigmacolor, sigmaspace, borderType)); + OCL_ON(cv::bilateralFilter(usrc_roi, udst_roi, ksize, sigmacolor, sigmaspace, borderType)); + + Near(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// Laplacian + +typedef FilterTestBase LaplacianTest; + +OCL_TEST_P(LaplacianTest, Accuracy) +{ + double scale = param; + + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::Laplacian(src_roi, dst_roi, -1, ksize, scale, 0, borderType)); + OCL_ON(cv::Laplacian(usrc_roi, udst_roi, -1, ksize, scale, 0, borderType)); + + Near(); + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////////// +// Sobel + +typedef FilterTestBase SobelTest; + +OCL_TEST_P(SobelTest, Mat) +{ + int dx = size.width, dy = size.height; + double scale = param; + + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::Sobel(src_roi, dst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType)); + OCL_ON(cv::Sobel(usrc_roi, udst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType)); + + Near(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// Scharr + +typedef FilterTestBase ScharrTest; + +OCL_TEST_P(ScharrTest, Mat) +{ + int dx = size.width, dy = size.height; + double scale = param; + + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::Scharr(src_roi, dst_roi, -1, dx, dy, scale, /* delta */ 0, borderType)); + OCL_ON(cv::Scharr(usrc_roi, udst_roi, -1, dx, dy, scale, /* delta */ 0, borderType)); + + Near(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// GaussianBlur + +typedef FilterTestBase GaussianBlurTest; + +OCL_TEST_P(GaussianBlurTest, Mat) +{ + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + double sigma1 = rng.uniform(0.1, 1.0); + double sigma2 = rng.uniform(0.1, 1.0); + + OCL_OFF(cv::GaussianBlur(src_roi, dst_roi, Size(ksize, ksize), sigma1, sigma2, borderType)); + OCL_ON(cv::GaussianBlur(usrc_roi, udst_roi, Size(ksize, ksize), sigma1, sigma2, borderType)); + + Near(CV_MAT_DEPTH(type) == CV_8U ? 3 : 5e-5, false); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define FILTER_BORDER_SET_NO_ISOLATED \ + Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT, (BorderType)BORDER_WRAP, (BorderType)BORDER_REFLECT_101/*, \ + (int)BORDER_CONSTANT|BORDER_ISOLATED, (int)BORDER_REPLICATE|BORDER_ISOLATED, \ + (int)BORDER_REFLECT|BORDER_ISOLATED, (int)BORDER_WRAP|BORDER_ISOLATED, \ + (int)BORDER_REFLECT_101|BORDER_ISOLATED*/) // WRAP and ISOLATED are not supported by cv:: version + +#define FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED \ + Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT, /*(int)BORDER_WRAP,*/ (BorderType)BORDER_REFLECT_101/*, \ + (int)BORDER_CONSTANT|BORDER_ISOLATED, (int)BORDER_REPLICATE|BORDER_ISOLATED, \ + (int)BORDER_REFLECT|BORDER_ISOLATED, (int)BORDER_WRAP|BORDER_ISOLATED, \ + (int)BORDER_REFLECT_101|BORDER_ISOLATED*/) // WRAP and ISOLATED are not supported by cv:: version + +#define FILTER_TYPES Values(CV_8UC1, CV_8UC2, CV_8UC4, CV_32FC1, CV_32FC4, CV_64FC1, CV_64FC4) + +OCL_INSTANTIATE_TEST_CASE_P(Filter, Bilateral, Combine( + Values((MatType)CV_8UC1), + Values(5, 9), // kernel size + Values(Size(0, 0)), // not used + FILTER_BORDER_SET_NO_ISOLATED, + Values(0.0), // not used + Bool())); + +OCL_INSTANTIATE_TEST_CASE_P(Filter, LaplacianTest, Combine( + FILTER_TYPES, + Values(1, 3), // kernel size + Values(Size(0, 0)), // not used + FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED, + Values(1.0, 0.2, 3.0), // kernel scale + Bool())); + +OCL_INSTANTIATE_TEST_CASE_P(Filter, SobelTest, Combine( + FILTER_TYPES, + Values(3, 5), // kernel size + Values(Size(1, 0), Size(1, 1), Size(2, 0), Size(2, 1)), // dx, dy + FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED, + Values(0.0), // not used + Bool())); + +OCL_INSTANTIATE_TEST_CASE_P(Filter, ScharrTest, Combine( + FILTER_TYPES, + Values(0), // not used + Values(Size(0, 1), Size(1, 0)), // dx, dy + FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED, + Values(1.0, 0.2), // kernel scale + Bool())); + +OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlurTest, Combine( + FILTER_TYPES, + Values(3, 5), // kernel size + Values(Size(0, 0)), // not used + FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED, + Values(0.0), // not used + Bool())); + +} } // namespace cvtest::ocl + +#endif // HAVE_OPENCL diff --git a/modules/imgproc/test/ocl/test_imgproc.cpp b/modules/imgproc/test/ocl/test_imgproc.cpp index ae833406f0..d6799ce450 100644 --- a/modules/imgproc/test/ocl/test_imgproc.cpp +++ b/modules/imgproc/test/ocl/test_imgproc.cpp @@ -97,15 +97,9 @@ PARAM_TEST_CASE(ImgprocTestBase, MatType, void Near(double threshold = 0.0, bool relative = false) { if (relative) - { - EXPECT_MAT_NEAR_RELATIVE(dst, udst, threshold); - EXPECT_MAT_NEAR_RELATIVE(dst_roi, udst_roi, threshold); - } + OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold) else - { - EXPECT_MAT_NEAR(dst, udst, threshold); - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); - } + OCL_EXPECT_MATS_NEAR(dst, threshold) } }; @@ -158,10 +152,9 @@ PARAM_TEST_CASE(CopyMakeBorder, MatDepth, // depth UMAT_UPLOAD_OUTPUT_PARAMETER(dst) } - void Near(double threshold = 0.0) + void Near() { - EXPECT_MAT_NEAR(dst, udst, threshold); - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst, 0) } }; @@ -271,15 +264,44 @@ OCL_TEST_P(CornerHarris, DISABLED_Mat) struct Integral : public ImgprocTestBase { - int sdepth; + int sdepth, sqdepth; + + TEST_DECLARE_OUTPUT_PARAMETER(dst2) virtual void SetUp() { type = GET_PARAM(0); - blockSize = GET_PARAM(1); - sdepth = GET_PARAM(2); + sdepth = GET_PARAM(1); + sqdepth = GET_PARAM(2); useRoi = GET_PARAM(3); } + + virtual void random_roi() + { + ASSERT_EQ(CV_MAT_CN(type), 1); + + Size roiSize = randomSize(1, MAX_VALUE), isize = Size(roiSize.width + 1, roiSize.height + 1); + Border srcBorder = randomBorder(0, useRoi ? 2 : 0); + randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256); + + Border dstBorder = randomBorder(0, useRoi ? 2 : 0); + randomSubMat(dst, dst_roi, isize, dstBorder, sdepth, 5, 16); + + Border dst2Border = randomBorder(0, useRoi ? 2 : 0); + randomSubMat(dst2, dst2_roi, isize, dst2Border, sqdepth, 5, 16); + + UMAT_UPLOAD_INPUT_PARAMETER(src) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst) + UMAT_UPLOAD_OUTPUT_PARAMETER(dst2) + } + + void Near2(double threshold = 0.0, bool relative = false) + { + if (relative) + OCL_EXPECT_MATS_NEAR_RELATIVE(dst2, threshold) + else + OCL_EXPECT_MATS_NEAR(dst2, threshold) + } }; OCL_TEST_P(Integral, Mat1) @@ -297,19 +319,15 @@ OCL_TEST_P(Integral, Mat1) OCL_TEST_P(Integral, Mat2) { - Mat dst1; - UMat udst1; - for (int j = 0; j < test_loop_times; j++) { random_roi(); - OCL_OFF(cv::integral(src_roi, dst_roi, dst1, sdepth)); - OCL_ON(cv::integral(usrc_roi, udst_roi, udst1, sdepth)); + OCL_OFF(cv::integral(src_roi, dst_roi, dst2_roi, sdepth, sqdepth)); + OCL_ON(cv::integral(usrc_roi, udst_roi, udst2_roi, sdepth, sqdepth)); Near(); - if (cv::ocl::Device::getDefault().doubleFPConfig() > 0) - EXPECT_MAT_NEAR(dst1, udst1, 0.); + sqdepth == CV_32F ? Near2(1e-6, true) : Near2(); } } @@ -381,8 +399,7 @@ PARAM_TEST_CASE(CLAHETest, Size, double, bool) void Near(double threshold = 0.0) { - EXPECT_MAT_NEAR(dst, udst, threshold); - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst, threshold) } }; @@ -412,19 +429,21 @@ OCL_INSTANTIATE_TEST_CASE_P(Imgproc, EqualizeHist, Combine( OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CornerMinEigenVal, Combine( Values((MatType)CV_8UC1, (MatType)CV_32FC1), Values(3, 5), - Values((int)BORDER_CONSTANT, (int)BORDER_REPLICATE, (int)BORDER_REFLECT, (int)BORDER_REFLECT101), + Values((BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, + (BorderType)BORDER_REFLECT, (BorderType)BORDER_REFLECT101), Bool())); OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CornerHarris, Combine( Values((MatType)CV_8UC1, CV_32FC1), Values(3, 5), - Values( (int)BORDER_CONSTANT, (int)BORDER_REPLICATE, (int)BORDER_REFLECT, (int)BORDER_REFLECT_101), + Values( (BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, + (BorderType)BORDER_REFLECT, (BorderType)BORDER_REFLECT_101), Bool())); OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Integral, Combine( Values((MatType)CV_8UC1), // TODO does not work with CV_32F, CV_64F - Values(0), // not used - Values((MatType)CV_32SC1, (MatType)CV_32FC1), + Values(CV_32SC1, CV_32FC1), // desired sdepth + Values(CV_32FC1, CV_64FC1), // desired sqdepth Bool())); OCL_INSTANTIATE_TEST_CASE_P(Imgproc, Threshold, Combine( diff --git a/modules/imgproc/test/ocl/test_warp.cpp b/modules/imgproc/test/ocl/test_warp.cpp index c05c33590a..d5c75f0dad 100644 --- a/modules/imgproc/test/ocl/test_warp.cpp +++ b/modules/imgproc/test/ocl/test_warp.cpp @@ -104,8 +104,7 @@ PARAM_TEST_CASE(WarpTestBase, MatType, Interpolation, bool, bool) void Near(double threshold = 0.0) { - EXPECT_MAT_NEAR(dst, udst, threshold); - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst, threshold) } }; @@ -203,8 +202,7 @@ PARAM_TEST_CASE(Resize, MatType, double, double, Interpolation, bool) void Near(double threshold = 0.0) { - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); - EXPECT_MAT_NEAR(dst, udst, threshold); + OCL_EXPECT_MATS_NEAR(dst, threshold) } }; @@ -280,8 +278,7 @@ PARAM_TEST_CASE(Remap, MatDepth, Channels, std::pair, BorderTy void Near(double threshold = 0.0) { - EXPECT_MAT_NEAR(dst, udst, threshold); - EXPECT_MAT_NEAR(dst_roi, udst_roi, threshold); + OCL_EXPECT_MATS_NEAR(dst, threshold) } }; diff --git a/modules/java/android_test/src/org/opencv/test/imgproc/ImgprocTest.java b/modules/java/android_test/src/org/opencv/test/imgproc/ImgprocTest.java index 7971ea2f1f..15ea13b168 100644 --- a/modules/java/android_test/src/org/opencv/test/imgproc/ImgprocTest.java +++ b/modules/java/android_test/src/org/opencv/test/imgproc/ImgprocTest.java @@ -1225,7 +1225,7 @@ public class ImgprocTest extends OpenCVTestCase { expSqsum.put(2, 0, 0, 18, 36, 54); expSqsum.put(3, 0, 0, 27, 54, 81); - Imgproc.integral2(src, sum, sqsum, CvType.CV_64F); + Imgproc.integral2(src, sum, sqsum, CvType.CV_64F, CvType.CV_64F); assertMatEqual(expSum, sum, EPS); assertMatEqual(expSqsum, sqsum, EPS); @@ -1274,7 +1274,7 @@ public class ImgprocTest extends OpenCVTestCase { expTilted.put(0, 0, 0, 0); expTilted.put(1, 0, 0, 1); - Imgproc.integral3(src, sum, sqsum, tilted, CvType.CV_64F); + Imgproc.integral3(src, sum, sqsum, tilted, CvType.CV_64F, CvType.CV_64F); assertMatEqual(expSum, sum, EPS); assertMatEqual(expSqsum, sqsum, EPS); diff --git a/modules/objdetect/doc/cascade_classification.rst b/modules/objdetect/doc/cascade_classification.rst index ecd27c7935..c351dc7138 100644 --- a/modules/objdetect/doc/cascade_classification.rst +++ b/modules/objdetect/doc/cascade_classification.rst @@ -221,44 +221,6 @@ The function is parallelized with the TBB library. * (Python) A face detection example using cascade classifiers can be found at opencv_source_code/samples/python2/facedetect.py -CascadeClassifier::setImage -------------------------------- -Sets an image for detection. - -.. ocv:function:: bool CascadeClassifier::setImage( Ptr& feval, const Mat& image ) - -.. ocv:cfunction:: void cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascade, const CvArr* sum, const CvArr* sqsum, const CvArr* tilted_sum, double scale ) - - :param cascade: Haar classifier cascade (OpenCV 1.x API only). See :ocv:func:`CascadeClassifier::detectMultiScale` for more information. - - :param feval: Pointer to the feature evaluator used for computing features. - - :param image: Matrix of the type ``CV_8UC1`` containing an image where the features are computed. - -The function is automatically called by :ocv:func:`CascadeClassifier::detectMultiScale` at every image scale. But if you want to test various locations manually using :ocv:func:`CascadeClassifier::runAt`, you need to call the function before, so that the integral images are computed. - -.. note:: in the old API you need to supply integral images (that can be obtained using :ocv:cfunc:`Integral`) instead of the original image. - - -CascadeClassifier::runAt ----------------------------- -Runs the detector at the specified point. - -.. ocv:function:: int CascadeClassifier::runAt( Ptr& feval, Point pt, double& weight ) - -.. ocv:cfunction:: int cvRunHaarClassifierCascade( const CvHaarClassifierCascade* cascade, CvPoint pt, int start_stage=0 ) - - :param cascade: Haar classifier cascade (OpenCV 1.x API only). See :ocv:func:`CascadeClassifier::detectMultiScale` for more information. - - :param feval: Feature evaluator used for computing features. - - :param pt: Upper left point of the window where the features are computed. Size of the window is equal to the size of training images. - -The function returns 1 if the cascade classifier detects an object in the given location. -Otherwise, it returns negated index of the stage at which the candidate has been rejected. - -Use :ocv:func:`CascadeClassifier::setImage` to set the image for the detector to work with. - groupRectangles ------------------- Groups the object candidate rectangles. diff --git a/modules/objdetect/include/opencv2/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect.hpp index c3dee4a2bb..d7f5b1a4b0 100644 --- a/modules/objdetect/include/opencv2/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect.hpp @@ -149,143 +149,97 @@ enum { CASCADE_DO_CANNY_PRUNING = 1, CASCADE_DO_ROUGH_SEARCH = 8 }; -class CV_EXPORTS_W CascadeClassifier +class CV_EXPORTS_W BaseCascadeClassifier : public Algorithm { public: - CV_WRAP CascadeClassifier(); - CV_WRAP CascadeClassifier( const String& filename ); - virtual ~CascadeClassifier(); + virtual ~BaseCascadeClassifier(); + virtual bool empty() const = 0; + virtual bool load( const String& filename ) = 0; + virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize ) = 0; - CV_WRAP virtual bool empty() const; - CV_WRAP bool load( const String& filename ); - virtual bool read( const FileNode& node ); - CV_WRAP virtual void detectMultiScale( InputArray image, - CV_OUT std::vector& objects, - double scaleFactor = 1.1, - int minNeighbors = 3, int flags = 0, - Size minSize = Size(), - Size maxSize = Size() ); + virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize ) = 0; - CV_WRAP virtual void detectMultiScale( InputArray image, - CV_OUT std::vector& objects, - CV_OUT std::vector& numDetections, - double scaleFactor=1.1, - int minNeighbors=3, int flags=0, - Size minSize=Size(), - Size maxSize=Size() ); - - CV_WRAP virtual void detectMultiScale( InputArray image, + virtual void detectMultiScale( InputArray image, CV_OUT std::vector& objects, CV_OUT std::vector& rejectLevels, CV_OUT std::vector& levelWeights, - double scaleFactor = 1.1, - int minNeighbors = 3, int flags = 0, - Size minSize = Size(), - Size maxSize = Size(), - bool outputRejectLevels = false ); + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize, + bool outputRejectLevels ) = 0; + virtual bool isOldFormatCascade() const = 0; + virtual Size getOriginalWindowSize() const = 0; + virtual int getFeatureType() const = 0; + virtual void* getOldCascade() = 0; - bool isOldFormatCascade() const; - virtual Size getOriginalWindowSize() const; - int getFeatureType() const; - bool setImage( const Mat& ); - -protected: - virtual bool detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, - int stripSize, int yStep, double factor, std::vector& candidates, - std::vector& rejectLevels, std::vector& levelWeights, bool outputRejectLevels = false ); - - virtual void detectMultiScaleNoGrouping( const Mat& image, std::vector& candidates, - std::vector& rejectLevels, std::vector& levelWeights, - double scaleFactor, Size minObjectSize, Size maxObjectSize, - bool outputRejectLevels = false ); - -protected: - enum { BOOST = 0 - }; - enum { DO_CANNY_PRUNING = CASCADE_DO_CANNY_PRUNING, - SCALE_IMAGE = CASCADE_SCALE_IMAGE, - FIND_BIGGEST_OBJECT = CASCADE_FIND_BIGGEST_OBJECT, - DO_ROUGH_SEARCH = CASCADE_DO_ROUGH_SEARCH - }; - - friend class CascadeClassifierInvoker; - - template - friend int predictOrdered( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - template - friend int predictCategorical( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - template - friend int predictOrderedStump( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - template - friend int predictCategoricalStump( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - bool setImage( Ptr& feval, const Mat& image); - virtual int runAt( Ptr& feval, Point pt, double& weight ); - - class Data - { - public: - struct CV_EXPORTS DTreeNode - { - int featureIdx; - float threshold; // for ordered features only - int left; - int right; - }; - - struct CV_EXPORTS DTree - { - int nodeCount; - }; - - struct CV_EXPORTS Stage - { - int first; - int ntrees; - float threshold; - }; - - bool read(const FileNode &node); - - bool isStumpBased; - - int stageType; - int featureType; - int ncategories; - Size origWinSize; - - std::vector stages; - std::vector classifiers; - std::vector nodes; - std::vector leaves; - std::vector subsets; - }; - - Data data; - Ptr featureEvaluator; - Ptr oldCascade; - -public: class CV_EXPORTS MaskGenerator { public: virtual ~MaskGenerator() {} - virtual cv::Mat generateMask(const cv::Mat& src)=0; - virtual void initializeMask(const cv::Mat& /*src*/) {}; + virtual Mat generateMask(const Mat& src)=0; + virtual void initializeMask(const Mat& /*src*/) {}; }; - void setMaskGenerator(Ptr maskGenerator); - Ptr getMaskGenerator(); - - void setFaceDetectionMaskGenerator(); - -protected: - Ptr maskGenerator; + virtual void setMaskGenerator(const Ptr& maskGenerator) = 0; + virtual Ptr getMaskGenerator() = 0; }; +class CV_EXPORTS_W CascadeClassifier +{ +public: + CV_WRAP CascadeClassifier(); + CV_WRAP CascadeClassifier(const String& filename); + ~CascadeClassifier(); + CV_WRAP bool empty() const; + CV_WRAP bool load( const String& filename ); + CV_WRAP bool read( const FileNode& node ); + CV_WRAP void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size() ); + + CV_WRAP void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor=1.1, + int minNeighbors=3, int flags=0, + Size minSize=Size(), + Size maxSize=Size() ); + + CV_WRAP void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& rejectLevels, + CV_OUT std::vector& levelWeights, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size(), + bool outputRejectLevels = false ); + + CV_WRAP bool isOldFormatCascade() const; + CV_WRAP Size getOriginalWindowSize() const; + CV_WRAP int getFeatureType() const; + void* getOldCascade(); + + void setMaskGenerator(const Ptr& maskGenerator); + Ptr getMaskGenerator(); + + Ptr cc; +}; + +CV_EXPORTS Ptr createFaceDetectionMaskGenerator(); + //////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector ////////////// // struct for detection region of interest (ROI) diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 92b685c5dd..2922375607 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -430,7 +430,6 @@ void groupRectangles_meanshift(std::vector& rectList, std::vector& } - FeatureEvaluator::~FeatureEvaluator() {} bool FeatureEvaluator::read(const FileNode&) {return true;} Ptr FeatureEvaluator::clone() const { return Ptr(); } @@ -834,25 +833,20 @@ Ptr FeatureEvaluator::create( int featureType ) //---------------------------------------- Classifier Cascade -------------------------------------------- -CascadeClassifier::CascadeClassifier() +CascadeClassifierImpl::CascadeClassifierImpl() { } -CascadeClassifier::CascadeClassifier(const String& filename) -{ - load(filename); -} - -CascadeClassifier::~CascadeClassifier() +CascadeClassifierImpl::~CascadeClassifierImpl() { } -bool CascadeClassifier::empty() const +bool CascadeClassifierImpl::empty() const { return !oldCascade && data.stages.empty(); } -bool CascadeClassifier::load(const String& filename) +bool CascadeClassifierImpl::load(const String& filename) { oldCascade.release(); data = Data(); @@ -862,7 +856,7 @@ bool CascadeClassifier::load(const String& filename) if( !fs.isOpened() ) return false; - if( read(fs.getFirstTopLevelNode()) ) + if( read_(fs.getFirstTopLevelNode()) ) return true; fs.release(); @@ -871,7 +865,12 @@ bool CascadeClassifier::load(const String& filename) return !oldCascade.empty(); } -int CascadeClassifier::runAt( Ptr& evaluator, Point pt, double& weight ) +void CascadeClassifierImpl::read(const FileNode& node) +{ + read_(node); +} + +int CascadeClassifierImpl::runAt( Ptr& evaluator, Point pt, double& weight ) { CV_Assert( !oldCascade ); @@ -905,33 +904,33 @@ int CascadeClassifier::runAt( Ptr& evaluator, Point pt, double } } -bool CascadeClassifier::setImage( Ptr& evaluator, const Mat& image ) +bool CascadeClassifierImpl::setImage( Ptr& evaluator, const Mat& image ) { return empty() ? false : evaluator->setImage(image, data.origWinSize); } -void CascadeClassifier::setMaskGenerator(Ptr _maskGenerator) +void CascadeClassifierImpl::setMaskGenerator(const Ptr& _maskGenerator) { maskGenerator=_maskGenerator; } -Ptr CascadeClassifier::getMaskGenerator() +Ptr CascadeClassifierImpl::getMaskGenerator() { return maskGenerator; } -void CascadeClassifier::setFaceDetectionMaskGenerator() +Ptr createFaceDetectionMaskGenerator() { #ifdef HAVE_TEGRA_OPTIMIZATION - setMaskGenerator(tegra::getCascadeClassifierMaskGenerator(*this)); + return tegra::getCascadeClassifierMaskGenerator(*this); #else - setMaskGenerator(Ptr()); + return Ptr(); #endif } class CascadeClassifierInvoker : public ParallelLoopBody { public: - CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, + CascadeClassifierInvoker( CascadeClassifierImpl& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, std::vector& _vec, std::vector& _levels, std::vector& _weights, bool outputLevels, const Mat& _mask, Mutex* _mtx) { classifier = &_cc; @@ -950,7 +949,8 @@ public: { Ptr evaluator = classifier->featureEvaluator->clone(); - Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor)); + Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), + cvRound(classifier->data.origWinSize.height * scalingFactor)); int y1 = range.start * stripSize; int y2 = std::min(range.end * stripSize, processingRectSize.height); @@ -995,7 +995,7 @@ public: } } - CascadeClassifier* classifier; + CascadeClassifierImpl* classifier; std::vector* rectangles; Size processingRectSize; int stripSize, yStep; @@ -1010,7 +1010,7 @@ struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } } struct getNeighbors { int operator ()(const CvAvgComp& e) const { return e.neighbors; } }; -bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, +bool CascadeClassifierImpl::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, int stripSize, int yStep, double factor, std::vector& candidates, std::vector& levels, std::vector& weights, bool outputRejectLevels ) { @@ -1051,27 +1051,33 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz return true; } -bool CascadeClassifier::isOldFormatCascade() const +bool CascadeClassifierImpl::isOldFormatCascade() const { return !oldCascade.empty(); } -int CascadeClassifier::getFeatureType() const +int CascadeClassifierImpl::getFeatureType() const { return featureEvaluator->getFeatureType(); } -Size CascadeClassifier::getOriginalWindowSize() const +Size CascadeClassifierImpl::getOriginalWindowSize() const { return data.origWinSize; } -bool CascadeClassifier::setImage(const Mat& image) +bool CascadeClassifierImpl::setImage(InputArray _image) { + Mat image = _image.getMat(); return featureEvaluator->setImage(image, data.origWinSize); } +void* CascadeClassifierImpl::getOldCascade() +{ + return oldCascade; +} + static void detectMultiScaleOldFormat( const Mat& image, Ptr oldCascade, std::vector& objects, std::vector& rejectLevels, @@ -1090,7 +1096,7 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr& candidates, +void CascadeClassifierImpl::detectMultiScaleNoGrouping( const Mat& image, std::vector& candidates, std::vector& rejectLevels, std::vector& levelWeights, double scaleFactor, Size minObjectSize, Size maxObjectSize, bool outputRejectLevels ) @@ -1154,7 +1160,7 @@ void CascadeClassifier::detectMultiScaleNoGrouping( const Mat& image, std::vecto } } -void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& objects, +void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector& objects, std::vector& rejectLevels, std::vector& levelWeights, double scaleFactor, int minNeighbors, @@ -1189,7 +1195,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& } } -void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& objects, +void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector& objects, double scaleFactor, int minNeighbors, int flags, Size minObjectSize, Size maxObjectSize) { @@ -1200,7 +1206,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& minNeighbors, flags, minObjectSize, maxObjectSize ); } -void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& objects, +void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector& objects, std::vector& numDetections, double scaleFactor, int minNeighbors, int flags, Size minObjectSize, Size maxObjectSize ) @@ -1229,7 +1235,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& } } -bool CascadeClassifier::Data::read(const FileNode &root) +bool CascadeClassifierImpl::Data::read(const FileNode &root) { static const float THRESHOLD_EPS = 1e-5f; @@ -1339,7 +1345,7 @@ bool CascadeClassifier::Data::read(const FileNode &root) return true; } -bool CascadeClassifier::read(const FileNode& root) +bool CascadeClassifierImpl::read_(const FileNode& root) { if( !data.read(root) ) return false; @@ -1356,4 +1362,117 @@ bool CascadeClassifier::read(const FileNode& root) template<> void DefaultDeleter::operator ()(CvHaarClassifierCascade* obj) const { cvReleaseHaarClassifierCascade(&obj); } + +BaseCascadeClassifier::~BaseCascadeClassifier() +{ +} + +CascadeClassifier::CascadeClassifier() {} +CascadeClassifier::CascadeClassifier(const String& filename) +{ + load(filename); +} + +CascadeClassifier::~CascadeClassifier() +{ +} + +bool CascadeClassifier::empty() const +{ + return cc.empty() || cc->empty(); +} + +bool CascadeClassifier::load( const String& filename ) +{ + cc = makePtr(); + if(!cc->load(filename)) + cc.release(); + return !empty(); +} + +bool CascadeClassifier::read(const FileNode &root) +{ + Ptr ccimpl; + bool ok = ccimpl->read_(root); + if( ok ) + cc = ccimpl.staticCast(); + else + cc.release(); + return ok; +} + +void CascadeClassifier::detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, + Size maxSize ) +{ + CV_Assert(!empty()); + cc->detectMultiScale(image, objects, scaleFactor, minNeighbors, flags, minSize, maxSize); +} + +void CascadeClassifier::detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize ) +{ + CV_Assert(!empty()); + cc->detectMultiScale(image, objects, numDetections, + scaleFactor, minNeighbors, flags, minSize, maxSize); +} + +void CascadeClassifier::detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& rejectLevels, + CV_OUT std::vector& levelWeights, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize, + bool outputRejectLevels ) +{ + CV_Assert(!empty()); + cc->detectMultiScale(image, objects, rejectLevels, levelWeights, + scaleFactor, minNeighbors, flags, + minSize, maxSize, outputRejectLevels); +} + +bool CascadeClassifier::isOldFormatCascade() const +{ + CV_Assert(!empty()); + return cc->isOldFormatCascade(); +} + +Size CascadeClassifier::getOriginalWindowSize() const +{ + CV_Assert(!empty()); + return cc->getOriginalWindowSize(); +} + +int CascadeClassifier::getFeatureType() const +{ + CV_Assert(!empty()); + return cc->getFeatureType(); +} + +void* CascadeClassifier::getOldCascade() +{ + CV_Assert(!empty()); + return cc->getOldCascade(); +} + +void CascadeClassifier::setMaskGenerator(const Ptr& maskGenerator) +{ + CV_Assert(!empty()); + cc->setMaskGenerator(maskGenerator); +} + +Ptr CascadeClassifier::getMaskGenerator() +{ + CV_Assert(!empty()); + return cc->getMaskGenerator(); +} + } // namespace cv diff --git a/modules/objdetect/src/cascadedetect.hpp b/modules/objdetect/src/cascadedetect.hpp index de3303e4aa..2505ea0711 100644 --- a/modules/objdetect/src/cascadedetect.hpp +++ b/modules/objdetect/src/cascadedetect.hpp @@ -3,6 +3,132 @@ namespace cv { +class CascadeClassifierImpl : public BaseCascadeClassifier +{ +public: + CascadeClassifierImpl(); + virtual ~CascadeClassifierImpl(); + + bool empty() const; + bool load( const String& filename ); + void read( const FileNode& node ); + bool read_( const FileNode& node ); + void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size() ); + + void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor=1.1, + int minNeighbors=3, int flags=0, + Size minSize=Size(), + Size maxSize=Size() ); + + void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& rejectLevels, + CV_OUT std::vector& levelWeights, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size(), + bool outputRejectLevels = false ); + + + bool isOldFormatCascade() const; + Size getOriginalWindowSize() const; + int getFeatureType() const; + bool setImage( InputArray ); + void* getOldCascade(); + + void setMaskGenerator(const Ptr& maskGenerator); + Ptr getMaskGenerator(); + +protected: + bool detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, + int stripSize, int yStep, double factor, std::vector& candidates, + std::vector& rejectLevels, std::vector& levelWeights, bool outputRejectLevels = false ); + + void detectMultiScaleNoGrouping( const Mat& image, std::vector& candidates, + std::vector& rejectLevels, std::vector& levelWeights, + double scaleFactor, Size minObjectSize, Size maxObjectSize, + bool outputRejectLevels = false ); + + enum { BOOST = 0 + }; + enum { DO_CANNY_PRUNING = CASCADE_DO_CANNY_PRUNING, + SCALE_IMAGE = CASCADE_SCALE_IMAGE, + FIND_BIGGEST_OBJECT = CASCADE_FIND_BIGGEST_OBJECT, + DO_ROUGH_SEARCH = CASCADE_DO_ROUGH_SEARCH + }; + + friend class CascadeClassifierInvoker; + + template + friend int predictOrdered( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + template + friend int predictCategorical( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + template + friend int predictOrderedStump( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + template + friend int predictCategoricalStump( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + bool setImage( Ptr& feval, const Mat& image); + int runAt( Ptr& feval, Point pt, double& weight ); + + class Data + { + public: + struct DTreeNode + { + int featureIdx; + float threshold; // for ordered features only + int left; + int right; + }; + + struct DTree + { + int nodeCount; + }; + + struct Stage + { + int first; + int ntrees; + float threshold; + }; + + bool read(const FileNode &node); + + bool isStumpBased; + + int stageType; + int featureType; + int ncategories; + Size origWinSize; + + std::vector stages; + std::vector classifiers; + std::vector nodes; + std::vector leaves; + std::vector subsets; + }; + + Data data; + Ptr featureEvaluator; + Ptr oldCascade; + + Ptr maskGenerator; +}; + #define CC_CASCADE_PARAMS "cascadeParams" #define CC_STAGE_TYPE "stageType" #define CC_FEATURE_TYPE "featureType" @@ -322,30 +448,31 @@ inline void HOGEvaluator::Feature :: updatePtrs( const std::vector &_hist, //---------------------------------------------- predictor functions ------------------------------------- template -inline int predictOrdered( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictOrdered( CascadeClassifierImpl& cascade, + Ptr &_featureEvaluator, double& sum ) { int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; FEval& featureEvaluator = (FEval&)*_featureEvaluator; float* cascadeLeaves = &cascade.data.leaves[0]; - CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; - CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; + CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; + CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; + CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0]; for( int si = 0; si < nstages; si++ ) { - CascadeClassifier::Data::Stage& stage = cascadeStages[si]; + CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si]; int wi, ntrees = stage.ntrees; sum = 0; for( wi = 0; wi < ntrees; wi++ ) { - CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi]; + CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi]; int idx = 0, root = nodeOfs; do { - CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; + CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx]; double val = featureEvaluator(node.featureIdx); idx = val < node.threshold ? node.left : node.right; } @@ -361,7 +488,8 @@ inline int predictOrdered( CascadeClassifier& cascade, Ptr &_f } template -inline int predictCategorical( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictCategorical( CascadeClassifierImpl& cascade, + Ptr &_featureEvaluator, double& sum ) { int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; @@ -369,23 +497,23 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr size_t subsetSize = (cascade.data.ncategories + 31)/32; int* cascadeSubsets = &cascade.data.subsets[0]; float* cascadeLeaves = &cascade.data.leaves[0]; - CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; - CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; + CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; + CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; + CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0]; for(int si = 0; si < nstages; si++ ) { - CascadeClassifier::Data::Stage& stage = cascadeStages[si]; + CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si]; int wi, ntrees = stage.ntrees; sum = 0; for( wi = 0; wi < ntrees; wi++ ) { - CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi]; + CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi]; int idx = 0, root = nodeOfs; do { - CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; + CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx]; int c = featureEvaluator(node.featureIdx); const int* subset = &cascadeSubsets[(root + idx)*subsetSize]; idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right; @@ -402,24 +530,25 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr } template -inline int predictOrderedStump( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictOrderedStump( CascadeClassifierImpl& cascade, + Ptr &_featureEvaluator, double& sum ) { int nodeOfs = 0, leafOfs = 0; FEval& featureEvaluator = (FEval&)*_featureEvaluator; float* cascadeLeaves = &cascade.data.leaves[0]; - CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; + CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; + CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0]; int nstages = (int)cascade.data.stages.size(); for( int stageIdx = 0; stageIdx < nstages; stageIdx++ ) { - CascadeClassifier::Data::Stage& stage = cascadeStages[stageIdx]; + CascadeClassifierImpl::Data::Stage& stage = cascadeStages[stageIdx]; sum = 0.0; int ntrees = stage.ntrees; for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 ) { - CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs]; + CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[nodeOfs]; double value = featureEvaluator(node.featureIdx); sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ]; } @@ -432,7 +561,8 @@ inline int predictOrderedStump( CascadeClassifier& cascade, Ptr -inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictCategoricalStump( CascadeClassifierImpl& cascade, + Ptr &_featureEvaluator, double& sum ) { int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; @@ -440,15 +570,15 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr _Tp *ptr(int y = 0); - template const _Tp *ptr(int y = 0) const; - //! matrix transposition oclMat t() const; diff --git a/modules/ocl/include/opencv2/ocl.hpp b/modules/ocl/include/opencv2/ocl.hpp index 19af00bef4..1f03170e5f 100644 --- a/modules/ocl/include/opencv2/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl.hpp @@ -378,14 +378,6 @@ namespace cv //! returns true if oclMatrix data is NULL bool empty() const; - //! returns pointer to y-th row - uchar* ptr(int y = 0); - const uchar *ptr(int y = 0) const; - - //! template version of the above method - template _Tp *ptr(int y = 0); - template const _Tp *ptr(int y = 0) const; - //! matrix transposition oclMat t() const; diff --git a/modules/ocl/include/opencv2/ocl/matrix_operations.hpp b/modules/ocl/include/opencv2/ocl/matrix_operations.hpp index 76db479035..ab1fe4fb70 100644 --- a/modules/ocl/include/opencv2/ocl/matrix_operations.hpp +++ b/modules/ocl/include/opencv2/ocl/matrix_operations.hpp @@ -456,36 +456,6 @@ namespace cv return data == 0; } - - - inline uchar *oclMat::ptr(int y) - { - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - CV_Error(Error::GpuNotSupported, "This function hasn't been supported yet.\n"); - return data + step * y; - } - - inline const uchar *oclMat::ptr(int y) const - { - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - CV_Error(Error::GpuNotSupported, "This function hasn't been supported yet.\n"); - return data + step * y; - } - - template inline _Tp *oclMat::ptr(int y) - { - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - CV_Error(Error::GpuNotSupported, "This function hasn't been supported yet.\n"); - return (_Tp *)(data + step * y); - } - - template inline const _Tp *oclMat::ptr(int y) const - { - CV_DbgAssert( (unsigned)y < (unsigned)rows ); - CV_Error(Error::GpuNotSupported, "This function hasn't been supported yet.\n"); - return (const _Tp *)(data + step * y); - } - inline oclMat oclMat::t() const { oclMat tmp; diff --git a/modules/ocl/perf/perf_moments.cpp b/modules/ocl/perf/perf_moments.cpp index c5d616f83d..631031ecb4 100644 --- a/modules/ocl/perf/perf_moments.cpp +++ b/modules/ocl/perf/perf_moments.cpp @@ -73,10 +73,10 @@ PERF_TEST_P(MomentsFixture, Moments, Mat src(srcSize, type), dst(7, 1, CV_64F); randu(src, 0, 255); - oclMat src_d(src); cv::Moments mom; if (RUN_OCL_IMPL) { + oclMat src_d(src); OCL_TEST_CYCLE() mom = cv::ocl::ocl_moments(src_d, binaryImage); } else if (RUN_PLAIN_IMPL) diff --git a/modules/ocl/src/brute_force_matcher.cpp b/modules/ocl/src/brute_force_matcher.cpp index d0e09320de..ca16f43462 100644 --- a/modules/ocl/src/brute_force_matcher.cpp +++ b/modules/ocl/src/brute_force_matcher.cpp @@ -676,7 +676,7 @@ void cv::ocl::BruteForceMatcher_OCL_base::matchCollection(const oclMat &query, c ensureSizeIsEnough(1, nQuery, CV_32S, imgIdx); ensureSizeIsEnough(1, nQuery, CV_32F, distance); - matchDispatcher(query, (const oclMat *)trainCollection.ptr(), trainCollection.cols, masks, trainIdx, imgIdx, distance, distType); + matchDispatcher(query, &trainCollection, trainCollection.cols, masks, trainIdx, imgIdx, distance, distType); return; } diff --git a/modules/ocl/src/cl_operations.cpp b/modules/ocl/src/cl_operations.cpp index 1e41577235..aa44c48749 100644 --- a/modules/ocl/src/cl_operations.cpp +++ b/modules/ocl/src/cl_operations.cpp @@ -290,8 +290,9 @@ void openCLFree(void *devPtr) } #else // TODO FIXIT Attach clReleaseMemObject call to event completion callback - Context* ctx = Context::getContext(); - clFinish(getClCommandQueue(ctx)); + // TODO 2013/12/04 Disable workaround + // Context* ctx = Context::getContext(); + // clFinish(getClCommandQueue(ctx)); #endif openCLSafeCall(clReleaseMemObject(data.mainBuffer)); } diff --git a/modules/ocl/src/haar.cpp b/modules/ocl/src/haar.cpp index 7c3277e99a..a023f8a042 100644 --- a/modules/ocl/src/haar.cpp +++ b/modules/ocl/src/haar.cpp @@ -655,7 +655,7 @@ void OclCascadeClassifier::detectMultiScale(oclMat &gimg, CV_OUT std::vectorcount; + float stagethreshold = stageinfo->threshold; int lcl_off = (lid_y*DATA_SIZE_X)+(lid_x); - for(int nodeloop = 0; nodeloop < stageinfo.x; nodecounter++,nodeloop++ ) + for(int nodeloop = 0; nodeloop < stagecount; nodecounter++,nodeloop++ ) { // simple macro to extract shorts from int #define M0(_t) ((_t)&0xFFFF) @@ -355,14 +357,17 @@ __kernel void __attribute__((reqd_work_group_size(8,8,1)))gpuRunHaarClassifierCa variance_norm_factor = variance_norm_factor * correction - mean * mean; variance_norm_factor = variance_norm_factor >=0.f ? sqrt(variance_norm_factor) : 1.f; - for(int stageloop = start_stage; (stageloop < split_stage) && result; stageloop++ ) + for(int stageloop = start_stage; (stageloop < split_stage) && result; stageloop++ ) { float stage_sum = 0.f; - int2 stageinfo = *(global int2*)(stagecascadeptr+stageloop); - float stagethreshold = as_float(stageinfo.y); - for(int nodeloop = 0; nodeloop < stageinfo.x; ) + __global GpuHidHaarStageClassifier* stageinfo = (__global GpuHidHaarStageClassifier*) + ((__global uchar*)stagecascadeptr+stageloop*sizeof(GpuHidHaarStageClassifier)); + int stagecount = stageinfo->count; + float stagethreshold = stageinfo->threshold; + for(int nodeloop = 0; nodeloop < stagecount; ) { - __global GpuHidHaarTreeNode* currentnodeptr = (nodeptr + nodecounter); + __global GpuHidHaarTreeNode* currentnodeptr = (__global GpuHidHaarTreeNode*) + (((__global uchar*)nodeptr) + nodecounter * sizeof(GpuHidHaarTreeNode)); int4 info1 = *(__global int4*)(&(currentnodeptr->p[0][0])); int4 info2 = *(__global int4*)(&(currentnodeptr->p[1][0])); @@ -418,7 +423,7 @@ __kernel void __attribute__((reqd_work_group_size(8,8,1)))gpuRunHaarClassifierCa #endif } - result = (stage_sum >= stagethreshold); + result = (stage_sum >= stagethreshold) ? 1 : 0; } if(factor < 2) { @@ -447,14 +452,17 @@ __kernel void __attribute__((reqd_work_group_size(8,8,1)))gpuRunHaarClassifierCa lclcount[0]=0; barrier(CLK_LOCAL_MEM_FENCE); - int2 stageinfo = *(global int2*)(stagecascadeptr+stageloop); - float stagethreshold = as_float(stageinfo.y); + //int2 stageinfo = *(global int2*)(stagecascadeptr+stageloop); + __global GpuHidHaarStageClassifier* stageinfo = (__global GpuHidHaarStageClassifier*) + ((__global uchar*)stagecascadeptr+stageloop*sizeof(GpuHidHaarStageClassifier)); + int stagecount = stageinfo->count; + float stagethreshold = stageinfo->threshold; int perfscale = queuecount > 4 ? 3 : 2; int queuecount_loop = (queuecount + (1<> perfscale; int lcl_compute_win = lcl_sz >> perfscale; int lcl_compute_win_id = (lcl_id >>(6-perfscale)); - int lcl_loops = (stageinfo.x + lcl_compute_win -1) >> (6-perfscale); + int lcl_loops = (stagecount + lcl_compute_win -1) >> (6-perfscale); int lcl_compute_id = lcl_id - (lcl_compute_win_id << (6-perfscale)); for(int queueloop=0; queueloopp[0][0])); int4 info2 = *(__global int4*)(&(currentnodeptr->p[1][0])); @@ -549,7 +557,7 @@ __kernel void __attribute__((reqd_work_group_size(8,8,1)))gpuRunHaarClassifierCa queuecount = lclcount[0]; barrier(CLK_LOCAL_MEM_FENCE); - nodecounter += stageinfo.x; + nodecounter += stagecount; }//end for(int stageloop = splitstage; stageloop< endstage && queuecount>0;stageloop++) if(lcl_id> 16; int totalgrp = scaleinfo1.y & 0xffff; float factor = as_float(scaleinfo1.w); @@ -174,15 +173,18 @@ __kernel void gpuRunHaarClassifierCascade_scaled2( for (int stageloop = start_stage; (stageloop < end_stage) && result; stageloop++) { float stage_sum = 0.f; - int stagecount = stagecascadeptr[stageloop].count; + __global GpuHidHaarStageClassifier* stageinfo = (__global GpuHidHaarStageClassifier*) + (((__global uchar*)stagecascadeptr_)+stageloop*sizeof(GpuHidHaarStageClassifier)); + int stagecount = stageinfo->count; for (int nodeloop = 0; nodeloop < stagecount;) { - __global GpuHidHaarTreeNode *currentnodeptr = (nodeptr + nodecounter); + __global GpuHidHaarTreeNode* currentnodeptr = (__global GpuHidHaarTreeNode*) + (((__global uchar*)nodeptr_) + nodecounter * sizeof(GpuHidHaarTreeNode)); int4 info1 = *(__global int4 *)(&(currentnodeptr->p[0][0])); int4 info2 = *(__global int4 *)(&(currentnodeptr->p[1][0])); int4 info3 = *(__global int4 *)(&(currentnodeptr->p[2][0])); float4 w = *(__global float4 *)(&(currentnodeptr->weight[0])); - float3 alpha3 = *(__global float3 *)(&(currentnodeptr->alpha[0])); + float3 alpha3 = *(__global float3*)(&(currentnodeptr->alpha[0])); float nodethreshold = w.w * variance_norm_factor; info1.x += p_offset; @@ -204,7 +206,7 @@ __kernel void gpuRunHaarClassifierCascade_scaled2( sum[clamp(mad24(info3.w, step, info3.x), 0, max_idx)] + sum[clamp(mad24(info3.w, step, info3.z), 0, max_idx)]) * w.z; - bool passThres = classsum >= nodethreshold; + bool passThres = (classsum >= nodethreshold) ? 1 : 0; #if STUMP_BASED stage_sum += passThres ? alpha3.y : alpha3.x; @@ -234,7 +236,8 @@ __kernel void gpuRunHaarClassifierCascade_scaled2( } #endif } - result = (int)(stage_sum >= stagecascadeptr[stageloop].threshold); + + result = (stage_sum >= stageinfo->threshold) ? 1 : 0; } barrier(CLK_LOCAL_MEM_FENCE); @@ -281,11 +284,14 @@ __kernel void gpuRunHaarClassifierCascade_scaled2( } } } -__kernel void gpuscaleclassifier(global GpuHidHaarTreeNode *orinode, global GpuHidHaarTreeNode *newnode, float scale, float weight_scale, int nodenum) +__kernel void gpuscaleclassifier(global GpuHidHaarTreeNode *orinode, global GpuHidHaarTreeNode *newnode, float scale, float weight_scale, const int nodenum) { - int counter = get_global_id(0); + const int counter = get_global_id(0); int tr_x[3], tr_y[3], tr_h[3], tr_w[3], i = 0; - GpuHidHaarTreeNode t1 = *(orinode + counter); + GpuHidHaarTreeNode t1 = *(__global GpuHidHaarTreeNode*) + (((__global uchar*)orinode) + counter * sizeof(GpuHidHaarTreeNode)); + __global GpuHidHaarTreeNode* pNew = (__global GpuHidHaarTreeNode*) + (((__global uchar*)newnode) + (counter + nodenum) * sizeof(GpuHidHaarTreeNode)); #pragma unroll for (i = 0; i < 3; i++) @@ -297,22 +303,21 @@ __kernel void gpuscaleclassifier(global GpuHidHaarTreeNode *orinode, global GpuH } t1.weight[0] = -(t1.weight[1] * tr_h[1] * tr_w[1] + t1.weight[2] * tr_h[2] * tr_w[2]) / (tr_h[0] * tr_w[0]); - counter += nodenum; #pragma unroll for (i = 0; i < 3; i++) { - newnode[counter].p[i][0] = tr_x[i]; - newnode[counter].p[i][1] = tr_y[i]; - newnode[counter].p[i][2] = tr_x[i] + tr_w[i]; - newnode[counter].p[i][3] = tr_y[i] + tr_h[i]; - newnode[counter].weight[i] = t1.weight[i] * weight_scale; + pNew->p[i][0] = tr_x[i]; + pNew->p[i][1] = tr_y[i]; + pNew->p[i][2] = tr_x[i] + tr_w[i]; + pNew->p[i][3] = tr_y[i] + tr_h[i]; + pNew->weight[i] = t1.weight[i] * weight_scale; } - newnode[counter].left = t1.left; - newnode[counter].right = t1.right; - newnode[counter].threshold = t1.threshold; - newnode[counter].alpha[0] = t1.alpha[0]; - newnode[counter].alpha[1] = t1.alpha[1]; - newnode[counter].alpha[2] = t1.alpha[2]; + pNew->left = t1.left; + pNew->right = t1.right; + pNew->threshold = t1.threshold; + pNew->alpha[0] = t1.alpha[0]; + pNew->alpha[1] = t1.alpha[1]; + pNew->alpha[2] = t1.alpha[2]; } diff --git a/modules/ocl/src/opencl/imgproc_threshold.cl b/modules/ocl/src/opencl/imgproc_threshold.cl index 63e410297b..85631be368 100644 --- a/modules/ocl/src/opencl/imgproc_threshold.cl +++ b/modules/ocl/src/opencl/imgproc_threshold.cl @@ -74,11 +74,11 @@ __kernel void threshold(__global const T * restrict src, int src_offset, int src VT vthresh = (VT)(thresh); #ifdef THRESH_BINARY - VT vecValue = sdata > vthresh ? max_val : (VT)(0); + VT vecValue = sdata > vthresh ? (VT)max_val : (VT)(0); #elif defined THRESH_BINARY_INV - VT vecValue = sdata > vthresh ? (VT)(0) : max_val; + VT vecValue = sdata > vthresh ? (VT)(0) : (VT)max_val; #elif defined THRESH_TRUNC - VT vecValue = sdata > vthresh ? thresh : sdata; + VT vecValue = sdata > vthresh ? (VT)thresh : sdata; #elif defined THRESH_TOZERO VT vecValue = sdata > vthresh ? sdata : (VT)(0); #elif defined THRESH_TOZERO_INV diff --git a/modules/photo/doc/cloning.rst b/modules/photo/doc/cloning.rst new file mode 100644 index 0000000000..384c6b676a --- /dev/null +++ b/modules/photo/doc/cloning.rst @@ -0,0 +1,99 @@ +Seamless Cloning +================ + +.. highlight:: cpp + +seamlessClone +------------- +Image editing tasks concern either global changes (color/intensity corrections, filters, deformations) or local changes concerned to a selection. +Here we are interested in achieving local changes, ones that are restricted to a region manually selected (ROI), in a seamless and effortless manner. +The extent of the changes ranges from slight distortions to complete replacement by novel content. + +.. ocv:function:: void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags) + + :param src: Input 8-bit 3-channel image. + + :param dst: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param p: Point in dst image where object is placed. + + :param result: Output image with the same size and type as ``dst``. + + :param flags: Cloning method that could be one of the following: + + * **NORMAL_CLONE** The power of the method is fully expressed when inserting objects with complex outlines into a new background + + * **MIXED_CLONE** The classic method, color-based selection and alpha + masking might be time consuming and often leaves an undesirable halo. Seamless + cloning, even averaged with the original image, is not effective. Mixed seamless + cloning based on a loose selection proves effective. + + * **FEATURE_EXCHANGE** Feature exchange allows the user to replace easily certain + features of one object by alternative features. + + + +colorChange +----------- +Given an original color image, two differently colored versions of this image can be mixed seamlessly. + +.. ocv:function:: void colorChange( InputArray src, InputArray mask, OutputArray dst, float red_mul = 1.0f, float green_mul = 1.0f, float blue_mul = 1.0f) + + :param src: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param red_mul: R-channel multiply factor. + + :param green_mul: G-channel multiply factor. + + :param blue_mul: B-channel multiply factor. + +Multiplication factor is between .5 to 2.5. + + +illuminationChange +------------------ +Applying an appropriate non-linear transformation to the gradient field inside the selection and then integrating back with a Poisson +solver, modifies locally the apparent illumination of an image. + +.. ocv:function:: void illuminationChange(InputArray src, InputArray mask, OutputArray dst, float alpha = 0.2f, float beta = 0.4f) + + :param src: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param alpha: Value ranges between 0-2. + + :param beta: Value ranges between 0-2. + +This is useful to highlight under-exposed foreground objects or to reduce specular reflections. + +textureFlattening +----------------- +By retaining only the gradients at edge locations, before integrating with the Poisson solver, one washes out the texture of the selected +region, giving its contents a flat aspect. Here Canny Edge Detector is used. + +.. ocv:function:: void textureFlattening(InputArray src, InputArray mask, OutputArray dst, double low_threshold=30 , double high_threshold=45, int kernel_size=3) + + :param src: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param low_threshold: Range from 0 to 100. + + :param high_threshold: Value > 100. + + :param kernel_size: The size of the Sobel kernel to be used. + +**NOTE:** + +The algorithm assumes that the color of the source image is close to that of the destination. This assumption means that when the colors don't match, the source image color gets tinted toward the color of the destination image. diff --git a/modules/photo/doc/decolor.rst b/modules/photo/doc/decolor.rst new file mode 100644 index 0000000000..cf7b9b9c4c --- /dev/null +++ b/modules/photo/doc/decolor.rst @@ -0,0 +1,19 @@ +Decolorization +============== + +.. highlight:: cpp + +decolor +------- + +Transforms a color image to a grayscale image. It is a basic tool in digital printing, stylized black-and-white photograph rendering, and in many single channel image processing applications. + +.. ocv:function:: void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost ) + + :param src: Input 8-bit 3-channel image. + + :param grayscale: Output 8-bit 1-channel image. + + :param color_boost: Output 8-bit 3-channel image. + +This function is to be applied on color images. diff --git a/modules/photo/doc/npr.rst b/modules/photo/doc/npr.rst new file mode 100644 index 0000000000..123c946c2a --- /dev/null +++ b/modules/photo/doc/npr.rst @@ -0,0 +1,74 @@ +Non-Photorealistic Rendering +============================ + +.. highlight:: cpp + +edgePreservingFilter +-------------------- + +Filtering is the fundamental operation in image and video processing. Edge-preserving smoothing filters are used in many different applications. + +.. ocv:function:: void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, float sigma_s = 60, float sigma_r = 0.4f) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output 8-bit 3-channel image. + + :param flags: Edge preserving filters: + + * **RECURS_FILTER** + + * **NORMCONV_FILTER** + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. + + +detailEnhance +------------- +This filter enhances the details of a particular image. + +.. ocv:function:: void detailEnhance(InputArray src, OutputArray dst, float sigma_s = 10, float sigma_r = 0.15f) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. + + +pencilSketch +------------ +Pencil-like non-photorealistic line drawing + +.. ocv:function:: void pencilSketch(InputArray src, OutputArray dst1, OutputArray dst2, float sigma_s = 60, float sigma_r = 0.07f, float shade_factor = 0.02f) + + :param src: Input 8-bit 3-channel image. + + :param dst1: Output 8-bit 1-channel image. + + :param dst2: Output image with the same size and type as ``src``. + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. + + :param shade_factor: Range between 0 to 0.1. + + +stylization +----------- +Stylization aims to produce digital imagery with a wide variety of effects not focused on photorealism. Edge-aware filters are ideal for stylization, as they can abstract regions of low contrast while preserving, or enhancing, high-contrast features. + +.. ocv:function:: void stylization(InputArray src, OutputArray dst, float sigma_s = 60, float sigma_r = 0.45f) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. diff --git a/modules/photo/doc/photo.rst b/modules/photo/doc/photo.rst index c8aefda99c..676f3e9d45 100644 --- a/modules/photo/doc/photo.rst +++ b/modules/photo/doc/photo.rst @@ -9,4 +9,7 @@ photo. Computational Photography inpainting denoising - hdr_imaging \ No newline at end of file + hdr_imaging + decolor + cloning + npr diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index beec929235..f0e3f8ec8a 100644 --- a/modules/photo/include/opencv2/photo.hpp +++ b/modules/photo/include/opencv2/photo.hpp @@ -47,7 +47,7 @@ #include "opencv2/imgproc.hpp" /*! \namespace cv - Namespace where all the C++ OpenCV functionality resides + Namespace where all the C++ OpenCV functionality resides */ namespace cv { @@ -59,26 +59,39 @@ enum INPAINT_TELEA = 1 // A. Telea algorithm }; +enum +{ + NORMAL_CLONE = 1, + MIXED_CLONE = 2, + MONOCHROME_TRANSFER = 3 +}; + +enum +{ + RECURS_FILTER = 1, + NORMCONV_FILTER = 2 +}; + //! restores the damaged image areas using one of the available intpainting algorithms CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, - OutputArray dst, double inpaintRadius, int flags ); + OutputArray dst, double inpaintRadius, int flags ); CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, - int templateWindowSize = 7, int searchWindowSize = 21); + int templateWindowSize = 7, int searchWindowSize = 21); CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); enum { LDR_SIZE = 256 }; @@ -288,6 +301,33 @@ public: CV_EXPORTS_W Ptr createMergeRobertson(); +CV_EXPORTS_W void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost); + +CV_EXPORTS_W void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, + OutputArray blend, int flags); + +CV_EXPORTS_W void colorChange(InputArray src, InputArray mask, OutputArray dst, float red_mul = 1.0f, + float green_mul = 1.0f, float blue_mul = 1.0f); + +CV_EXPORTS_W void illuminationChange(InputArray src, InputArray mask, OutputArray dst, + float alpha = 0.2f, float beta = 0.4f); + +CV_EXPORTS_W void textureFlattening(InputArray src, InputArray mask, OutputArray dst, + double low_threshold = 30, double high_threshold = 45, + int kernel_size = 3); + +CV_EXPORTS_W void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, + float sigma_s = 60, float sigma_r = 0.4f); + +CV_EXPORTS_W void detailEnhance(InputArray src, OutputArray dst, float sigma_s = 10, + float sigma_r = 0.15f); + +CV_EXPORTS_W void pencilSketch(InputArray src, OutputArray dst1, OutputArray dst2, + float sigma_s = 60, float sigma_r = 0.07f, float shade_factor = 0.02f); + +CV_EXPORTS_W void stylization(InputArray src, OutputArray dst, float sigma_s = 60, + float sigma_r = 0.45f); + } // cv #endif diff --git a/modules/photo/src/contrast_preserve.cpp b/modules/photo/src/contrast_preserve.cpp new file mode 100644 index 0000000000..806afdf312 --- /dev/null +++ b/modules/photo/src/contrast_preserve.cpp @@ -0,0 +1,210 @@ +/*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) 2013, 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 "precomp.hpp" +#include "opencv2/photo.hpp" +#include "math.h" +#include +#include +#include +#include "contrast_preserve.hpp" + +using namespace std; +using namespace cv; + +void cv::decolor(InputArray _src, OutputArray _dst, OutputArray _color_boost) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC1); + Mat dst = _dst.getMat(); + + _color_boost.create(I.size(), CV_8UC3); + Mat color_boost = _color_boost.getMat(); + + if(!I.data ) + { + cout << "Could not open or find the image" << endl ; + return; + } + if(I.channels() !=3) + { + cout << "Input Color Image" << endl; + return; + } + + // Parameter Setting + int maxIter = 15; + int iterCount = 0; + double tol = .0001; + double E = 0; + double pre_E = std::numeric_limits::infinity(); + + Decolor obj; + + Mat img; + + img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + // Initialization + obj.init(); + + vector Cg; + vector < vector > polyGrad; + vector < vector < int > > comb; + + vector alf; + + obj.grad_system(img,polyGrad,Cg,comb); + obj.weak_order(img,alf); + + // Solver + Mat Mt = Mat((int)polyGrad.size(),(int)polyGrad[0].size(), CV_32FC1); + obj.wei_update_matrix(polyGrad,Cg,Mt); + + vector wei; + obj.wei_inti(comb,wei); + + //////////////////////////////// main loop starting //////////////////////////////////////// + + while(sqrt(pow(E-pre_E,2)) > tol) + { + iterCount +=1; + pre_E = E; + + vector G_pos; + vector G_neg; + + vector temp; + vector temp1; + + double val = 0.0; + for(unsigned int i=0;i< polyGrad[0].size();i++) + { + val = 0.0; + for(unsigned int j =0;j EXPsum; + vector EXPterm; + + for(unsigned int i = 0;i temp2; + + for(unsigned int i=0;i wei1; + + for(unsigned int i=0;i< polyGrad.size();i++) + { + val1 = 0.0; + for(unsigned int j =0;j(i,j) * EXPterm[j]); + } + wei1.push_back(val1); + } + + for(unsigned int i =0;i maxIter) + break; + + G_pos.clear(); + G_neg.clear(); + temp.clear(); + temp1.clear(); + EXPsum.clear(); + EXPterm.clear(); + temp2.clear(); + wei1.clear(); + } + + Mat Gray = Mat::zeros(img.size(),CV_32FC1); + obj.grayImContruct(wei, img, Gray); + + Gray.convertTo(dst,CV_8UC1,255); + + /////////////////////////////////// Contrast Boosting ///////////////////////////////// + + Mat lab = Mat(img.size(),CV_8UC3); + Mat color = Mat(img.size(),CV_8UC3); + + cvtColor(I,lab,COLOR_BGR2Lab); + + vector lab_channel; + split(lab,lab_channel); + + dst.copyTo(lab_channel[0]); + + merge(lab_channel,lab); + + cvtColor(lab,color_boost,COLOR_Lab2BGR); +} diff --git a/modules/photo/src/contrast_preserve.hpp b/modules/photo/src/contrast_preserve.hpp new file mode 100644 index 0000000000..0cc6bce850 --- /dev/null +++ b/modules/photo/src/contrast_preserve.hpp @@ -0,0 +1,433 @@ +/*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) 2013, 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 "precomp.hpp" +#include "opencv2/photo.hpp" +#include "math.h" +#include +#include + +using namespace std; +using namespace cv; + +class Decolor +{ + private: + Mat kernelx; + Mat kernely; + int order; + + public: + float sigma; + void init(); + vector product(vector < vector > &comb, vector &initRGB); + double energyCalcu(vector &Cg, vector < vector > &polyGrad, vector &wei); + void singleChannelGradx(const Mat &img, Mat& dest); + void singleChannelGrady(const Mat &img, Mat& dest); + void gradvector(const Mat &img, vector &grad); + void colorGrad(Mat img, vector &Cg); + void add_vector(vector < vector > &comb, int r,int g,int b); + void add_to_vector_poly(vector < vector > &polyGrad, vector &curGrad); + void weak_order(Mat img, vector &alf); + void grad_system(Mat img, vector < vector < double > > &polyGrad, + vector < double > &Cg, vector < vector >& comb); + void wei_update_matrix(vector < vector > &poly, vector &Cg, Mat &X); + void wei_inti(vector < vector > &comb, vector &wei); + void grayImContruct(vector &wei, Mat img, Mat &Gray); +}; + +int round_num(double a); + +int round_num(double a) +{ + return int(a + 0.5); +} + +double Decolor::energyCalcu(vector &Cg, vector < vector > &polyGrad, vector &wei) +{ + vector energy; + vector temp; + vector temp1; + + double val = 0.0; + for(unsigned int i=0;i< polyGrad[0].size();i++) + { + val = 0.0; + for(unsigned int j =0;j(0,0)=1.0; + kernelx.at(0,1)=-1.0; + kernely.at(0,0)=1.0; + kernely.at(1,0)=-1.0; + order = 2; + sigma = 0.02f; +} + +vector Decolor::product(vector < vector > &comb, vector &initRGB) +{ + vector res; + double dp; + for (unsigned int i=0;i(i,w-1)=0.0; +} + +void Decolor::singleChannelGrady(const Mat &img, Mat& dest) +{ + int w=img.size().width; + int h=img.size().height; + Point anchor(kernely.cols - kernely.cols/2 - 1, kernely.rows - kernely.rows/2 - 1); + filter2D(img, dest, -1, kernely, anchor, 0.0, BORDER_CONSTANT); + for(int j=0;j(h-1,j)=0.0; +} + +void Decolor::gradvector(const Mat &img, vector &grad) +{ + Mat dest= Mat(img.size().height,img.size().width, CV_32FC1); + Mat dest1= Mat(img.size().height,img.size().width, CV_32FC1); + singleChannelGradx(img,dest); + singleChannelGrady(img,dest1); + + Mat d_trans=dest.t(); + Mat d1_trans=dest1.t(); + + int height = d_trans.size().height; + int width = d_trans.size().width; + + for(int i=0;i(i,j)); + + for(int i=0;i(i,j)); + dest.release(); + dest1.release(); +} + +void Decolor::colorGrad(Mat img, vector &Cg) +{ + + Mat lab = Mat(img.size(),CV_32FC3); + + cvtColor(img,lab,COLOR_BGR2Lab); + + vector lab_channel; + split(lab,lab_channel); + + vector ImL; + vector Ima; + vector Imb; + + gradvector(lab_channel[0],ImL); + gradvector(lab_channel[1],Ima); + gradvector(lab_channel[2],Imb); + + double res =0.0; + for(unsigned int i=0;i > &comb, int r,int g,int b) +{ + static int idx =0; + comb.push_back( vector () ); + comb.at(idx).push_back( r ); + comb.at(idx).push_back( g ); + comb.at(idx).push_back( b ); + idx++; +} + +void Decolor::add_to_vector_poly(vector < vector > &polyGrad, vector &curGrad) +{ + static int idx1 =0; + polyGrad.push_back( vector () ); + for(unsigned int i=0;i &alf) +{ + int h = img.size().height; + int w = img.size().width; + double sizefactor; + if((h + w) > 800) + { + sizefactor = (double)800/(h+w); + resize(img,img,Size(round_num(h*sizefactor),round_num(w*sizefactor))); + } + + Mat curIm = Mat(img.size(),CV_32FC1); + vector rgb_channel; + split(img,rgb_channel); + + vector Rg, Gg, Bg; + vector t1, t2, t3; + vector tmp1, tmp2, tmp3; + + gradvector(rgb_channel[2],Rg); + gradvector(rgb_channel[1],Gg); + gradvector(rgb_channel[0],Bg); + + double level = .05; + + for(unsigned int i=0;i level) + t1.push_back(1.0); + else + t1.push_back(0.0); + + if(Gg[i] > level) + t2.push_back(1.0); + else + t2.push_back(0.0); + + if(Bg[i] > level) + t3.push_back(1.0); + else + t3.push_back(0.0); + + if(Rg[i] < -1.0*level) + tmp1.push_back(1.0); + else + tmp1.push_back(0.0); + + if(Gg[i] < -1.0*level) + tmp2.push_back(1.0); + else + tmp2.push_back(0.0); + + if(Bg[i] < -1.0*level) + tmp3.push_back(1.0); + else + tmp3.push_back(0.0); + } + for(unsigned int i =0 ;i < Rg.size();i++) + alf.push_back(t1[i] * t2[i] * t3[i]); + + for(unsigned int i =0 ;i < Rg.size();i++) + alf[i] -= tmp1[i] * tmp2[i] * tmp3[i]; + + double sum =0.0; + for(unsigned int i=0;i > &polyGrad, + vector < double > &Cg, vector < vector >& comb) +{ + int h = img.size().height; + int w = img.size().width; + + double sizefactor; + if((h + w) > 800) + { + sizefactor = (double)800/(h+w); + resize(img,img,Size(round_num(h*sizefactor),round_num(w*sizefactor))); + } + + h = img.size().height; + w = img.size().width; + colorGrad(img,Cg); + + Mat curIm = Mat(img.size(),CV_32FC1); + vector rgb_channel; + split(img,rgb_channel); + + for(int r=0 ;r <=order; r++) + for(int g=0; g<=order;g++) + for(int b =0; b <=order;b++) + { + if((r+g+b)<=order && (r+g+b) > 0) + { + add_vector(comb,r,g,b); + for(int i = 0;i(i,j)= + pow(rgb_channel[2].at(i,j),r)*pow(rgb_channel[1].at(i,j),g)* + pow(rgb_channel[0].at(i,j),b); + vector curGrad; + gradvector(curIm,curGrad); + add_to_vector_poly(polyGrad,curGrad); + } + } +} + +void Decolor::wei_update_matrix(vector < vector > &poly, vector &Cg, Mat &X) +{ + int size = static_cast(poly.size()), size0 = static_cast(poly[0].size()); + Mat P = Mat(size, size0, CV_32FC1); + Mat A = Mat(size, size, CV_32FC1); + + for (int i = 0; i < size; i++) + for (int j = 0; j < size0;j++) + P.at(i,j) = (float) poly[i][j]; + + Mat P_trans = P.t(); + Mat B = Mat(size, size0, CV_32FC1); + for(int i =0;i < size;i++) + { + for(int j = 0, end = (int)Cg.size(); j < end;j++) + B.at(i,j) = (float) (poly[i][j] * Cg[j]); + } + + A = P*P_trans; + solve(A, B, X, DECOMP_NORMAL); + +} + +void Decolor::wei_inti(vector < vector > &comb, vector &wei) +{ + vector initRGB; + + initRGB.push_back( .33 ); + initRGB.push_back( .33 ); + initRGB.push_back( .33 ); + wei = product(comb,initRGB); + + vector sum; + + for(unsigned int i=0;i &wei, Mat img, Mat &Gray) +{ + int h=img.size().height; + int w=img.size().width; + + vector rgb_channel; + split(img,rgb_channel); + + int kk =0; + + for(int r =0;r<=order;r++) + for(int g=0;g<=order;g++) + for(int b=0;b<=order;b++) + if((r + g + b) <=order && (r+g+b) > 0) + { + for(int i = 0;i(i,j)=Gray.at(i,j) + + (float) wei[kk]*pow(rgb_channel[2].at(i,j),r)*pow(rgb_channel[1].at(i,j),g)* + pow(rgb_channel[0].at(i,j),b); + + kk=kk+1; + } + + float minval = FLT_MAX; + float maxval = -FLT_MAX; + + for(int i=0;i(i,j) < minval) + minval = Gray.at(i,j); + + if(Gray.at(i,j) > maxval) + maxval = Gray.at(i,j); + } + + Gray -= minval; + Gray /= maxval - minval; +} diff --git a/modules/photo/src/npr.cpp b/modules/photo/src/npr.cpp new file mode 100644 index 0000000000..761f3c73cb --- /dev/null +++ b/modules/photo/src/npr.cpp @@ -0,0 +1,173 @@ +/*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) 2013, 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 "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include + +#include "npr.hpp" + +using namespace std; +using namespace cv; + +void cv::edgePreservingFilter(InputArray _src, OutputArray _dst, int flags, float sigma_s, float sigma_r) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC3); + Mat dst = _dst.getMat(); + + int h = I.size().height; + int w = I.size().width; + + Mat res = Mat(h,w,CV_32FC3); + dst.convertTo(res,CV_32FC3,1.0/255.0); + + Domain_Filter obj; + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + obj.filter(img, res, sigma_s, sigma_r, flags); + + convertScaleAbs(res, dst, 255,0); +} + +void cv::detailEnhance(InputArray _src, OutputArray _dst, float sigma_s, float sigma_r) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC3); + Mat dst = _dst.getMat(); + + int h = I.size().height; + int w = I.size().width; + float factor = 3.0f; + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + Mat res = Mat(h,w,CV_32FC1); + dst.convertTo(res,CV_32FC3,1.0/255.0); + + Mat result = Mat(img.size(),CV_32FC3); + Mat lab = Mat(img.size(),CV_32FC3); + vector lab_channel; + + cvtColor(img,lab,COLOR_BGR2Lab); + split(lab,lab_channel); + + Mat L = Mat(img.size(),CV_32FC1); + + lab_channel[0].convertTo(L,CV_32FC1,1.0/255.0); + + Domain_Filter obj; + + obj.filter(L, res, sigma_s, sigma_r, 1); + + Mat detail = Mat(h,w,CV_32FC1); + + detail = L - res; + multiply(detail,factor,detail); + L = res + detail; + + L.convertTo(lab_channel[0],CV_32FC1,255); + + merge(lab_channel,lab); + + cvtColor(lab,result,COLOR_Lab2BGR); + result.convertTo(dst,CV_8UC3,255); +} + +void cv::pencilSketch(InputArray _src, OutputArray _dst1, OutputArray _dst2, float sigma_s, float sigma_r, float shade_factor) +{ + Mat I = _src.getMat(); + _dst1.create(I.size(), CV_8UC1); + Mat dst1 = _dst1.getMat(); + + _dst2.create(I.size(), CV_8UC3); + Mat dst2 = _dst2.getMat(); + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + Domain_Filter obj; + + Mat sketch = Mat(I.size(),CV_32FC1); + Mat color_sketch = Mat(I.size(),CV_32FC3); + + obj.pencil_sketch(img, sketch, color_sketch, sigma_s, sigma_r, shade_factor); + + sketch.convertTo(dst1,CV_8UC1,255); + color_sketch.convertTo(dst2,CV_8UC3,255); + +} + +void cv::stylization(InputArray _src, OutputArray _dst, float sigma_s, float sigma_r) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC3); + Mat dst = _dst.getMat(); + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + int h = img.size().height; + int w = img.size().width; + + Mat res = Mat(h,w,CV_32FC3); + Mat magnitude = Mat(h,w,CV_32FC1); + + Domain_Filter obj; + obj.filter(img, res, sigma_s, sigma_r, NORMCONV_FILTER); + + obj.find_magnitude(res,magnitude); + + Mat stylized = Mat(h,w,CV_32FC3); + + vector temp; + split(res,temp); + multiply(temp[0],magnitude,temp[0]); + multiply(temp[1],magnitude,temp[1]); + multiply(temp[2],magnitude,temp[2]); + merge(temp,stylized); + + stylized.convertTo(dst,CV_8UC3,255); +} diff --git a/modules/photo/src/npr.hpp b/modules/photo/src/npr.hpp new file mode 100644 index 0000000000..744b2bdfbb --- /dev/null +++ b/modules/photo/src/npr.hpp @@ -0,0 +1,582 @@ +/*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) 2013, 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 "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include +#include +#include "math.h" + + +using namespace std; +using namespace cv; + +double myinf = std::numeric_limits::infinity(); + +class Domain_Filter +{ + public: + Mat ct_H, ct_V, horiz, vert, O, O_t, lower_idx, upper_idx; + void init(const Mat &img, int flags, float sigma_s, float sigma_r); + void getGradientx( const Mat &img, Mat &gx); + void getGradienty( const Mat &img, Mat &gy); + void diffx(const Mat &img, Mat &temp); + void diffy(const Mat &img, Mat &temp); + void find_magnitude(Mat &img, Mat &mag); + void compute_boxfilter(Mat &output, Mat &hz, Mat &psketch, float radius); + void compute_Rfilter(Mat &O, Mat &horiz, float sigma_h); + void compute_NCfilter(Mat &O, Mat &horiz, Mat &psketch, float radius); + void filter(const Mat &img, Mat &res, float sigma_s, float sigma_r, int flags); + void pencil_sketch(const Mat &img, Mat &sketch, Mat &color_res, float sigma_s, float sigma_r, float shade_factor); + void Depth_of_field(const Mat &img, Mat &img1, float sigma_s, float sigma_r); +}; + +void Domain_Filter::diffx(const Mat &img, Mat &temp) +{ + int channel = img.channels(); + + for(int i = 0; i < img.size().height; i++) + for(int j = 0; j < img.size().width-1; j++) + { + for(int c =0; c < channel; c++) + { + temp.at(i,j*channel+c) = + img.at(i,(j+1)*channel+c) - img.at(i,j*channel+c); + } + } +} + +void Domain_Filter::diffy(const Mat &img, Mat &temp) +{ + int channel = img.channels(); + + for(int i = 0; i < img.size().height-1; i++) + for(int j = 0; j < img.size().width; j++) + { + for(int c =0; c < channel; c++) + { + temp.at(i,j*channel+c) = + img.at((i+1),j*channel+c) - img.at(i,j*channel+c); + } + } +} + +void Domain_Filter::getGradientx( const Mat &img, Mat &gx) +{ + int w = img.cols; + int h = img.rows; + int channel = img.channels(); + + for(int i=0;i(i,j*channel+c) = + img.at(i,(j+1)*channel+c) - img.at(i,j*channel+c); + } +} + +void Domain_Filter::getGradienty( const Mat &img, Mat &gy) +{ + int w = img.cols; + int h = img.rows; + int channel = img.channels(); + + for(int i=0;i(i,j*channel+c) = + img.at(i+1,j*channel+c) - img.at(i,j*channel+c); + + } +} + +void Domain_Filter::find_magnitude(Mat &img, Mat &mag) +{ + int h = img.rows; + int w = img.cols; + + vector planes; + split(img, planes); + + Mat magXR = Mat(h, w, CV_32FC1); + Mat magYR = Mat(h, w, CV_32FC1); + + Mat magXG = Mat(h, w, CV_32FC1); + Mat magYG = Mat(h, w, CV_32FC1); + + Mat magXB = Mat(h, w, CV_32FC1); + Mat magYB = Mat(h, w, CV_32FC1); + + Sobel(planes[0], magXR, CV_32FC1, 1, 0, 3); + Sobel(planes[0], magYR, CV_32FC1, 0, 1, 3); + + Sobel(planes[1], magXG, CV_32FC1, 1, 0, 3); + Sobel(planes[1], magYG, CV_32FC1, 0, 1, 3); + + Sobel(planes[2], magXB, CV_32FC1, 1, 0, 3); + Sobel(planes[2], magYB, CV_32FC1, 0, 1, 3); + + Mat mag1 = Mat(h,w,CV_32FC1); + Mat mag2 = Mat(h,w,CV_32FC1); + Mat mag3 = Mat(h,w,CV_32FC1); + + magnitude(magXR,magYR,mag1); + magnitude(magXG,magYG,mag2); + magnitude(magXB,magYB,mag3); + + mag = mag1 + mag2 + mag3; + mag = 1.0f - mag; +} + +void Domain_Filter::compute_Rfilter(Mat &output, Mat &hz, float sigma_h) +{ + int h = output.rows; + int w = output.cols; + + float a = (float) exp((-1.0 * sqrt(2.0)) / sigma_h); + + Mat temp = Mat(h,w,CV_32FC3); + + output.copyTo(temp); + Mat V = Mat(h,w,CV_32FC1); + + for(int i=0;i(i,j) = pow(a,hz.at(i,j)); + + for(int i=0; i(i,j) = temp.at(i,j) + (temp.at(i,j-1) - temp.at(i,j)) * V.at(i,j); + } + } + + for(int i=0; i= 0; j--) + { + temp.at(i,j) = temp.at(i,j) + (temp.at(i,j+1) - temp.at(i,j)) * V.at(i,j+1); + } + } + + temp.copyTo(output); +} + +void Domain_Filter::compute_boxfilter(Mat &output, Mat &hz, Mat &psketch, float radius) +{ + int h = output.rows; + int w = output.cols; + Mat lower_pos = Mat(h,w,CV_32FC1); + Mat upper_pos = Mat(h,w,CV_32FC1); + + lower_pos = hz - radius; + upper_pos = hz + radius; + + lower_idx = Mat::zeros(h,w,CV_32FC1); + upper_idx = Mat::zeros(h,w,CV_32FC1); + + Mat domain_row = Mat::zeros(1,w+1,CV_32FC1); + + for(int i=0;i(0,j) = hz.at(i,j); + domain_row.at(0,w) = (float) myinf; + + Mat lower_pos_row = Mat::zeros(1,w,CV_32FC1); + Mat upper_pos_row = Mat::zeros(1,w,CV_32FC1); + + for(int j=0;j(0,j) = lower_pos.at(i,j); + upper_pos_row.at(0,j) = upper_pos.at(i,j); + } + + Mat temp_lower_idx = Mat::zeros(1,w,CV_32FC1); + Mat temp_upper_idx = Mat::zeros(1,w,CV_32FC1); + + for(int j=0;j(0,j) > lower_pos_row.at(0,0)) + { + temp_lower_idx.at(0,0) = (float) j; + break; + } + } + for(int j=0;j(0,j) > upper_pos_row.at(0,0)) + { + temp_upper_idx.at(0,0) = (float) j; + break; + } + } + + int temp = 0; + for(int j=1;j(0,j-1);k(0,k) > lower_pos_row.at(0,j)) + { + temp = count; + break; + } + count++; + } + + temp_lower_idx.at(0,j) = temp_lower_idx.at(0,j-1) + temp; + + count = 0; + for(int k=(int) temp_upper_idx.at(0,j-1);k(0,k) > upper_pos_row.at(0,j)) + { + temp = count; + break; + } + count++; + } + + temp_upper_idx.at(0,j) = temp_upper_idx.at(0,j-1) + temp; + } + + for(int j=0;j(i,j) = temp_lower_idx.at(0,j) + 1; + upper_idx.at(i,j) = temp_upper_idx.at(0,j) + 1; + } + + } + psketch = upper_idx - lower_idx; +} +void Domain_Filter::compute_NCfilter(Mat &output, Mat &hz, Mat &psketch, float radius) +{ + int h = output.rows; + int w = output.cols; + int channel = output.channels(); + + compute_boxfilter(output,hz,psketch,radius); + + Mat box_filter = Mat::zeros(h,w+1,CV_32FC3); + + for(int i = 0; i < h; i++) + { + box_filter.at(i,1*channel+0) = output.at(i,0*channel+0); + box_filter.at(i,1*channel+1) = output.at(i,0*channel+1); + box_filter.at(i,1*channel+2) = output.at(i,0*channel+2); + for(int j = 2; j < w+1; j++) + { + for(int c=0;c(i,j*channel+c) = output.at(i,(j-1)*channel+c) + box_filter.at(i,(j-1)*channel+c); + } + } + + Mat indices = Mat::zeros(h,w,CV_32FC1); + Mat final = Mat::zeros(h,w,CV_32FC3); + + for(int i=0;i(i,j) = (float) i+1; + + Mat a = Mat::zeros(h,w,CV_32FC1); + Mat b = Mat::zeros(h,w,CV_32FC1); + + // Compute the box filter using a summed area table. + for(int c=0;c(i,j)/(h*(w+1)); + rem = (int) b.at(i,j) - r*h*(w+1); + q = rem/h; + p = rem - q*h; + if(q==0) + { + p=h; + q=w; + r=r-1; + } + if(p==0) + { + p=h; + q=q-1; + } + + r1 = (int) a.at(i,j)/(h*(w+1)); + rem1 = (int) a.at(i,j) - r1*h*(w+1); + q1 = rem1/h; + p1 = rem1 - q1*h; + if(p1==0) + { + p1=h; + q1=q1-1; + } + + final.at(i,j*channel+2-c) = (box_filter.at(p-1,q*channel+(2-r)) - box_filter.at(p1-1,q1*channel+(2-r1))) + /(upper_idx.at(i,j) - lower_idx.at(i,j)); + } + } + } + + final.copyTo(output); +} +void Domain_Filter::init(const Mat &img, int flags, float sigma_s, float sigma_r) +{ + int h = img.size().height; + int w = img.size().width; + int channel = img.channels(); + + //////////////////////////////////// horizontal and vertical partial derivatives ///////////////////////////////// + + Mat derivx = Mat::zeros(h,w-1,CV_32FC3); + Mat derivy = Mat::zeros(h-1,w,CV_32FC3); + + diffx(img,derivx); + diffy(img,derivy); + + Mat distx = Mat::zeros(h,w,CV_32FC1); + Mat disty = Mat::zeros(h,w,CV_32FC1); + + //////////////////////// Compute the l1-norm distance of neighbor pixels //////////////////////////////////////////////// + + for(int i = 0; i < h; i++) + for(int j = 0,k=1; j < w-1; j++,k++) + for(int c = 0; c < channel; c++) + { + distx.at(i,k) = + distx.at(i,k) + abs(derivx.at(i,j*channel+c)); + } + + for(int i = 0,k=1; i < h-1; i++,k++) + for(int j = 0; j < w; j++) + for(int c = 0; c < channel; c++) + { + disty.at(k,j) = + disty.at(k,j) + abs(derivy.at(i,j*channel+c)); + } + + ////////////////////// Compute the derivatives of the horizontal and vertical domain transforms. ///////////////////////////// + + horiz = Mat(h,w,CV_32FC1); + vert = Mat(h,w,CV_32FC1); + + Mat final = Mat(h,w,CV_32FC3); + + Mat tempx,tempy; + multiply(distx,sigma_s/sigma_r,tempx); + multiply(disty,sigma_s/sigma_r,tempy); + + horiz = 1.0f + tempx; + vert = 1.0f + tempy; + + O = Mat(h,w,CV_32FC3); + img.copyTo(O); + + O_t = Mat(w,h,CV_32FC3); + + if(flags == 2) + { + + ct_H = Mat(h,w,CV_32FC1); + ct_V = Mat(h,w,CV_32FC1); + + for(int i = 0; i < h; i++) + { + ct_H.at(i,0) = horiz.at(i,0); + for(int j = 1; j < w; j++) + { + ct_H.at(i,j) = horiz.at(i,j) + ct_H.at(i,j-1); + } + } + + for(int j = 0; j < w; j++) + { + ct_V.at(0,j) = vert.at(0,j); + for(int i = 1; i < h; i++) + { + ct_V.at(i,j) = vert.at(i,j) + ct_V.at(i-1,j); + } + } + } + +} + +void Domain_Filter::filter(const Mat &img, Mat &res, float sigma_s = 60, float sigma_r = 0.4, int flags = 1) +{ + int no_of_iter = 3; + int h = img.size().height; + int w = img.size().width; + float sigma_h = sigma_s; + + init(img,flags,sigma_s,sigma_r); + + if(flags == 1) + { + Mat vert_t = vert.t(); + + for(int i=0;i YUV_channel; + Mat vert_t = ct_V.t(); + + float sigma_h = sigma_s; + + Mat penx = Mat(h,w,CV_32FC1); + + Mat pen_res = Mat::zeros(h,w,CV_32FC1); + Mat peny = Mat(w,h,CV_32FC1); + + Mat peny_t; + + float radius; + + for(int i=0;i(k,j) = (shade_factor * (penx.at(k,j) + peny_t.at(k,j))); + + if(i==0) + { + sketch = pen_res.clone(); + split(color_sketch,YUV_channel); + pen_res.copyTo(YUV_channel[0]); + merge(YUV_channel,color_sketch); + cvtColor(color_sketch,color_res,COLOR_YCrCb2BGR); + } + + } +} diff --git a/modules/photo/src/seamless_cloning.cpp b/modules/photo/src/seamless_cloning.cpp new file mode 100644 index 0000000000..63f4530477 --- /dev/null +++ b/modules/photo/src/seamless_cloning.cpp @@ -0,0 +1,193 @@ +/*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) 2013, 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 "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include + +#include "seamless_cloning.hpp" + +using namespace std; +using namespace cv; + +void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags) +{ + Mat src = _src.getMat(); + Mat dest = _dst.getMat(); + Mat mask = _mask.getMat(); + _blend.create(dest.size(), CV_8UC3); + Mat blend = _blend.getMat(); + + int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN; + int h = mask.size().height; + int w = mask.size().width; + + Mat gray = Mat(mask.size(),CV_8UC1); + Mat dst_mask = Mat::zeros(dest.size(),CV_8UC1); + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); + Mat cd_mask = Mat::zeros(dest.size(),CV_8UC3); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + + for(int i=0;i(i,j) == 255) + { + minx = std::min(minx,i); + maxx = std::max(maxx,i); + miny = std::min(miny,j); + maxy = std::max(maxy,j); + } + } + } + + int lenx = maxx - minx; + int leny = maxy - miny; + + int minxd = p.y - lenx/2; + int maxxd = p.y + lenx/2; + int minyd = p.x - leny/2; + int maxyd = p.x + leny/2; + + if(minxd < 0 || minyd < 0 || maxxd > dest.size().height || maxyd > dest.size().width) + { + cout << "Index out of range" << endl; + exit(0); + } + + Rect roi_d(minyd,minxd,leny,lenx); + Rect roi_s(miny,minx,leny,lenx); + + Mat destinationROI = dst_mask(roi_d); + Mat sourceROI = cs_mask(roi_s); + + gray(roi_s).copyTo(destinationROI); + src(roi_s).copyTo(sourceROI,gray(roi_s)); + + destinationROI = cd_mask(roi_d); + cs_mask(roi_s).copyTo(destinationROI); + + Cloning obj; + obj.normal_clone(dest,cd_mask,dst_mask,blend,flags); +} + +void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b) +{ + Mat src = _src.getMat(); + Mat mask = _mask.getMat(); + _dst.create(src.size(), src.type()); + Mat blend = _dst.getMat(); + + float red = r; + float green = g; + float blue = b; + + Mat gray = Mat::zeros(mask.size(),CV_8UC1); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); + + src.copyTo(cs_mask,gray); + + Cloning obj; + obj.local_color_change(src,cs_mask,gray,blend,red,green,blue); +} + + +void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b) +{ + + Mat src = _src.getMat(); + Mat mask = _mask.getMat(); + _dst.create(src.size(), src.type()); + Mat blend = _dst.getMat(); + float alpha = a; + float beta = b; + + Mat gray = Mat::zeros(mask.size(),CV_8UC1); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); + + src.copyTo(cs_mask,gray); + + Cloning obj; + obj.illum_change(src,cs_mask,gray,blend,alpha,beta); + +} + +void cv::textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst, + double low_threshold, double high_threshold, int kernel_size) +{ + + Mat src = _src.getMat(); + Mat mask = _mask.getMat(); + _dst.create(src.size(), src.type()); + Mat blend = _dst.getMat(); + + Mat gray = Mat::zeros(mask.size(),CV_8UC1); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); + + src.copyTo(cs_mask,gray); + + Cloning obj; + obj.texture_flatten(src,cs_mask,gray,low_threshold,high_threshold,kernel_size,blend); +} diff --git a/modules/photo/src/seamless_cloning.hpp b/modules/photo/src/seamless_cloning.hpp new file mode 100644 index 0000000000..73d719c1ba --- /dev/null +++ b/modules/photo/src/seamless_cloning.hpp @@ -0,0 +1,594 @@ +/*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) 2013, 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 "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include +#include +#include "math.h" + +using namespace std; +using namespace cv; + +class Cloning +{ + + public: + + vector rgb_channel, rgbx_channel, rgby_channel, output; + Mat grx, gry, sgx, sgy, srx32, sry32, grx32, gry32, smask, smask1; + void init_var(Mat &I, Mat &wmask); + void initialization(Mat &I, Mat &mask, Mat &wmask); + void scalar_product(Mat mat, float r, float g, float b); + void array_product(Mat mat1, Mat mat2, Mat mat3); + void poisson(Mat &I, Mat &gx, Mat &gy, Mat &sx, Mat &sy); + void evaluate(Mat &I, Mat &wmask, Mat &cloned); + void getGradientx(const Mat &img, Mat &gx); + void getGradienty(const Mat &img, Mat &gy); + void lapx(const Mat &img, Mat &gxx); + void lapy(const Mat &img, Mat &gyy); + void dst(double *mod_diff, double *sineTransform,int h,int w); + void idst(double *mod_diff, double *sineTransform,int h,int w); + void transpose(double *mat, double *mat_t,int h,int w); + void solve(const Mat &img, double *mod_diff, Mat &result); + void poisson_solver(const Mat &img, Mat &gxx , Mat &gyy, Mat &result); + void normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num); + void local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float red_mul, float green_mul, float blue_mul); + void illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta); + void texture_flatten(Mat &I, Mat &mask, Mat &wmask, double low_threshold, double high_threhold, int kernel_size, Mat &cloned); +}; + +void Cloning::getGradientx( const Mat &img, Mat &gx) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i,j*channel+c) = + (float)img.at(i,(j+1)*channel+c) - (float)img.at(i,j*channel+c); + } + +} + +void Cloning::getGradienty( const Mat &img, Mat &gy) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i,j*channel+c) = + (float)img.at((i+1),j*channel+c) - (float)img.at(i,j*channel+c); + + } +} + +void Cloning::lapx( const Mat &img, Mat &gxx) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i,(j+1)*channel+c) = + (float)img.at(i,(j+1)*channel+c) - (float)img.at(i,j*channel+c); + } +} + +void Cloning::lapy( const Mat &img, Mat &gyy) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i+1,j*channel+c) = + (float)img.at((i+1),j*channel+c) - (float)img.at(i,j*channel+c); + + } +} + +void Cloning::dst(double *mod_diff, double *sineTransform,int h,int w) +{ + + unsigned long int idx; + + Mat temp = Mat(2*h+2,1,CV_32F); + Mat res = Mat(h,1,CV_32F); + + Mat planes[] = {Mat_(temp), Mat::zeros(temp.size(), CV_32F)}; + + Mat result; + int p=0; + for(int i=0;i(0,0) = 0.0; + + for(int j=0,r=1;j(r,0) = (float) mod_diff[idx]; + } + + temp.at(h+1,0)=0.0; + + for(int j=h-1, r=h+2;j>=0;j--,r++) + { + idx = j*w+i; + temp.at(r,0) = (float) (-1.0 * mod_diff[idx]); + } + + merge(planes, 2, result); + + dft(result,result,0,0); + + Mat planes1[] = {Mat::zeros(result.size(), CV_32F), Mat::zeros(result.size(), CV_32F)}; + + split(result, planes1); + + std::complex two_i = std::sqrt(std::complex(-1)); + + double factor = -2*imag(two_i); + + for(int c=1,z=0;c(z,0) = (float) (planes1[1].at(c,0)/factor); + } + + for(int q=0,z=0;q(z,0); + } + p++; + } +} + +void Cloning::idst(double *mod_diff, double *sineTransform,int h,int w) +{ + int nn = h+1; + unsigned long int idx; + dst(mod_diff,sineTransform,h,w); + for(int i= 0;i(i,j) = (float) mat[idx]; + } + } + Mat tmp_t = tmp.t(); + + for(int i = 0;i < tmp_t.size().height; i++) + for(int j=0;j(i,j); + } +} + +void Cloning::solve(const Mat &img, double *mod_diff, Mat &result) +{ + int w = img.size().width; + int h = img.size().height; + + unsigned long int idx,idx1; + + double *sineTransform = new double[(h-2)*(w-2)]; + double *sineTransform_t = new double[(h-2)*(w-2)]; + double *denom = new double[(h-2)*(w-2)]; + double *invsineTransform = new double[(h-2)*(w-2)]; + double *invsineTransform_t = new double[(h-2)*(w-2)]; + double *img_d = new double[(h)*(w)]; + + dst(mod_diff,sineTransform,h-2,w-2); + + transpose(sineTransform,sineTransform_t,h-2,w-2); + + dst(sineTransform_t,sineTransform,w-2,h-2); + + transpose(sineTransform,sineTransform_t,w-2,h-2); + + int cy = 1; + + for(int i = 0 ; i < w-2;i++,cy++) + { + for(int j = 0,cx = 1; j < h-2; j++,cx++) + { + idx = j*(w-2) + i; + denom[idx] = (float) 2*cos(CV_PI*cy/( (double) (w-1))) - 2 + 2*cos(CV_PI*cx/((double) (h-1))) - 2; + + } + } + + for(idx = 0 ; idx < (unsigned)(w-2)*(h-2) ;idx++) + { + sineTransform_t[idx] = sineTransform_t[idx]/denom[idx]; + } + + idst(sineTransform_t,invsineTransform,h-2,w-2); + + transpose(invsineTransform,invsineTransform_t,h-2,w-2); + + idst(invsineTransform_t,invsineTransform,w-2,h-2); + + transpose(invsineTransform,invsineTransform_t,w-2,h-2); + + for(int i = 0 ; i < h;i++) + { + for(int j = 0 ; j < w; j++) + { + idx = i*w + j; + img_d[idx] = (double)img.at(i,j); + } + } + for(int i = 1 ; i < h-1;i++) + { + for(int j = 1 ; j < w-1; j++) + { + idx = i*w + j; + img_d[idx] = 0.0; + } + } + for(int i = 1,id1=0 ; i < h-1;i++,id1++) + { + for(int j = 1,id2=0 ; j < w-1; j++,id2++) + { + idx = i*w + j; + idx1= id1*(w-2) + id2; + img_d[idx] = invsineTransform_t[idx1]; + } + } + + for(int i = 0 ; i < h;i++) + { + for(int j = 0 ; j < w; j++) + { + idx = i*w + j; + if(img_d[idx] < 0.0) + result.at(i,j) = 0; + else if(img_d[idx] > 255.0) + result.at(i,j) = 255; + else + result.at(i,j) = (uchar) img_d[idx]; + } + } + + delete [] sineTransform; + delete [] sineTransform_t; + delete [] denom; + delete [] invsineTransform; + delete [] invsineTransform_t; + delete [] img_d; +} + +void Cloning::poisson_solver(const Mat &img, Mat &gxx , Mat &gyy, Mat &result) +{ + + int w = img.size().width; + int h = img.size().height; + + unsigned long int idx; + + Mat lap = Mat(img.size(),CV_32FC1); + + lap = gxx + gyy; + + Mat bound = img.clone(); + + rectangle(bound, Point(1, 1), Point(img.cols-2, img.rows-2), Scalar::all(0), -1); + + double *boundary_point = new double[h*w]; + + for(int i =1;i(i,j) + (int)bound.at(i,(j+1)) + (int)bound.at(i,(j-1)) + + (int)bound.at(i-1,j) + (int)bound.at(i+1,j); + } + + Mat diff = Mat(h,w,CV_32FC1); + for(int i =0;i(i,j) = (float) (lap.at(i,j) - boundary_point[idx]); + } + } + + double *mod_diff = new double[(h-2)*(w-2)]; + for(int i = 0 ; i < h-2;i++) + { + for(int j = 0 ; j < w-2; j++) + { + idx = i*(w-2) + j; + mod_diff[idx] = diff.at(i+1,j+1); + + } + } + ///////////////////////////////////////////////////// Find DST ///////////////////////////////////////////////////// + + solve(img,mod_diff,result); + + delete [] mod_diff; + delete [] boundary_point; +} + +void Cloning::init_var(Mat &I, Mat &wmask) +{ + grx = Mat(I.size(),CV_32FC3); + gry = Mat(I.size(),CV_32FC3); + sgx = Mat(I.size(),CV_32FC3); + sgy = Mat(I.size(),CV_32FC3); + + split(I,rgb_channel); + + smask = Mat(wmask.size(),CV_32FC1); + srx32 = Mat(I.size(),CV_32FC3); + sry32 = Mat(I.size(),CV_32FC3); + smask1 = Mat(wmask.size(),CV_32FC1); + grx32 = Mat(I.size(),CV_32FC3); + gry32 = Mat(I.size(),CV_32FC3); +} + +void Cloning::initialization(Mat &I, Mat &mask, Mat &wmask) +{ + init_var(I,wmask); + + getGradientx(I,grx); + getGradienty(I,gry); + + getGradientx(mask,sgx); + getGradienty(mask,sgy); + + Mat Kernel(Size(3, 3), CV_8UC1); + Kernel.setTo(Scalar(1)); + + erode(wmask, wmask, Kernel, Point(-1,-1), 3); + + wmask.convertTo(smask,CV_32FC1,1.0/255.0); + I.convertTo(srx32,CV_32FC3,1.0/255.0); + I.convertTo(sry32,CV_32FC3,1.0/255.0); +} + +void Cloning::scalar_product(Mat mat, float r, float g, float b) +{ + vector channels; + split(mat,channels); + multiply(channels[2],r,channels[2]); + multiply(channels[1],g,channels[1]); + multiply(channels[0],b,channels[0]); + merge(channels,mat); +} + +void Cloning::array_product(Mat mat1, Mat mat2, Mat mat3) +{ + vector channels_temp1; + vector channels_temp2; + split(mat1,channels_temp1); + split(mat2,channels_temp2); + multiply(channels_temp2[2],mat3,channels_temp1[2]); + multiply(channels_temp2[1],mat3,channels_temp1[1]); + multiply(channels_temp2[0],mat3,channels_temp1[0]); + merge(channels_temp1,mat1); +} + +void Cloning::poisson(Mat &I, Mat &gx, Mat &gy, Mat &sx, Mat &sy) +{ + Mat fx = Mat(I.size(),CV_32FC3); + Mat fy = Mat(I.size(),CV_32FC3); + + fx = gx + sx; + fy = gy + sy; + + Mat gxx = Mat(I.size(),CV_32FC3); + Mat gyy = Mat(I.size(),CV_32FC3); + + lapx(fx,gxx); + lapy(fy,gyy); + + split(gxx,rgbx_channel); + split(gyy,rgby_channel); + + split(I,output); + + poisson_solver(rgb_channel[2],rgbx_channel[2], rgby_channel[2],output[2]); + poisson_solver(rgb_channel[1],rgbx_channel[1], rgby_channel[1],output[1]); + poisson_solver(rgb_channel[0],rgbx_channel[0], rgby_channel[0],output[0]); +} + +void Cloning::evaluate(Mat &I, Mat &wmask, Mat &cloned) +{ + bitwise_not(wmask,wmask); + + wmask.convertTo(smask1,CV_32FC1,1.0/255.0); + I.convertTo(grx32,CV_32FC3,1.0/255.0); + I.convertTo(gry32,CV_32FC3,1.0/255.0); + + array_product(grx32,grx,smask1); + array_product(gry32,gry,smask1); + + poisson(I,grx32,gry32,srx32,sry32); + + merge(output,cloned); +} + +void Cloning::normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num) +{ + int w = I.size().width; + int h = I.size().height; + + initialization(I,mask,wmask); + + if(num == 1) + { + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + } + else if(num == 2) + { + for(int i=0;i < h; i++) + for(int j=0; j < w; j++) + { + if(abs(sgx.at(i,j) - sgy.at(i,j)) > abs(grx.at(i,j) - gry.at(i,j))) + { + srx32.at(i,j) = sgx.at(i,j) * smask.at(i,j); + sry32.at(i,j) = sgy.at(i,j) * smask.at(i,j); + } + else + { + srx32.at(i,j) = grx.at(i,j) * smask.at(i,j); + sry32.at(i,j) = gry.at(i,j) * smask.at(i,j); + } + } + } + else if(num == 3) + { + Mat gray = Mat(mask.size(),CV_8UC1); + Mat gray8 = Mat(mask.size(),CV_8UC3); + cvtColor(mask, gray, COLOR_BGR2GRAY ); + vector temp; + split(I,temp); + gray.copyTo(temp[2]); + gray.copyTo(temp[1]); + gray.copyTo(temp[0]); + + merge(temp,gray8); + + getGradientx(gray8,sgx); + getGradienty(gray8,sgy); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + } + + evaluate(I,wmask,cloned); +} + +void Cloning::local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float red_mul=1.0, + float green_mul=1.0, float blue_mul=1.0) +{ + initialization(I,mask,wmask); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + scalar_product(srx32,red_mul,green_mul,blue_mul); + scalar_product(sry32,red_mul,green_mul,blue_mul); + + evaluate(I,wmask,cloned); +} + +void Cloning::illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta) +{ + initialization(I,mask,wmask); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + Mat mag = Mat(I.size(),CV_32FC3); + magnitude(srx32,sry32,mag); + + Mat multX, multY, multx_temp, multy_temp; + + multiply(srx32,pow(alpha,beta),multX); + pow(mag,-1*beta, multx_temp); + multiply(multX,multx_temp,srx32); + + multiply(sry32,pow(alpha,beta),multY); + pow(mag,-1*beta, multy_temp); + multiply(multY,multy_temp,sry32); + + Mat zeroMask = (srx32 != 0); + + srx32.copyTo(srx32, zeroMask); + sry32.copyTo(sry32, zeroMask); + + evaluate(I,wmask,cloned); +} + +void Cloning::texture_flatten(Mat &I, Mat &mask, Mat &wmask, double low_threshold, + double high_threshold, int kernel_size, Mat &cloned) +{ + initialization(I,mask,wmask); + + Mat out = Mat(mask.size(),CV_8UC1); + Canny(mask,out,low_threshold,high_threshold,kernel_size); + + Mat zeros(sgx.size(), CV_32FC3); + zeros.setTo(0); + Mat zerosMask = (out != 255); + zeros.copyTo(sgx, zerosMask); + zeros.copyTo(sgy, zerosMask); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + evaluate(I,wmask,cloned); +} diff --git a/modules/photo/test/test_cloning.cpp b/modules/photo/test/test_cloning.cpp new file mode 100644 index 0000000000..62fe243954 --- /dev/null +++ b/modules/photo/test/test_cloning.cpp @@ -0,0 +1,181 @@ +/*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) 2013, 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/photo.hpp" +#include + +using namespace cv; +using namespace std; + + +TEST(Photo_SeamlessClone_normal, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Normal_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(destination.empty()) << "Could not load destination image " << original_path2; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path3; + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + seamlessClone(source, destination, mask, p, result, 1); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_mixed, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Mixed_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(destination.empty()) << "Could not load destination image " << original_path2; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path3; + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + seamlessClone(source, destination, mask, p, result, 2); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_featureExchange, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Monochrome_Transfer/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(destination.empty()) << "Could not load destination image " << original_path2; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path3; + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + seamlessClone(source, destination, mask, p, result, 3); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_colorChange, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/color_change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path2; + + Mat result; + colorChange(source, mask, result, 1.5, .5, .5); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_illuminationChange, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Illumination_Change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path2; + + Mat result; + illuminationChange(source, mask, result, 0.2f, 0.4f); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_textureFlattening, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Texture_Flattening/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path2; + + Mat result; + textureFlattening(source, mask, result, 30, 45, 3); + + imwrite(folder + "cloned.png", result); + +} diff --git a/modules/photo/test/test_decolor.cpp b/modules/photo/test/test_decolor.cpp new file mode 100644 index 0000000000..bf21f37384 --- /dev/null +++ b/modules/photo/test/test_decolor.cpp @@ -0,0 +1,67 @@ +/*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) 2013, 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/photo.hpp" +#include + +using namespace cv; +using namespace std; + + +TEST(Photo_Decolor, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "decolor/"; + string original_path = folder + "color_image_1.png"; + + Mat original = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(original.channels()!=3) << "Load color input image " << original_path; + + Mat grayscale, color_boost; + decolor(original, grayscale, color_boost); + + imwrite(folder + "grayscale.png",grayscale); + imwrite(folder + "color_boost.png",color_boost); + +} diff --git a/modules/photo/test/test_npr.cpp b/modules/photo/test/test_npr.cpp new file mode 100755 index 0000000000..4d1c027ba1 --- /dev/null +++ b/modules/photo/test/test_npr.cpp @@ -0,0 +1,130 @@ +/*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) 2013, 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/photo.hpp" +#include + +using namespace cv; +using namespace std; + + +TEST(Photo_NPR_EdgePreserveSmoothing_RecursiveFilter, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + edgePreservingFilter(source,result,1); + + imwrite(folder + "smoothened_RF.png", result); + +} + +TEST(Photo_NPR_EdgePreserveSmoothing_NormConvFilter, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + edgePreservingFilter(source,result,2); + + imwrite(folder + "smoothened_NCF.png", result); + +} + +TEST(Photo_NPR_DetailEnhance, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + detailEnhance(source,result); + + imwrite(folder + "detail_enhanced.png", result); + +} + +TEST(Photo_NPR_PencilSketch, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result,result1; + pencilSketch(source,result,result1, 10, 0.1f, 0.03f); + + imwrite(folder + "pencil_sketch.png", result); + imwrite(folder + "color_pencil_sketch.png", result1); + +} + +TEST(Photo_NPR_Stylization, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + stylization(source,result); + + imwrite(folder + "stylized.png", result); + +} diff --git a/modules/ts/include/opencv2/ts/ocl_test.hpp b/modules/ts/include/opencv2/ts/ocl_test.hpp index 1b66799ed0..57220c7a7a 100644 --- a/modules/ts/include/opencv2/ts/ocl_test.hpp +++ b/modules/ts/include/opencv2/ts/ocl_test.hpp @@ -110,6 +110,26 @@ extern int test_loop_times; << cv::format("Size: %d x %d", mat1.size().width, mat1.size().height) << std::endl; \ } +#define OCL_EXPECT_MATS_NEAR(name, eps) \ +{ \ + EXPECT_MAT_NEAR(name ## _roi, u ## name ## _roi, eps); \ + int nextValue = rng.next(); \ + RNG dataRng1(nextValue), dataRng2(nextValue); \ + dataRng1.fill(name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \ + dataRng2.fill(u ## name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \ + EXPECT_MAT_NEAR(name, u ## name, 0/*FLT_EPSILON*/); \ +} + +#define OCL_EXPECT_MATS_NEAR_RELATIVE(name, eps) \ +{ \ + EXPECT_MAT_NEAR_RELATIVE(name ## _roi, u ## name ## _roi, eps); \ + int nextValue = rng.next(); \ + RNG dataRng1(nextValue), dataRng2(nextValue); \ + dataRng1.fill(name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \ + dataRng2.fill(u ## name ## _roi, RNG::UNIFORM, Scalar::all(-MAX_VALUE), Scalar::all(MAX_VALUE)); \ + EXPECT_MAT_NEAR_RELATIVE(name, u ## name, 0/*FLT_EPSILON*/); \ +} + #define EXPECT_MAT_SIMILAR(mat1, mat2, eps) \ { \ ASSERT_EQ(mat1.type(), mat2.type()); \ @@ -302,12 +322,12 @@ IMPLEMENT_PARAM_CLASS(Channels, int) #define OCL_OFF(fn) cv::ocl::setUseOpenCL(false); fn #define OCL_ON(fn) cv::ocl::setUseOpenCL(true); fn -#define OCL_ALL_DEPTHS Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F) +#define OCL_ALL_DEPTHS Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F) #define OCL_ALL_CHANNELS Values(1, 2, 3, 4) CV_ENUM(Interpolation, INTER_NEAREST, INTER_LINEAR, INTER_CUBIC, INTER_AREA) CV_ENUM(ThreshOp, THRESH_BINARY, THRESH_BINARY_INV, THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV) -CV_ENUM(BorderType, BORDER_REPLICATE, BORDER_REFLECT, BORDER_WRAP, BORDER_REFLECT_101) +CV_ENUM(BorderType, BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT, BORDER_WRAP, BORDER_REFLECT_101) #define OCL_INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ INSTANTIATE_TEST_CASE_P(OCL_ ## prefix, test_case_name, generator) diff --git a/modules/viz/CMakeLists.txt b/modules/viz/CMakeLists.txt index ee6354dc97..7ccd079216 100644 --- a/modules/viz/CMakeLists.txt +++ b/modules/viz/CMakeLists.txt @@ -1,57 +1,11 @@ -macro(find_qvtk) - find_library (QVTK_LIBRARY QVTK HINTS ${VTK_DIR} ${VTK_DIR}/bin) - find_path (QVTK_INCLUDE_DIR QVTKWidget.h HINT ${VTK_INCLUDE_DIRS}) - find_package_handle_standard_args(QVTK DEFAULT_MSG QVTK_LIBRARY QVTK_INCLUDE_DIR) - - if(QVTK_FOUND) - get_filename_component (QVTK_LIBRARY_DIR ${QVTK_LIBRARY} PATH) - list(APPEND VTK_LIBRARY_DIRS ${QVTK_LIBRARY_DIR}) - list(APPEND VTK_INCLUDE_DIRS ${QVTK_INCLUDE_DIR}) - set (VTK_USE_QVTK ON) - endif() -endmacro() - -macro(find_vtk) - find_package(VTK) - if(${VTK_MAJOR_VERSION} LESS 5) - MESSAGE(FATAL_ERROR "VTK 5 or more required!") - endif() - if(VTK_FOUND) - if (BUILD_SHARED_LIBS OR (NOT BUILD_SHARED_LIBS AND NOT VTK_BUILD_SHARED_LIBS)) - find_qvtk() - message(STATUS "VTK found (include: ${VTK_INCLUDE_DIRS}, lib: ${VTK_LIBRARY_DIRS})") - link_directories(${VTK_LIBRARY_DIRS}) - include_directories(SYSTEM ${VTK_INCLUDE_DIRS}) - set(HAVE_VTK ON) - else () - set(HAVE_VTK OFF) - message (FATAL_ERROR "VTK disabled. You are to build OpenCV in STATIC but VTK is SHARED!") - endif () - endif() -endmacro() - -if (NOT OPENCV_INITIAL_PASS AND DEFINED BUILD_opencv_viz AND BUILD_opencv_viz) - find_vtk() -endif() - -if(DEFINED HAVE_VTK AND HAVE_VTK) - set(VTK_USE_FILE ${VTK_USE_FILE} CACHE INTERNAL "VTK_USE_FILE") - include (${VTK_USE_FILE}) - add_definitions(-DHAVE_VTK) +if(NOT WITH_VTK OR NOT DEFINED HAVE_VTK OR NOT HAVE_VTK) + ocv_module_disable(viz) endif() +include(${VTK_USE_FILE}) set(the_description "Viz") -set(BUILD_opencv_viz_INIT OFF) -include_directories(src) -ocv_define_module(viz opencv_core) +ocv_define_module(viz opencv_core ${VTK_LIBRARIES}) -if(DEFINED BUILD_opencv_viz AND BUILD_opencv_viz AND DEFINED HAVE_VTK AND HAVE_VTK) - if (${VTK_VERSION_MAJOR} EQUAL 5) - target_link_libraries(opencv_viz vtkCommon vtkWidgets vtkFiltering vtkRendering) - else() - target_link_libraries(opencv_viz vtkViewsCore vtkRenderingLOD vtkIOPLY vtkRenderingFreeTypeOpenGL vtkRenderingVolumeOpenGL vtkFiltersTexture) - endif() - if(APPLE) - target_link_libraries(opencv_viz "-framework Cocoa") - endif() +if(APPLE AND BUILD_opencv_viz) + target_link_libraries(opencv_viz "-framework Cocoa") endif() diff --git a/modules/viz/doc/viz3d.rst b/modules/viz/doc/viz3d.rst index 79e262bb91..2f8dfcd9d0 100644 --- a/modules/viz/doc/viz3d.rst +++ b/modules/viz/doc/viz3d.rst @@ -76,68 +76,6 @@ Checks **point** for nan :param p: return true if **any** of the elements of the point is *nan*. -viz::VizAccessor ----------------- -.. ocv:class:: VizAccessor - -A singleton class that provides access by name infrastructure for 3D visualization windows. :: - - class CV_EXPORTS VizAccessor - { - public: - static VizAccessor & getInstance(); - static void release(); - - Viz3d get(const String &window_name); - - //! window names automatically have Viz - prefix even though not provided by the users - static void generateWindowName(const String &window_name, String &output); - - private: - /* hidden */ - }; - -viz::VizAccessor::getInstance ------------------------------ -Returns the single instance of VizAccessor. - -.. ocv:function:: static VizAccessor & getInstance() - -viz::VizAccessor::release -------------------------- -Deletes the single instance of VizAccessor. - -.. ocv:function:: static void release() - -viz::VizAccessor::get ---------------------- -Retrieves a window by its name. - -.. ocv:function:: Viz3d get(const String &window_name) - - :param window_name: Name of the window that is to be retrieved. - -This function returns a :ocv:class:`Viz3d` object with the given name. - -.. note:: If the window with that name already exists, that window is returned. Otherwise, new window is created with the given name, and it is returned. - -.. note:: Window names are automatically prefixed by "Viz - " if it is not done by the user. - - .. code-block:: cpp - - /// window and window_2 are the same windows. - viz::Viz3d window = viz::get("myWindow"); - viz::Viz3d window_2 = viz::get("Viz - myWindow"); - -viz::VizAccessor::generateWindowName ------------------------------------- -Generates a window name by prefixing "Viz - " if it has not already been prefixed. - -.. ocv:function:: static void generateWindowName(const String &window_name, String &output) - - :param window_name: Window name - :param output: Prefixed window name - viz::Viz3d ---------- .. ocv:class:: Viz3d diff --git a/modules/viz/doc/widget.rst b/modules/viz/doc/widget.rst index 6ceccf0cb9..bbbfef63a9 100644 --- a/modules/viz/doc/widget.rst +++ b/modules/viz/doc/widget.rst @@ -262,8 +262,8 @@ This 3D Widget defines a finite plane. :: class CV_EXPORTS WPlane : public Widget3D { public: - WPlane(const Vec4f& coefs, double size = 1.0, const Color &color = Color::white()); - WPlane(const Vec4f& coefs, const Point3f& pt, double size = 1.0, const Color &color = Color::white()); + WPlane(const Vec4f& coefs, float size = 1.0, const Color &color = Color::white()); + WPlane(const Vec4f& coefs, const Point3f& pt, float size = 1.0, const Color &color = Color::white()); private: /* hidden */ }; @@ -272,13 +272,13 @@ viz::WPlane::WPlane ------------------- Constructs a WPlane. -.. ocv:function:: WPlane(const Vec4f& coefs, double size = 1.0, const Color &color = Color::white()) +.. ocv:function:: WPlane(const Vec4f& coefs, float size = 1.0, const Color &color = Color::white()) :param coefs: Plane coefficients as in (A,B,C,D) where Ax + By + Cz + D = 0. :param size: Size of the plane. :param color: :ocv:class:`Color` of the plane. -.. ocv:function:: WPlane(const Vec4f& coefs, const Point3f& pt, double size = 1.0, const Color &color = Color::white()) +.. ocv:function:: WPlane(const Vec4f& coefs, const Point3f& pt, float size = 1.0, const Color &color = Color::white()) :param coefs: Plane coefficients as in (A,B,C,D) where Ax + By + Cz + D = 0. :param pt: Position of the plane. @@ -317,14 +317,14 @@ This 3D Widget defines an arrow. :: class CV_EXPORTS WArrow : public Widget3D { public: - WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()); + WArrow(const Point3f& pt1, const Point3f& pt2, float thickness = 0.03, const Color &color = Color::white()); }; viz::WArrow::WArrow ----------------------------- Constructs an WArrow. -.. ocv:function:: WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()) +.. ocv:function:: WArrow(const Point3f& pt1, const Point3f& pt2, float thickness = 0.03, const Color &color = Color::white()) :param pt1: Start point of the arrow. :param pt2: End point of the arrow. @@ -342,14 +342,14 @@ This 3D Widget defines a circle. :: class CV_EXPORTS WCircle : public Widget3D { public: - WCircle(const Point3f& pt, double radius, double thickness = 0.01, const Color &color = Color::white()); + WCircle(const Point3f& pt, float radius, float thickness = 0.01, const Color &color = Color::white()); }; viz::WCircle::WCircle ------------------------------- Constructs a WCircle. -.. ocv:function:: WCircle(const Point3f& pt, double radius, double thickness = 0.01, const Color &color = Color::white()) +.. ocv:function:: WCircle(const Point3f& pt, float radius, float thickness = 0.01, const Color &color = Color::white()) :param pt: Center of the circle. :param radius: Radius of the circle. @@ -365,14 +365,14 @@ This 3D Widget defines a cylinder. :: class CV_EXPORTS WCylinder : public Widget3D { public: - WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides = 30, const Color &color = Color::white()); + WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides = 30, const Color &color = Color::white()); }; viz::WCylinder::WCylinder ----------------------------------- Constructs a WCylinder. -.. ocv:function:: WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides = 30, const Color &color = Color::white()) +.. ocv:function:: WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides = 30, const Color &color = Color::white()) :param pt_on_axis: A point on the axis of the cylinder. :param axis_direction: Direction of the axis of the cylinder. @@ -416,14 +416,14 @@ This 3D Widget represents a coordinate system. :: class CV_EXPORTS WCoordinateSystem : public Widget3D { public: - WCoordinateSystem(double scale = 1.0); + WCoordinateSystem(float scale = 1.0); }; viz::WCoordinateSystem::WCoordinateSystem --------------------------------------------------- Constructs a WCoordinateSystem. -.. ocv:function:: WCoordinateSystem(double scale = 1.0) +.. ocv:function:: WCoordinateSystem(float scale = 1.0) :param scale: Determines the size of the axes. @@ -494,7 +494,7 @@ This 3D Widget represents 3D text. The text always faces the camera. :: class CV_EXPORTS WText3D : public Widget3D { public: - WText3D(const String &text, const Point3f &position, double text_scale = 1.0, double face_camera = true, const Color &color = Color::white()); + WText3D(const String &text, const Point3f &position, float text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()); void setText(const String &text); String getText() const; @@ -504,7 +504,7 @@ viz::WText3D::WText3D ------------------------------- Constructs a WText3D. -.. ocv:function:: WText3D(const String &text, const Point3f &position, double text_scale = 1.0, double face_camera = true, const Color &color = Color::white()) +.. ocv:function:: WText3D(const String &text, const Point3f &position, float text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()) :param text: Text content of the widget. :param position: Position of the text. @@ -649,15 +649,15 @@ This 3D Widget represents camera position in a scene by its axes or viewing frus { public: //! Creates camera coordinate frame (axes) at the origin - WCameraPosition(double scale = 1.0); + WCameraPosition(float scale = 1.0); //! Creates frustum based on the intrinsic marix K at the origin - WCameraPosition(const Matx33f &K, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Matx33f &K, float scale = 1.0, const Color &color = Color::white()); //! Creates frustum based on the field of view at the origin - WCameraPosition(const Vec2f &fov, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Matx33f &K, const Mat &img, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Matx33f &K, const Mat &img, float scale = 1.0, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Vec2f &fov, const Mat &img, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Vec2f &fov, const Mat &img, float scale = 1.0, const Color &color = Color::white()); }; viz::WCameraPosition::WCameraPosition @@ -666,7 +666,7 @@ Constructs a WCameraPosition. - **Display camera coordinate frame.** - .. ocv:function:: WCameraPosition(double scale = 1.0) + .. ocv:function:: WCameraPosition(float scale = 1.0) Creates camera coordinate frame at the origin. @@ -676,7 +676,7 @@ Constructs a WCameraPosition. - **Display the viewing frustum.** - .. ocv:function:: WCameraPosition(const Matx33f &K, double scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Matx33f &K, float scale = 1.0, const Color &color = Color::white()) :param K: Intrinsic matrix of the camera. :param scale: Scale of the frustum. @@ -684,7 +684,7 @@ Constructs a WCameraPosition. Creates viewing frustum of the camera based on its intrinsic matrix K. - .. ocv:function:: WCameraPosition(const Vec2f &fov, double scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()) :param fov: Field of view of the camera (horizontal, vertical). :param scale: Scale of the frustum. @@ -698,7 +698,7 @@ Constructs a WCameraPosition. - **Display image on the far plane of the viewing frustum.** - .. ocv:function:: WCameraPosition(const Matx33f &K, const Mat &img, double scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Matx33f &K, const Mat &img, float scale = 1.0, const Color &color = Color::white()) :param K: Intrinsic matrix of the camera. :param img: BGR or Gray-Scale image that is going to be displayed on the far plane of the frustum. @@ -707,7 +707,7 @@ Constructs a WCameraPosition. Creates viewing frustum of the camera based on its intrinsic matrix K, and displays image on the far end plane. - .. ocv:function:: WCameraPosition(const Vec2f &fov, const Mat &img, double scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Vec2f &fov, const Mat &img, float scale = 1.0, const Color &color = Color::white()) :param fov: Field of view of the camera (horizontal, vertical). :param img: BGR or Gray-Scale image that is going to be displayed on the far plane of the frustum. @@ -732,11 +732,11 @@ This 3D Widget represents a trajectory. :: enum {DISPLAY_FRAMES = 1, DISPLAY_PATH = 2}; //! Displays trajectory of the given path either by coordinate frames or polyline - WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), double scale = 1.0); + WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), float scale = 1.0); //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Matx33f &K, double scale = 1.0, const Color &color = Color::white()); + WTrajectory(const std::vector &path, const Matx33f &K, float scale = 1.0, const Color &color = Color::white()); //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Vec2f &fov, double scale = 1.0, const Color &color = Color::white()); + WTrajectory(const std::vector &path, const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()); private: /* hidden */ @@ -746,7 +746,7 @@ viz::WTrajectory::WTrajectory ----------------------------- Constructs a WTrajectory. -.. ocv:function:: WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), double scale = 1.0) +.. ocv:function:: WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), float scale = 1.0) :param path: List of poses on a trajectory. :param display_mode: Display mode. This can be DISPLAY_PATH, DISPLAY_FRAMES, DISPLAY_PATH & DISPLAY_FRAMES. @@ -759,7 +759,7 @@ Constructs a WTrajectory. * DISPLAY_FRAMES : Displays coordinate frames at each pose. * DISPLAY_PATH & DISPLAY_FRAMES : Displays both poly line and coordinate frames. -.. ocv:function:: WTrajectory(const std::vector &path, const Matx33f &K, double scale = 1.0, const Color &color = Color::white()) +.. ocv:function:: WTrajectory(const std::vector &path, const Matx33f &K, float scale = 1.0, const Color &color = Color::white()) :param path: List of poses on a trajectory. :param K: Intrinsic matrix of the camera. @@ -768,7 +768,7 @@ Constructs a WTrajectory. Displays frustums at each pose of the trajectory. -.. ocv:function:: WTrajectory(const std::vector &path, const Vec2f &fov, double scale = 1.0, const Color &color = Color::white()) +.. ocv:function:: WTrajectory(const std::vector &path, const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()) :param path: List of poses on a trajectory. :param fov: Field of view of the camera (horizontal, vertical). @@ -788,7 +788,7 @@ represent the direction from previous position to the current. :: { public: WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, - double init_sphere_radius = 0.021, sphere_radius = 0.007, + float init_sphere_radius = 0.021, sphere_radius = 0.007, Color &line_color = Color::white(), const Color &sphere_color = Color::white()); }; @@ -796,7 +796,7 @@ viz::WSpheresTrajectory::WSpheresTrajectory ------------------------------------------- Constructs a WSpheresTrajectory. -.. ocv:function:: WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, double init_sphere_radius = 0.021, double sphere_radius = 0.007, const Color &line_color = Color::white(), const Color &sphere_color = Color::white()) +.. ocv:function:: WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, float init_sphere_radius = 0.021, float sphere_radius = 0.007, const Color &line_color = Color::white(), const Color &sphere_color = Color::white()) :param path: List of poses on a trajectory. :param line_length: Length of the lines. diff --git a/modules/viz/include/opencv2/viz.hpp b/modules/viz/include/opencv2/viz.hpp index 5c2fe03d93..d4f08af725 100644 --- a/modules/viz/include/opencv2/viz.hpp +++ b/modules/viz/include/opencv2/viz.hpp @@ -63,9 +63,12 @@ namespace cv //! constructs camera pose from position, focal_point and up_vector (see gluLookAt() for more infromation) CV_EXPORTS Affine3f makeCameraPose(const Vec3f& position, const Vec3f& focal_point, const Vec3f& y_dir); - //! retrieves a window by its name + //! retrieves a window by its name. If no window with such name, then it creates new. CV_EXPORTS Viz3d get(const String &window_name); + //! Unregisters all Viz windows from internal database. After it 'get()' will create new windows instead getting existing from the database. + CV_EXPORTS void unregisterAllWindows(); + //! checks float value for Nan inline bool isNan(float x) { @@ -88,32 +91,6 @@ namespace cv template inline bool isNan(const Point3_<_Tp>& p) { return isNan(p.x) || isNan(p.y) || isNan(p.z); } - //! helper class that provides access by name infrastructure - class CV_EXPORTS VizAccessor - { - public: - static VizAccessor & getInstance(); - static void release(); - - Viz3d get(const String &window_name); - - //! window names automatically have Viz - prefix even though not provided by the users - static void generateWindowName(const String &window_name, String &output); - - private: - VizAccessor(); // Singleton - ~VizAccessor(); - - void add(Viz3d window); - void remove(const String &window_name); - - static VizAccessor * instance_; - - struct VizAccessorImpl; - VizAccessorImpl * impl_; - - friend class Viz3d; - }; } /* namespace viz */ } /* namespace cv */ diff --git a/modules/viz/include/opencv2/viz/types.hpp b/modules/viz/include/opencv2/viz/types.hpp index 3cccfa06fe..682006f959 100644 --- a/modules/viz/include/opencv2/viz/types.hpp +++ b/modules/viz/include/opencv2/viz/types.hpp @@ -176,8 +176,8 @@ namespace cv /// cv::viz::Color inline cv::viz::Color::Color() : Scalar(0, 0, 0) {} -inline cv::viz::Color::Color(double gray) : Scalar(gray, gray, gray) {} -inline cv::viz::Color::Color(double blue, double green, double red) : Scalar(blue, green, red) {} +inline cv::viz::Color::Color(double _gray) : Scalar(_gray, _gray, _gray) {} +inline cv::viz::Color::Color(double _blue, double _green, double _red) : Scalar(_blue, _green, _red) {} inline cv::viz::Color::Color(const Scalar& color) : Scalar(color) {} inline cv::viz::Color cv::viz::Color::black() { return Color( 0, 0, 0); } diff --git a/modules/viz/include/opencv2/viz/viz3d.hpp b/modules/viz/include/opencv2/viz/viz3d.hpp index b121472741..f19709eb52 100644 --- a/modules/viz/include/opencv2/viz/viz3d.hpp +++ b/modules/viz/include/opencv2/viz/viz3d.hpp @@ -49,7 +49,7 @@ #ifndef __OPENCV_VIZ_VIZ3D_HPP__ #define __OPENCV_VIZ_VIZ3D_HPP__ -#if !defined YES_I_AGREE_THAT_VIZ_API_IS_NOT_STABLE_NOW_AND_BINARY_COMPARTIBILITY_WONT_BE_SUPPORTED +#if !defined YES_I_AGREE_THAT_VIZ_API_IS_NOT_STABLE_NOW_AND_BINARY_COMPARTIBILITY_WONT_BE_SUPPORTED && !defined CVAPI_EXPORTS //#error "Viz is in beta state now. Please define macro above to use it" #endif @@ -64,7 +64,6 @@ namespace cv class CV_EXPORTS Viz3d { public: - typedef cv::Ptr Ptr; typedef void (*KeyboardCallback)(const KeyboardEvent&, void*); typedef void (*MouseCallback)(const MouseEvent&, void*); @@ -122,6 +121,8 @@ namespace cv void create(const String &window_name); void release(); + + friend class VizStorage; }; } /* namespace viz */ diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index 9a2c5ecbf8..07b3358993 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -143,8 +143,8 @@ namespace cv class CV_EXPORTS WPlane : public Widget3D { public: - WPlane(const Vec4f& coefs, double size = 1.0, const Color &color = Color::white()); - WPlane(const Vec4f& coefs, const Point3f& pt, double size = 1.0, const Color &color = Color::white()); + WPlane(const Vec4f& coefs, float size = 1.f, const Color &color = Color::white()); + WPlane(const Vec4f& coefs, const Point3f& pt, float size = 1.f, const Color &color = Color::white()); private: struct SetSizeImpl; }; @@ -158,19 +158,19 @@ namespace cv class CV_EXPORTS WArrow : public Widget3D { public: - WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()); + WArrow(const Point3f& pt1, const Point3f& pt2, float thickness = 0.03f, const Color &color = Color::white()); }; class CV_EXPORTS WCircle : public Widget3D { public: - WCircle(const Point3f& pt, double radius, double thickness = 0.01, const Color &color = Color::white()); + WCircle(const Point3f& pt, float radius, float thickness = 0.01f, const Color &color = Color::white()); }; class CV_EXPORTS WCylinder : public Widget3D { public: - WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides = 30, const Color &color = Color::white()); + WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides = 30, const Color &color = Color::white()); }; class CV_EXPORTS WCube : public Widget3D @@ -182,7 +182,7 @@ namespace cv class CV_EXPORTS WCoordinateSystem : public Widget3D { public: - WCoordinateSystem(double scale = 1.0); + WCoordinateSystem(float scale = 1.f); }; class CV_EXPORTS WPolyLine : public Widget3D @@ -210,7 +210,7 @@ namespace cv class CV_EXPORTS WText3D : public Widget3D { public: - WText3D(const String &text, const Point3f &position, double text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()); + WText3D(const String &text, const Point3f &position, float text_scale = 1.f, bool face_camera = true, const Color &color = Color::white()); void setText(const String &text); String getText() const; @@ -248,15 +248,15 @@ namespace cv { public: //! Creates camera coordinate frame (axes) at the origin - WCameraPosition(double scale = 1.0); + WCameraPosition(float scale = 1.f); //! Creates frustum based on the intrinsic marix K at the origin - WCameraPosition(const Matx33f &K, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Matx33f &K, float scale = 1.f, const Color &color = Color::white()); //! Creates frustum based on the field of view at the origin - WCameraPosition(const Vec2f &fov, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Vec2f &fov, float scale = 1.f, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Matx33f &K, const Mat &img, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Matx33f &K, const Mat &img, float scale = 1.f, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Vec2f &fov, const Mat &img, double scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Vec2f &fov, const Mat &img, float scale = 1.f, const Color &color = Color::white()); private: struct ProjectImage; @@ -268,11 +268,11 @@ namespace cv enum {DISPLAY_FRAMES = 1, DISPLAY_PATH = 2}; //! Displays trajectory of the given path either by coordinate frames or polyline - WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), double scale = 1.0); + WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), float scale = 1.f); //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Matx33f &K, double scale = 1.0, const Color &color = Color::white()); + WTrajectory(const std::vector &path, const Matx33f &K, float scale = 1.f, const Color &color = Color::white()); //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Vec2f &fov, double scale = 1.0, const Color &color = Color::white()); + WTrajectory(const std::vector &path, const Vec2f &fov, float scale = 1.f, const Color &color = Color::white()); private: struct ApplyPath; @@ -281,8 +281,8 @@ namespace cv class CV_EXPORTS WSpheresTrajectory: public Widget3D { public: - WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, double init_sphere_radius = 0.021, - double sphere_radius = 0.007, const Color &line_color = Color::white(), const Color &sphere_color = Color::white()); + WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, float init_sphere_radius = 0.021f, + float sphere_radius = 0.007f, const Color &line_color = Color::white(), const Color &sphere_color = Color::white()); }; class CV_EXPORTS WCloud: public Widget3D diff --git a/modules/viz/src/interactor_style.h b/modules/viz/src/interactor_style.hpp similarity index 100% rename from modules/viz/src/interactor_style.h rename to modules/viz/src/interactor_style.hpp diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp index 6df03e4f61..ab673b389c 100644 --- a/modules/viz/src/precomp.hpp +++ b/modules/viz/src/precomp.hpp @@ -54,14 +54,6 @@ #include #include -#if defined __GNUC__ -#pragma GCC system_header -#ifdef __DEPRECATED -#undef __DEPRECATED -#define __DEPRECATED_DISABLED__ -#endif -#endif - #include #include #include @@ -70,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -105,7 +96,6 @@ #include #include #include -#include #include #include #include @@ -119,11 +109,7 @@ #include #include #include - -#if defined __GNUC__ && defined __DEPRECATED_DISABLED__ -#define __DEPRECATED -#undef __DEPRECATED_DISABLED__ -#endif +#include #include #include @@ -135,20 +121,34 @@ namespace cv namespace viz { typedef std::map > WidgetActorMap; - } -} - -#include "interactor_style.h" -#include "viz3d_impl.hpp" - -namespace cv -{ - namespace viz - { typedef std::map VizMap; - typedef std::pair VizPair; + + class VizStorage + { + public: + static void unregisterAll(); + + //! window names automatically have Viz - prefix even though not provided by the users + static String generateWindowName(const String &window_name); + + private: + VizStorage(); // Static + ~VizStorage(); + + static void add(const Viz3d& window); + static Viz3d& get(const String &window_name); + static void remove(const String &window_name); + static bool windowExists(const String &window_name); + static void removeUnreferenced(); + + static VizMap storage; + friend class Viz3d; + }; } } +#include "interactor_style.hpp" +#include "viz3d_impl.hpp" + #endif diff --git a/modules/viz/src/shape_widgets.cpp b/modules/viz/src/shape_widgets.cpp index 2e062d52d5..6e4f4c70ff 100644 --- a/modules/viz/src/shape_widgets.cpp +++ b/modules/viz/src/shape_widgets.cpp @@ -104,7 +104,7 @@ struct cv::viz::WPlane::SetSizeImpl } }; -cv::viz::WPlane::WPlane(const Vec4f& coefs, double size, const Color &color) +cv::viz::WPlane::WPlane(const Vec4f& coefs, float size, const Color &color) { vtkSmartPointer plane = vtkSmartPointer::New(); plane->SetNormal(coefs[0], coefs[1], coefs[2]); @@ -124,7 +124,7 @@ cv::viz::WPlane::WPlane(const Vec4f& coefs, double size, const Color &color) setColor(color); } -cv::viz::WPlane::WPlane(const Vec4f& coefs, const Point3f& pt, double size, const Color &color) +cv::viz::WPlane::WPlane(const Vec4f& coefs, const Point3f& pt, float size, const Color &color) { vtkSmartPointer plane = vtkSmartPointer::New(); Point3f coefs3(coefs[0], coefs[1], coefs[2]); @@ -183,7 +183,7 @@ template<> cv::viz::WSphere cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// arrow widget implementation -cv::viz::WArrow::WArrow(const Point3f& pt1, const Point3f& pt2, double thickness, const Color &color) +cv::viz::WArrow::WArrow(const Point3f& pt1, const Point3f& pt2, float thickness, const Color &color) { vtkSmartPointer arrowSource = vtkSmartPointer::New(); arrowSource->SetShaftRadius(thickness); @@ -256,7 +256,7 @@ template<> cv::viz::WArrow cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// circle widget implementation -cv::viz::WCircle::WCircle(const Point3f& pt, double radius, double thickness, const Color& color) +cv::viz::WCircle::WCircle(const Point3f& pt, float radius, float thickness, const Color& color) { vtkSmartPointer disk = vtkSmartPointer::New(); // Maybe the resolution should be lower e.g. 50 or 25 @@ -292,7 +292,7 @@ template<> cv::viz::WCircle cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// cylinder widget implementation -cv::viz::WCylinder::WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides, const Color &color) +cv::viz::WCylinder::WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides, const Color &color) { const Point3f pt2 = pt_on_axis + axis_direction; vtkSmartPointer line = vtkSmartPointer::New(); @@ -355,7 +355,7 @@ template<> cv::viz::WCube cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// coordinate system widget implementation -cv::viz::WCoordinateSystem::WCoordinateSystem(double scale) +cv::viz::WCoordinateSystem::WCoordinateSystem(float scale) { vtkSmartPointer axes = vtkSmartPointer::New(); axes->SetOrigin(0, 0, 0); @@ -593,7 +593,7 @@ template<> cv::viz::WGrid cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// text3D widget implementation -cv::viz::WText3D::WText3D(const String &text, const Point3f &position, double text_scale, bool face_camera, const Color &color) +cv::viz::WText3D::WText3D(const String &text, const Point3f &position, float text_scale, bool face_camera, const Color &color) { vtkSmartPointer textSource = vtkSmartPointer::New(); textSource->SetText(text.c_str()); @@ -1032,7 +1032,7 @@ struct cv::viz::WCameraPosition::ProjectImage } }; -cv::viz::WCameraPosition::WCameraPosition(double scale) +cv::viz::WCameraPosition::WCameraPosition(float scale) { vtkSmartPointer axes = vtkSmartPointer::New(); axes->SetOrigin(0, 0, 0); @@ -1074,7 +1074,7 @@ cv::viz::WCameraPosition::WCameraPosition(double scale) WidgetAccessor::setProp(*this, actor); } -cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, double scale, const Color &color) +cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, float scale, const Color &color) { vtkSmartPointer camera = vtkSmartPointer::New(); float f_x = K(0,0); @@ -1116,7 +1116,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, double scale, const } -cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, double scale, const Color &color) +cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, float scale, const Color &color) { vtkSmartPointer camera = vtkSmartPointer::New(); @@ -1154,7 +1154,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, double scale, const setColor(color); } -cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, const Mat &image, double scale, const Color &color) +cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, const Mat &image, float scale, const Color &color) { CV_Assert(!image.empty() && image.depth() == CV_8U); float f_y = K(1,1); @@ -1168,7 +1168,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, const Mat &image, do WidgetAccessor::setProp(*this, actor); } -cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, const Mat &image, double scale, const Color &color) +cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, const Mat &image, float scale, const Color &color) { CV_Assert(!image.empty() && image.depth() == CV_8U); float fovy = fov[1] * 180.0f / CV_PI; @@ -1220,7 +1220,7 @@ struct cv::viz::WTrajectory::ApplyPath } }; -cv::viz::WTrajectory::WTrajectory(const std::vector &path, int display_mode, const Color &color, double scale) +cv::viz::WTrajectory::WTrajectory(const std::vector &path, int display_mode, const Color &color, float scale) { vtkSmartPointer appendFilter = vtkSmartPointer::New(); @@ -1316,7 +1316,7 @@ cv::viz::WTrajectory::WTrajectory(const std::vector &path, int display WidgetAccessor::setProp(*this, actor); } -cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Matx33f &K, double scale, const Color &color) +cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Matx33f &K, float scale, const Color &color) { vtkSmartPointer camera = vtkSmartPointer::New(); float f_x = K(0,0); @@ -1360,7 +1360,7 @@ cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Matx3 setColor(color); } -cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Vec2f &fov, double scale, const Color &color) +cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Vec2f &fov, float scale, const Color &color) { vtkSmartPointer camera = vtkSmartPointer::New(); @@ -1409,7 +1409,7 @@ template<> cv::viz::WTrajectory cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// spheres trajectory widget implementation -cv::viz::WSpheresTrajectory::WSpheresTrajectory(const std::vector &path, float line_length, double init_sphere_radius, double sphere_radius, +cv::viz::WSpheresTrajectory::WSpheresTrajectory(const std::vector &path, float line_length, float init_sphere_radius, float sphere_radius, const Color &line_color, const Color &sphere_color) { vtkSmartPointer appendFilter = vtkSmartPointer::New(); diff --git a/modules/viz/src/viz.cpp b/modules/viz/src/viz.cpp index 747c8de342..6a08dfa34a 100644 --- a/modules/viz/src/viz.cpp +++ b/modules/viz/src/viz.cpp @@ -107,70 +107,48 @@ namespace cv { namespace viz }} /////////////////////////////////////////////////////////////////////////////////////////////// -/// Viz accessor implementation +/// VizStorage implementation -cv::viz::VizAccessor * cv::viz::VizAccessor::instance_ = 0; +cv::viz::VizMap cv::viz::VizStorage::storage; +void cv::viz::VizStorage::unregisterAll() { storage.clear(); } -struct cv::viz::VizAccessor::VizAccessorImpl +cv::viz::Viz3d& cv::viz::VizStorage::get(const String &window_name) { - cv::viz::VizMap viz_map; -}; - -cv::viz::VizAccessor::VizAccessor() { impl_ = new cv::viz::VizAccessor::VizAccessorImpl;} -cv::viz::VizAccessor::~VizAccessor() { delete impl_; } - -cv::viz::VizAccessor & cv::viz::VizAccessor::getInstance() -{ - if (!instance_) - instance_ = new VizAccessor(); - - return *instance_; + String name = generateWindowName(window_name); + VizMap::iterator vm_itr = storage.find(name); + CV_Assert(vm_itr != storage.end()); + return vm_itr->second; } -void cv::viz::VizAccessor::release() -{ - if (instance_) - { - delete instance_; - instance_ = 0; - } -} - -cv::viz::Viz3d cv::viz::VizAccessor::get(const String & window_name) -{ - // Add the prefix Viz - String name; - generateWindowName(window_name, name); - - VizMap::iterator vm_itr = impl_->viz_map.find(name); - return vm_itr != impl_->viz_map.end() ? vm_itr->second : Viz3d(window_name); -} - -void cv::viz::VizAccessor::add(Viz3d window) +void cv::viz::VizStorage::add(const Viz3d& window) { String window_name = window.getWindowName(); - VizMap::iterator vm_itr = impl_->viz_map.find(window_name); - if (vm_itr == impl_->viz_map.end()) - impl_->viz_map.insert(VizPair(window_name, window)); + VizMap::iterator vm_itr = storage.find(window_name); + CV_Assert(vm_itr == storage.end()); + storage.insert(std::make_pair(window_name, window)); } -void cv::viz::VizAccessor::remove(const String &window_name) +bool cv::viz::VizStorage::windowExists(const String &window_name) { - // Add the prefix Viz - String name; - generateWindowName(window_name, name); - - VizMap::iterator vm_itr = impl_->viz_map.find(name); - if (vm_itr != impl_->viz_map.end()) - impl_->viz_map.erase(vm_itr); + String name = generateWindowName(window_name); + return storage.find(name) != storage.end(); } -void cv::viz::VizAccessor::generateWindowName(const String &window_name, String &output) +void cv::viz::VizStorage::removeUnreferenced() { - output = "Viz"; + for(VizMap::iterator pos = storage.begin(); pos != storage.end();) + if(pos->second.impl_->ref_counter == 1) + storage.erase(pos++); + else + ++pos; +} + +cv::String cv::viz::VizStorage::generateWindowName(const String &window_name) +{ + String output = "Viz"; // Already is Viz if (window_name == output) - return; + return output; String prefixed = output + " - "; if (window_name.substr(0, prefixed.length()) == prefixed) @@ -179,9 +157,9 @@ void cv::viz::VizAccessor::generateWindowName(const String &window_name, String output = prefixed + window_name; // Doesn't have prefix else output = (window_name == "" ? output : prefixed + window_name); + + return output; } -cv::viz::Viz3d cv::viz::get(const String &window_name) -{ - return cv::viz::VizAccessor::getInstance().get(window_name); -} +cv::viz::Viz3d cv::viz::get(const String &window_name) { return Viz3d (window_name); } +void cv::viz::unregisterAllWindows() { VizStorage::unregisterAll(); } diff --git a/modules/viz/src/viz3d.cpp b/modules/viz/src/viz3d.cpp index f5a0bc8895..08cb880dec 100644 --- a/modules/viz/src/viz3d.cpp +++ b/modules/viz/src/viz3d.cpp @@ -52,7 +52,8 @@ cv::viz::Viz3d::Viz3d(const String& window_name) : impl_(0) { create(window_name cv::viz::Viz3d::Viz3d(const Viz3d& other) : impl_(other.impl_) { - if (impl_) CV_XADD(&impl_->ref_counter, 1); + if (impl_) + CV_XADD(&impl_->ref_counter, 1); } cv::viz::Viz3d& cv::viz::Viz3d::operator=(const Viz3d& other) @@ -61,7 +62,8 @@ cv::viz::Viz3d& cv::viz::Viz3d::operator=(const Viz3d& other) { release(); impl_ = other.impl_; - if (impl_) CV_XADD(&impl_->ref_counter, 1); + if (impl_) + CV_XADD(&impl_->ref_counter, 1); } return *this; } @@ -70,24 +72,33 @@ cv::viz::Viz3d::~Viz3d() { release(); } void cv::viz::Viz3d::create(const String &window_name) { - if (impl_) release(); - impl_ = new VizImpl(window_name); - impl_->ref_counter = 1; - // Register the window - cv::viz::VizAccessor::getInstance().add(*this); + if (impl_) + release(); + + if (VizStorage::windowExists(window_name)) + *this = VizStorage::get(window_name); + else + { + impl_ = new VizImpl(window_name); + impl_->ref_counter = 1; + + // Register the window + VizStorage::add(*this); + } } void cv::viz::Viz3d::release() { - // If the current referene count is equal to 2, we can delete it - // - 2 : because minimum there will be two instances, one of which is in the map - if (impl_ && CV_XADD(&impl_->ref_counter, -1) == 2) + if (impl_ && CV_XADD(&impl_->ref_counter, -1) == 1) { - // Erase the window - cv::viz::VizAccessor::getInstance().remove(getWindowName()); delete impl_; impl_ = 0; } + + if (impl_ && impl_->ref_counter == 1) + VizStorage::removeUnreferenced(); + + impl_ = 0; } void cv::viz::Viz3d::spin() { impl_->spin(); } diff --git a/modules/viz/src/viz3d_impl.cpp b/modules/viz/src/viz3d_impl.cpp index ae8fc150c6..b1173f645d 100644 --- a/modules/viz/src/viz3d_impl.cpp +++ b/modules/viz/src/viz3d_impl.cpp @@ -48,6 +48,8 @@ #include "precomp.hpp" +vtkRenderWindowInteractor* vtkRenderWindowInteractorFixNew(); + #if 1 || !defined __APPLE__ vtkRenderWindowInteractor* vtkRenderWindowInteractorFixNew() { @@ -57,7 +59,7 @@ vtkRenderWindowInteractor* vtkRenderWindowInteractorFixNew() ///////////////////////////////////////////////////////////////////////////////////////////// cv::viz::Viz3d::VizImpl::VizImpl(const String &name) - : style_(vtkSmartPointer::New()) , widget_actor_map_(new WidgetActorMap), s_lastDone_(0.0) + : s_lastDone_(0.0), style_(vtkSmartPointer::New()), widget_actor_map_(new WidgetActorMap) { renderer_ = vtkSmartPointer::New(); @@ -77,7 +79,7 @@ cv::viz::Viz3d::VizImpl::VizImpl(const String &name) style_->UseTimersOn(); ///////////////////////////////////////////////// - interactor_ = vtkSmartPointer ::Take(vtkRenderWindowInteractorFixNew()); + interactor_ = vtkSmartPointer::Take(vtkRenderWindowInteractorFixNew()); window_->AlphaBitPlanesOff(); window_->PointSmoothingOff(); @@ -95,9 +97,9 @@ cv::viz::Viz3d::VizImpl::VizImpl(const String &name) timer_id_ = interactor_->CreateRepeatingTimer(5000L); // Set a simple PointPicker - vtkSmartPointer pp = vtkSmartPointer::New(); - pp->SetTolerance(pp->GetTolerance() * 2); - interactor_->SetPicker(pp); + //vtkSmartPointer pp = vtkSmartPointer::New(); + //pp->SetTolerance(pp->GetTolerance() * 2); + //interactor_->SetPicker(pp); exit_main_loop_timer_callback_ = vtkSmartPointer::New(); exit_main_loop_timer_callback_->viz_ = this; @@ -112,8 +114,7 @@ cv::viz::Viz3d::VizImpl::VizImpl(const String &name) ////////////////////////////// - String window_name; - VizAccessor::generateWindowName(name, window_name); + String window_name = VizStorage::generateWindowName(name); window_->SetWindowName(window_name.c_str()); } @@ -314,45 +315,6 @@ bool cv::viz::Viz3d::VizImpl::removeActorFromRenderer(const vtkSmartPointer &data, vtkSmartPointer &actor, bool use_scalars) -{ - if (!actor) - actor = vtkSmartPointer::New(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(data); -#else - mapper->SetInputData(data); -#endif - - if (use_scalars) - { - vtkSmartPointer scalars = data->GetPointData()->GetScalars(); - if (scalars) - { - cv::Vec3d minmax(scalars->GetRange()); - mapper->SetScalarRange(minmax.val); - mapper->SetScalarModeToUsePointData(); - - // interpolation OFF, if data is a vtkPolyData that contains only vertices, ON for anything else. - vtkPolyData* polyData = vtkPolyData::SafeDownCast(data); - bool interpolation = (polyData && polyData->GetNumberOfCells() != polyData->GetNumberOfVerts()); - - mapper->SetInterpolateScalarsBeforeMapping(interpolation); - mapper->ScalarVisibilityOn(); - } - } - mapper->ImmediateModeRenderingOff(); - - actor->SetNumberOfCloudPoints(int(std::max(1, data->GetNumberOfPoints() / 10))); - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->BackfaceCullingOn(); - - actor->SetMapper(mapper); -} - ////////////////////////////////////////////////////////////////////////////////////////////// void cv::viz::Viz3d::VizImpl::setBackgroundColor(const Color& color) { @@ -542,48 +504,6 @@ void cv::viz::Viz3d::VizImpl::setRepresentation(int representation) } } -////////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::updateCells(vtkSmartPointer &cells, vtkSmartPointer &initcells, vtkIdType nr_points) -{ - // If no init cells and cells has not been initialized... - if (!cells) - cells = vtkSmartPointer::New(); - - // If we have less values then we need to recreate the array - if (cells->GetNumberOfTuples() < nr_points) - { - cells = vtkSmartPointer::New(); - - // If init cells is given, and there's enough data in it, use it - if (initcells && initcells->GetNumberOfTuples() >= nr_points) - { - cells->DeepCopy(initcells); - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - else - { - // If the number of tuples is still too small, we need to recreate the array - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - vtkIdType *cell = cells->GetPointer(0); - // Fill it with 1s - std::fill_n(cell, nr_points * 2, 1); - cell++; - for (vtkIdType i = 0; i < nr_points; ++i, cell += 2) - *cell = i; - // Save the results in initcells - initcells = vtkSmartPointer::New(); - initcells->DeepCopy(cells); - } - } - else - { - // The assumption here is that the current set of cells has more data than needed - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } -} ////////////////////////////////////////////////////////////////////////////////////////////// void cv::viz::Viz3d::VizImpl::setFullScreen(bool mode) diff --git a/modules/viz/src/viz3d_impl.hpp b/modules/viz/src/viz3d_impl.hpp index 88f8424bf4..59f45a8fa0 100644 --- a/modules/viz/src/viz3d_impl.hpp +++ b/modules/viz/src/viz3d_impl.hpp @@ -52,7 +52,6 @@ struct cv::viz::Viz3d::VizImpl { public: - typedef cv::Ptr Ptr; typedef Viz3d::KeyboardCallback KeyboardCallback; typedef Viz3d::MouseCallback MouseCallback; @@ -181,9 +180,6 @@ private: bool camera_set_; bool removeActorFromRenderer(const vtkSmartPointer &actor); - - void createActorFromVTKDataSet(const vtkSmartPointer &data, vtkSmartPointer &actor, bool use_scalars = true); - void updateCells(vtkSmartPointer &cells, vtkSmartPointer &initcells, vtkIdType nr_points); }; diff --git a/modules/viz/test/test_tutorial2.cpp b/modules/viz/test/test_tutorial2.cpp new file mode 100644 index 0000000000..6e9189b8f2 --- /dev/null +++ b/modules/viz/test/test_tutorial2.cpp @@ -0,0 +1,54 @@ +#include "test_precomp.hpp" + +using namespace cv; +using namespace std; + +void tutorial2() +{ + /// Create a window + viz::Viz3d myWindow("Coordinate Frame"); + + /// Add coordinate axes + myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); + + /// Add line to represent (1,1,1) axis + viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f)); + axis.setRenderingProperty(viz::LINE_WIDTH, 4.0); + myWindow.showWidget("Line Widget", axis); + + /// Construct a cube widget + viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue()); + cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0); + + /// Display widget (update if already displayed) + myWindow.showWidget("Cube Widget", cube_widget); + + /// Rodrigues vector + Mat rot_vec = Mat::zeros(1,3,CV_32F); + float translation_phase = 0.0, translation = 0.0; + while(!myWindow.wasStopped()) + { + /* Rotation using rodrigues */ + /// Rotate around (1,1,1) + rot_vec.at(0,0) += CV_PI * 0.01f; + rot_vec.at(0,1) += CV_PI * 0.01f; + rot_vec.at(0,2) += CV_PI * 0.01f; + + /// Shift on (1,1,1) + translation_phase += CV_PI * 0.01f; + translation = sin(translation_phase); + + /// Construct pose + Affine3f pose(rot_vec, Vec3f(translation, translation, translation)); + + myWindow.setWidgetPose("Cube Widget", pose); + + myWindow.spinOnce(1, true); + } +} + + +TEST(Viz_viz3d, DISABLED_tutorial2_pose_of_widget) +{ + tutorial2(); +} diff --git a/platforms/android/service/engine/AndroidManifest.xml b/platforms/android/service/engine/AndroidManifest.xml index 162d31eb02..7cae6ce8a0 100644 --- a/platforms/android/service/engine/AndroidManifest.xml +++ b/platforms/android/service/engine/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="216@ANDROID_PLATFORM_VERSION_CODE@" + android:versionName="2.16" > diff --git a/platforms/android/service/engine/jni/NativeService/PackageInfo.cpp b/platforms/android/service/engine/jni/NativeService/PackageInfo.cpp index 64ea70dae8..98ea828747 100644 --- a/platforms/android/service/engine/jni/NativeService/PackageInfo.cpp +++ b/platforms/android/service/engine/jni/NativeService/PackageInfo.cpp @@ -170,7 +170,7 @@ inline string JoinPlatform(int platform) return result; } -inline int SplitPlatfrom(const vector& features) +inline int SplitPlatform(const vector& features) { int result = 0; @@ -419,7 +419,7 @@ InstallPath(install_path) return; } - Platform = SplitPlatfrom(features); + Platform = SplitPlatform(features); if (PLATFORM_UNKNOWN != Platform) { switch (Platform) diff --git a/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp b/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp index 8637dfee30..83dd9c27e1 100644 --- a/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp +++ b/platforms/android/service/engine/jni/Tests/HardwareDetectionTest.cpp @@ -170,7 +170,7 @@ TEST(CpuID, CheckVFPv3) EXPECT_TRUE(cpu_id & FEATURES_HAS_VFPv3); } -TEST(PlatfromDetector, CheckTegra) +TEST(PlatformDetector, CheckTegra) { EXPECT_NE(PLATFORM_UNKNOWN, DetectKnownPlatforms()); } diff --git a/platforms/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java b/platforms/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java index 4e9050fa4d..8e8389dcc7 100644 --- a/platforms/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java +++ b/platforms/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java @@ -90,28 +90,28 @@ public class ManagerActivity extends Activity mInstalledPackageView.setAdapter(mInstalledPacksAdapter); TextView HardwarePlatformView = (TextView)findViewById(R.id.HardwareValue); - int Platfrom = HardwareDetector.DetectKnownPlatforms(); + int Platform = HardwareDetector.DetectKnownPlatforms(); int CpuId = HardwareDetector.GetCpuID(); - if (HardwareDetector.PLATFORM_UNKNOWN != Platfrom) + if (HardwareDetector.PLATFORM_UNKNOWN != Platform) { - if (HardwareDetector.PLATFORM_TEGRA == Platfrom) + if (HardwareDetector.PLATFORM_TEGRA == Platform) { HardwarePlatformView.setText("Tegra"); } - else if (HardwareDetector.PLATFORM_TEGRA2 == Platfrom) + else if (HardwareDetector.PLATFORM_TEGRA2 == Platform) { HardwarePlatformView.setText("Tegra 2"); } - else if (HardwareDetector.PLATFORM_TEGRA3 == Platfrom) + else if (HardwareDetector.PLATFORM_TEGRA3 == Platform) { HardwarePlatformView.setText("Tegra 3"); } - else if (HardwareDetector.PLATFORM_TEGRA4i == Platfrom) + else if (HardwareDetector.PLATFORM_TEGRA4i == Platform) { HardwarePlatformView.setText("Tegra 4i"); } - else if (HardwareDetector.PLATFORM_TEGRA4 == Platfrom) + else if (HardwareDetector.PLATFORM_TEGRA4 == Platform) { HardwarePlatformView.setText("Tegra 4"); } diff --git a/platforms/android/service/readme.txt b/platforms/android/service/readme.txt index 1e757a0e5f..a280b506f0 100644 --- a/platforms/android/service/readme.txt +++ b/platforms/android/service/readme.txt @@ -14,20 +14,20 @@ manually using adb tool: .. code-block:: sh - adb install OpenCV-2.4.7-android-sdk/apk/OpenCV_2.4.7_Manager_2.14_.apk + adb install OpenCV-2.4.7.1-android-sdk/apk/OpenCV_2.4.7.1_Manager_2.15_.apk Use the table below to determine proper OpenCV Manager package for your device: -+------------------------------+--------------+----------------------------------------------------+ -| Hardware Platform | Android ver. | Package name | -+==============================+==============+====================================================+ -| armeabi-v7a (ARMv7-A + NEON) | >= 2.3 | OpenCV_2.4.7_Manager_2.14_armv7a-neon.apk | -+------------------------------+--------------+----------------------------------------------------+ -| armeabi-v7a (ARMv7-A + NEON) | = 2.2 | OpenCV_2.4.7_Manager_2.14_armv7a-neon-android8.apk | -+------------------------------+--------------+----------------------------------------------------+ -| armeabi (ARMv5, ARMv6) | >= 2.3 | OpenCV_2.4.7_Manager_2.14_armeabi.apk | -+------------------------------+--------------+----------------------------------------------------+ -| Intel x86 | >= 2.3 | OpenCV_2.4.7_Manager_2.14_x86.apk | -+------------------------------+--------------+----------------------------------------------------+ -| MIPS | >= 2.3 | OpenCV_2.4.7_Manager_2.14_mips.apk | -+------------------------------+--------------+----------------------------------------------------+ ++------------------------------+--------------+------------------------------------------------------+ +| Hardware Platform | Android ver. | Package name | ++==============================+==============+======================================================+ +| armeabi-v7a (ARMv7-A + NEON) | >= 2.3 | OpenCV_2.4.7.1_Manager_2.15_armv7a-neon.apk | ++------------------------------+--------------+------------------------------------------------------+ +| armeabi-v7a (ARMv7-A + NEON) | = 2.2 | OpenCV_2.4.7.1_Manager_2.15_armv7a-neon-android8.apk | ++------------------------------+--------------+------------------------------------------------------+ +| armeabi (ARMv5, ARMv6) | >= 2.3 | OpenCV_2.4.7.1_Manager_2.15_armeabi.apk | ++------------------------------+--------------+------------------------------------------------------+ +| Intel x86 | >= 2.3 | OpenCV_2.4.7.1_Manager_2.15_x86.apk | ++------------------------------+--------------+------------------------------------------------------+ +| MIPS | >= 2.3 | OpenCV_2.4.7.1_Manager_2.15_mips.apk | ++------------------------------+--------------+------------------------------------------------------+ diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 2aa71f047c..4b0bf011d9 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -29,6 +29,10 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) ocv_include_directories("${OpenCV_SOURCE_DIR}/modules/cudafilters/include") endif() + if(HAVE_opencv_ocl) + ocv_include_directories("${OpenCV_SOURCE_DIR}/modules/ocl/include") + endif() + if(CMAKE_COMPILER_IS_GNUCXX AND NOT ENABLE_NOISY_WARNINGS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function") endif() @@ -56,6 +60,10 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) target_link_libraries(${the_target} opencv_cudaarithm opencv_cudafilters) endif() + if(HAVE_opencv_ocl) + target_link_libraries(${the_target} opencv_ocl) + endif() + set_target_properties(${the_target} PROPERTIES OUTPUT_NAME "cpp-${sample_kind}-${name}" PROJECT_LABEL "(${sample_KIND}) ${name}") diff --git a/samples/cpp/bagofwords_classification.cpp b/samples/cpp/bagofwords_classification.cpp index b841b63f8b..20ff1dcfbb 100644 --- a/samples/cpp/bagofwords_classification.cpp +++ b/samples/cpp/bagofwords_classification.cpp @@ -1,8 +1,13 @@ +#include "opencv2/opencv_modules.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/ml/ml.hpp" +#ifdef HAVE_OPENCV_OCL +#define _OCL_SVM_ 1 //select whether using ocl::svm method or not, default is using +#include "opencv2/ocl/ocl.hpp" +#endif #include #include @@ -2373,9 +2378,15 @@ static void setSVMTrainAutoParams( CvParamGrid& c_grid, CvParamGrid& gamma_grid, degree_grid.step = 0; } +#if defined HAVE_OPENCV_OCL && _OCL_SVM_ +static void trainSVMClassifier( cv::ocl::CvSVM_OCL& svm, const SVMTrainParamsExt& svmParamsExt, const string& objClassName, VocData& vocData, + Ptr& bowExtractor, const Ptr& fdetector, + const string& resPath ) +#else static void trainSVMClassifier( CvSVM& svm, const SVMTrainParamsExt& svmParamsExt, const string& objClassName, VocData& vocData, Ptr& bowExtractor, const Ptr& fdetector, const string& resPath ) +#endif { /* first check if a previously trained svm for the current class has been saved to file */ string svmFilename = resPath + svmsDir + "/" + objClassName + ".xml.gz"; @@ -2448,9 +2459,15 @@ static void trainSVMClassifier( CvSVM& svm, const SVMTrainParamsExt& svmParamsEx } } +#if defined HAVE_OPENCV_OCL && _OCL_SVM_ +static void computeConfidences( cv::ocl::CvSVM_OCL& svm, const string& objClassName, VocData& vocData, + Ptr& bowExtractor, const Ptr& fdetector, + const string& resPath ) +#else static void computeConfidences( CvSVM& svm, const string& objClassName, VocData& vocData, Ptr& bowExtractor, const Ptr& fdetector, const string& resPath ) +#endif { cout << "*** CALCULATING CONFIDENCES FOR CLASS " << objClassName << " ***" << endl; cout << "CALCULATING BOW VECTORS FOR TEST SET OF " << objClassName << "..." << endl; @@ -2589,7 +2606,11 @@ int main(int argc, char** argv) for( size_t classIdx = 0; classIdx < objClasses.size(); ++classIdx ) { // Train a classifier on train dataset +#if defined HAVE_OPENCV_OCL && _OCL_SVM_ + cv::ocl::CvSVM_OCL svm; +#else CvSVM svm; +#endif trainSVMClassifier( svm, svmTrainParamsExt, objClasses[classIdx], vocData, bowExtractor, featureDetector, resPath ); diff --git a/samples/cpp/cloning_demo.cpp b/samples/cpp/cloning_demo.cpp new file mode 100644 index 0000000000..24d9b7facf --- /dev/null +++ b/samples/cpp/cloning_demo.cpp @@ -0,0 +1,246 @@ +/* +* cloning_demo.cpp +* +* Author: +* Siddharth Kherada +* +* This tutorial demonstrates how to use OpenCV seamless cloning +* module without GUI. +* +* 1- Normal Cloning +* 2- Mixed Cloning +* 3- Monochrome Transfer +* 4- Color Change +* 5- Illumination change +* 6- Texture Flattening + +* The program takes as input a source and a destination image (for 1-3 methods) +* and ouputs the cloned image. +* +* Download test images from opencv_extra folder @github. +* +*/ + +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +int main() +{ + cout << endl; + cout << "Cloning Module" << endl; + cout << "---------------" << endl; + cout << "Options: " << endl; + cout << endl; + cout << "1) Normal Cloning " << endl; + cout << "2) Mixed Cloning " << endl; + cout << "3) Monochrome Transfer " << endl; + cout << "4) Local Color Change " << endl; + cout << "5) Local Illumination Change " << endl; + cout << "6) Texture Flattening " << endl; + cout << endl; + cout << "Press number 1-6 to choose from above techniques: "; + int num = 1; + cin >> num; + cout << endl; + + if(num == 1) + { + string folder = "cloning/Normal_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(destination.empty()) + { + cout << "Could not load destination image " << original_path2 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path3 << endl; + exit(0); + } + + Mat result; + Point p; + p.x = 400; + p.y = 100; + + seamlessClone(source, destination, mask, p, result, 1); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 2) + { + string folder = "cloning/Mixed_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(destination.empty()) + { + cout << "Could not load destination image " << original_path2 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path3 << endl; + exit(0); + } + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + + seamlessClone(source, destination, mask, p, result, 2); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 3) + { + string folder = "cloning/Monochrome_Transfer/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(destination.empty()) + { + cout << "Could not load destination image " << original_path2 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path3 << endl; + exit(0); + } + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + + seamlessClone(source, destination, mask, p, result, 3); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 4) + { + string folder = "cloning/Color_Change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path2 << endl; + exit(0); + } + + Mat result; + + colorChange(source, mask, result, 1.5, .5, .5); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 5) + { + string folder = "cloning/Illumination_Change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path2 << endl; + exit(0); + } + + Mat result; + + illuminationChange(source, mask, result, 0.2f, 0.4f); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 6) + { + string folder = "cloning/Texture_Flattening/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path2 << endl; + exit(0); + } + + Mat result; + + textureFlattening(source, mask, result, 30, 45, 3); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + waitKey(0); +} diff --git a/samples/cpp/cloning_gui.cpp b/samples/cpp/cloning_gui.cpp new file mode 100644 index 0000000000..2457b12154 --- /dev/null +++ b/samples/cpp/cloning_gui.cpp @@ -0,0 +1,546 @@ +/* +* cloning.cpp +* +* Author: +* Siddharth Kherada +* +* This tutorial demonstrates how to use OpenCV seamless cloning +* module. +* +* 1- Normal Cloning +* 2- Mixed Cloning +* 3- Monochrome Transfer +* 4- Color Change +* 5- Illumination change +* 6- Texture Flattening + +* The program takes as input a source and a destination image (for 1-3 methods) +* and ouputs the cloned image. + +* Step 1: +* -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button. +* -> To set the Polygon ROI, click the right mouse button or 'd' key. +* -> To reset the region selected, click the middle mouse button or 'r' key. + +* Step 2: +* -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button. +* -> To get the cloned result, click the right mouse button or 'c' key. +* -> To quit the program, use 'q' key. +* +* Result: The cloned image will be displayed. +*/ + +#include +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +Mat img0, img1, img2, res, res1, final, final1, blend; + +Point point; +int drag = 0; +int destx, desty; + +int numpts = 100; +Point* pts = new Point[100]; +Point* pts2 = new Point[100]; +Point* pts_diff = new Point[100]; + +int var = 0; +int flag = 0, flag1 = 0, flag4 = 0; + +int minx, miny, maxx, maxy, lenx, leny; +int minxd, minyd, maxxd, maxyd, lenxd, lenyd; + +int channel, num, kernel_size; + +float alpha,beta; + +float red, green, blue; + +double low_t, high_t; + +void source(int, int, int, int, void*); +void destination(int, int, int, int, void*); +void checkfile(char*); + +void source(int event, int x, int y, int, void*) +{ + + if (event == EVENT_LBUTTONDOWN && !drag) + { + if(flag1 == 0) + { + if(var==0) + img1 = img0.clone(); + point = Point(x, y); + circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0); + pts[var] = point; + var++; + drag = 1; + if(var>1) + line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0); + + imshow("Source", img1); + } + } + + if (event == EVENT_LBUTTONUP && drag) + { + imshow("Source", img1); + + drag = 0; + } + if (event == EVENT_RBUTTONDOWN) + { + flag1 = 1; + img1 = img0.clone(); + for(int i = var; i < numpts ; i++) + pts[i] = point; + + if(var!=0) + { + const Point* pts3[1] = {&pts[0]}; + polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0); + } + + for(int i=0;i im1.size().width || maxyd > im1.size().height || minxd < 0 || minyd < 0) + { + cout << "Index out of range" << endl; + exit(0); + } + + final1 = Mat::zeros(img2.size(),CV_8UC3); + res = Mat::zeros(img2.size(),CV_8UC1); + for(int i=miny, k=minyd;i<(miny+leny);i++,k++) + for(int j=minx,l=minxd ;j<(minx+lenx);j++,l++) + { + for(int c=0;c(k,l*channel+c) = final.at(i,j*channel+c); + + } + } + + const Point* pts6[1] = {&pts2[0]}; + fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0); + + if(num == 1 || num == 2 || num == 3) + { + seamlessClone(img0,img2,res1,point,blend,num); + imshow("Cloned Image", blend); + imwrite("cloned.png",blend); + waitKey(0); + } + + for(int i = 0; i < flag ; i++) + { + pts2[i].x=0; + pts2[i].y=0; + } + + minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; + } + + im1.release(); +} + +int main() +{ + cout << endl; + cout << "Cloning Module" << endl; + cout << "---------------" << endl; + cout << "Step 1:" << endl; + cout << " -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button." << endl; + cout << " -> To set the Polygon ROI, click the right mouse button or use 'd' key" << endl; + cout << " -> To reset the region selected, click the middle mouse button or use 'r' key." << endl; + + cout << "Step 2:" << endl; + cout << " -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button." << endl; + cout << " -> To get the cloned result, click the right mouse button or use 'c' key." << endl; + cout << " -> To quit the program, use 'q' key." << endl; + cout << endl; + cout << "Options: " << endl; + cout << endl; + cout << "1) Normal Cloning " << endl; + cout << "2) Mixed Cloning " << endl; + cout << "3) Monochrome Transfer " << endl; + cout << "4) Local Color Change " << endl; + cout << "5) Local Illumination Change " << endl; + cout << "6) Texture Flattening " << endl; + + cout << endl; + + cout << "Press number 1-6 to choose from above techniques: "; + cin >> num; + cout << endl; + + minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN; + + minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; + + int flag3 = 0; + + if(num == 1 || num == 2 || num == 3) + { + + string src,dest; + cout << "Enter Source Image: "; + cin >> src; + + cout << "Enter Destination Image: "; + cin >> dest; + + img0 = imread(src); + + img2 = imread(dest); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + if(!img2.data) + { + cout << "Destination Image does not exist" << endl; + exit(0); + } + + channel = img0.channels(); + + res = Mat::zeros(img2.size(),CV_8UC1); + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + final1 = Mat::zeros(img2.size(),CV_8UC3); + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + + /////////// destination image /////////////// + + namedWindow("Destination", 1); + setMouseCallback("Destination", destination, NULL); + imshow("Destination",img2); + + } + else if(num == 4) + { + string src; + cout << "Enter Source Image: "; + cin >> src; + + cout << "Enter RGB values: " << endl; + cout << "Red: "; + cin >> red; + + cout << "Green: "; + cin >> green; + + cout << "Blue: "; + cin >> blue; + + img0 = imread(src); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + + } + else if(num == 5) + { + string src; + cout << "Enter Source Image: "; + cin >> src; + + cout << "alpha: "; + cin >> alpha; + + cout << "beta: "; + cin >> beta; + + img0 = imread(src); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + + } + else if(num == 6) + { + string src; + cout << "Enter Source Image: "; + cin >> src; + + cout << "low_threshold: "; + cin >> low_t; + + cout << "high_threshold: "; + cin >> high_t; + + cout << "kernel_size: "; + cin >> kernel_size; + + img0 = imread(src); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + } + else + { + cout << "Wrong Option Choosen" << endl; + exit(0); + } + + for(;;) + { + char key = (char) waitKey(0); + + if(key == 'd' && flag3 == 0) + { + flag1 = 1; + flag3 = 1; + img1 = img0.clone(); + for(int i = var; i < numpts ; i++) + pts[i] = point; + + if(var!=0) + { + const Point* pts3[1] = {&pts[0]}; + polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0); + } + + for(int i=0;i +* +* This tutorial demonstrates how to make mask image (black and white). +* The program takes as input a source image and ouputs its corresponding +* mask image. +*/ + +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +Mat img0, img1, res1, final; + +Point point; +int drag = 0; + +int numpts = 100; +Point* pts = new Point[100]; + +int var = 0; +int flag = 0; +int flag1 = 0; + +int minx,miny,maxx,maxy,lenx,leny; + +int channel; + +void mouseHandler(int, int, int, int, void*); + +void mouseHandler(int event, int x, int y, int, void*) +{ + + if (event == EVENT_LBUTTONDOWN && !drag) + { + if(flag1 == 0) + { + if(var==0) + img1 = img0.clone(); + point = Point(x, y); + circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0); + pts[var] = point; + var++; + drag = 1; + if(var>1) + line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0); + + imshow("Source", img1); + } + } + + if (event == EVENT_LBUTTONUP && drag) + { + imshow("Source", img1); + + drag = 0; + } + if (event == EVENT_RBUTTONDOWN) + { + flag1 = 1; + img1 = img0.clone(); + for(int i = var; i < numpts ; i++) + pts[i] = point; + + if(var!=0) + { + const Point* pts3[1] = {&pts[0]}; + polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0); + } + + for(int i=0;i" << endl; + exit(1); + } + + Mat src = imread(argv[1]); + + minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN; + + img0 = src; + + channel = img0.channels(); + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", mouseHandler, NULL); + imshow("Source", img0); + waitKey(0); + + img0.release(); + img1.release(); +} diff --git a/samples/cpp/npr_demo.cpp b/samples/cpp/npr_demo.cpp new file mode 100644 index 0000000000..5579ca269f --- /dev/null +++ b/samples/cpp/npr_demo.cpp @@ -0,0 +1,96 @@ +/* +* npr_demo.cpp +* +* Author: +* Siddharth Kherada +* +* This tutorial demonstrates how to use OpenCV Non-Photorealistic Rendering Module. +* 1) Edge Preserve Smoothing +* -> Using Normalized convolution Filter +* -> Using Recursive Filter +* 2) Detail Enhancement +* 3) Pencil sketch/Color Pencil Drawing +* 4) Stylization +* +*/ + +#include +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +int main(int argc, char* argv[]) +{ + if(argc < 2) + { + cout << "usage: " << argv[0] << " " << endl; + exit(0); + } + + int num,type; + + Mat I = imread(argv[1]); + + if(!I.data) + { + cout << "Image not found" << endl; + exit(0); + } + + cout << endl; + cout << " Edge Preserve Filter" << endl; + cout << "----------------------" << endl; + + cout << "Options: " << endl; + cout << endl; + + cout << "1) Edge Preserve Smoothing" << endl; + cout << " -> Using Normalized convolution Filter" << endl; + cout << " -> Using Recursive Filter" << endl; + cout << "2) Detail Enhancement" << endl; + cout << "3) Pencil sketch/Color Pencil Drawing" << endl; + cout << "4) Stylization" << endl; + cout << endl; + + cout << "Press number 1-4 to choose from above techniques: "; + + cin >> num; + + Mat img; + + if(num == 1) + { + cout << endl; + cout << "Press 1 for Normalized Convolution Filter and 2 for Recursive Filter: "; + + cin >> type; + + edgePreservingFilter(I,img,type); + imshow("Edge Preserve Smoothing",img); + + } + else if(num == 2) + { + detailEnhance(I,img); + imshow("Detail Enhanced",img); + } + else if(num == 3) + { + Mat img1; + pencilSketch(I,img1, img, 10 , 0.1f, 0.03f); + imshow("Pencil Sketch",img1); + imshow("Color Pencil Sketch",img); + } + else if(num == 4) + { + stylization(I,img); + imshow("Stylization",img); + } + waitKey(0); +} diff --git a/samples/cpp/points_classifier.cpp b/samples/cpp/points_classifier.cpp index ecf8ae8a30..26858da886 100644 --- a/samples/cpp/points_classifier.cpp +++ b/samples/cpp/points_classifier.cpp @@ -1,6 +1,12 @@ +#include "opencv2/opencv_modules.hpp" #include "opencv2/core/core.hpp" #include "opencv2/ml/ml.hpp" #include "opencv2/highgui/highgui.hpp" +#ifdef HAVE_OPENCV_OCL +#define _OCL_KNN_ 1 // select whether using ocl::KNN method or not, default is using +#define _OCL_SVM_ 1 // select whether using ocl::svm method or not, default is using +#include "opencv2/ocl/ocl.hpp" +#endif #include @@ -133,7 +139,14 @@ static void find_decision_boundary_KNN( int K ) prepare_train_data( trainSamples, trainClasses ); // learn classifier +#if defined HAVE_OPENCV_OCL && _OCL_KNN_ + cv::ocl::KNearestNeighbour knnClassifier; + Mat temp, result; + knnClassifier.train(trainSamples, trainClasses, temp, false, K); + cv::ocl::oclMat testSample_ocl, reslut_ocl; +#else CvKNearest knnClassifier( trainSamples, trainClasses, Mat(), false, K ); +#endif Mat testSample( 1, 2, CV_32FC1 ); for( int y = 0; y < img.rows; y += testStep ) @@ -142,9 +155,19 @@ static void find_decision_boundary_KNN( int K ) { testSample.at(0) = (float)x; testSample.at(1) = (float)y; +#if defined HAVE_OPENCV_OCL && _OCL_KNN_ + testSample_ocl.upload(testSample); + + knnClassifier.find_nearest(testSample_ocl, K, reslut_ocl); + + reslut_ocl.download(result); + int response = saturate_cast(result.at(0)); + circle(imgDst, Point(x, y), 1, classColors[response]); +#else int response = (int)knnClassifier.find_nearest( testSample, K ); circle( imgDst, Point(x,y), 1, classColors[response] ); +#endif } } } @@ -159,7 +182,11 @@ static void find_decision_boundary_SVM( CvSVMParams params ) prepare_train_data( trainSamples, trainClasses ); // learn classifier +#if defined HAVE_OPENCV_OCL && _OCL_SVM_ + cv::ocl::CvSVM_OCL svmClassifier(trainSamples, trainClasses, Mat(), Mat(), params); +#else CvSVM svmClassifier( trainSamples, trainClasses, Mat(), Mat(), params ); +#endif Mat testSample( 1, 2, CV_32FC1 ); for( int y = 0; y < img.rows; y += testStep ) @@ -178,7 +205,7 @@ static void find_decision_boundary_SVM( CvSVMParams params ) for( int i = 0; i < svmClassifier.get_support_vector_count(); i++ ) { const float* supportVector = svmClassifier.get_support_vector(i); - circle( imgDst, Point(supportVector[0],supportVector[1]), 5, Scalar(255,255,255), -1 ); + circle( imgDst, Point(saturate_cast(supportVector[0]),saturate_cast(supportVector[1])), 5, CV_RGB(255,255,255), -1 ); } } diff --git a/samples/ocl/facedetect.cpp b/samples/ocl/facedetect.cpp index 781efa066f..fd570b5154 100644 --- a/samples/ocl/facedetect.cpp +++ b/samples/ocl/facedetect.cpp @@ -8,11 +8,16 @@ #include #include +#if defined(_MSC_VER) && (_MSC_VER >= 1700) + # include +#endif using namespace std; using namespace cv; #define LOOP_NUM 1 +///////////////////////////single-threading faces detecting/////////////////////////////// + const static Scalar colors[] = { CV_RGB(0,0,255), CV_RGB(0,128,255), CV_RGB(0,255,255), @@ -26,7 +31,7 @@ const static Scalar colors[] = { CV_RGB(0,0,255), int64 work_begin = 0; int64 work_end = 0; -string outputName; +string inputName, outputName, cascadeName; static void workBegin() { @@ -61,41 +66,17 @@ static void Draw(Mat& img, vector& faces, double scale); // Else if will return (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels) double checkRectSimilarity(Size sz, vector& cpu_rst, vector& gpu_rst); -int main( int argc, const char** argv ) +static int facedetect_one_thread(bool useCPU, double scale ) { - const char* keys = - "{ h help | false | print help message }" - "{ i input | | specify input image }" - "{ t template | haarcascade_frontalface_alt.xml |" - " specify template file path }" - "{ c scale | 1.0 | scale image }" - "{ s use_cpu | false | use cpu or gpu to process the image }" - "{ o output | facedetect_output.jpg |" - " specify output image save path(only works when input is images) }"; - - CommandLineParser cmd(argc, argv, keys); - if (cmd.get("help")) - { - cout << "Usage : facedetect [options]" << endl; - cout << "Available options:" << endl; - cmd.printMessage(); - return EXIT_SUCCESS; - } - CvCapture* capture = 0; Mat frame, frameCopy0, frameCopy, image; - bool useCPU = cmd.get("s"); - string inputName = cmd.get("i"); - outputName = cmd.get("o"); - string cascadeName = cmd.get("t"); - double scale = cmd.get("c"); ocl::OclCascadeClassifier cascade; CascadeClassifier cpu_cascade; if( !cascade.load( cascadeName ) || !cpu_cascade.load(cascadeName) ) { - cout << "ERROR: Could not load classifier cascade" << endl; + cout << "ERROR: Could not load classifier cascade: " << cascadeName << endl; return EXIT_FAILURE; } @@ -186,9 +167,114 @@ int main( int argc, const char** argv ) } cvDestroyWindow("result"); + std::cout<< "single-threaded sample has finished" <= 1700) + +#define MAX_THREADS 10 + +static void detectFaces(std::string fileName) +{ + ocl::OclCascadeClassifier cascade; + if(!cascade.load(cascadeName)) + { + std::cout << "ERROR: Could not load classifier cascade: " << cascadeName << std::endl; + return; + } + + Mat img = imread(fileName, CV_LOAD_IMAGE_COLOR); + if (img.empty()) + { + std::cout << "cann't open file " + fileName < oclfaces; + cascade.detectMultiScale(d_img, oclfaces, 1.1, 3, 0 | CASCADE_SCALE_IMAGE, Size(30, 30), Size(0, 0)); + + for(unsigned int i = 0; i threads; + for(int i = 0; i= 1 }"; + + CommandLineParser cmd(argc, argv, keys); + if (cmd.has("help")) + { + cout << "Usage : facedetect [options]" << endl; + cout << "Available options:" << endl; + cmd.printMessage(); + return EXIT_SUCCESS; + } + bool useCPU = cmd.get("s"); + inputName = cmd.get("i"); + outputName = cmd.get("o"); + cascadeName = cmd.get("t"); + double scale = cmd.get("c"); + int n = cmd.get("n"); + + if(n > 1) + { +#if defined(_MSC_VER) && (_MSC_VER >= 1700) + std::cout<<"multi-threaded sample is running" <& faces, ocl::OclCascadeClassifier& cascade, double scale)