Merge remote-tracking branch 'upstream/3.4' into merge-3.4

This commit is contained in:
Alexander Alekhin 2020-03-17 13:23:33 +03:00
commit ca23c0e630
24 changed files with 565 additions and 145 deletions

View File

@ -14,6 +14,11 @@
#include <windows.h> #include <windows.h>
#endif #endif
// defined in core/private.hpp
namespace cv {
CV_EXPORTS const char* currentParallelFramework();
}
static void dumpHWFeatures(bool showAll = false) static void dumpHWFeatures(bool showAll = false)
{ {
std::cout << "OpenCV's HW features list:" << std::endl; std::cout << "OpenCV's HW features list:" << std::endl;
@ -34,6 +39,16 @@ static void dumpHWFeatures(bool showAll = false)
std::cout << "Total available: " << count << std::endl; std::cout << "Total available: " << count << std::endl;
} }
static void dumpParallelFramework()
{
const char* parallelFramework = cv::currentParallelFramework();
if (parallelFramework)
{
int threads = cv::getNumThreads();
std::cout << "Parallel framework: " << parallelFramework << " (nthreads=" << threads << ")" << std::endl;
}
}
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
CV_TRACE_FUNCTION(); CV_TRACE_FUNCTION();
@ -47,6 +62,7 @@ int main(int argc, const char** argv)
"{ verbose v | | show build configuration log }" "{ verbose v | | show build configuration log }"
"{ opencl | | show information about OpenCL (available platforms/devices, default selected device) }" "{ opencl | | show information about OpenCL (available platforms/devices, default selected device) }"
"{ hw | | show detected HW features (see cv::checkHardwareSupport() function). Use --hw=0 to show available features only }" "{ hw | | show detected HW features (see cv::checkHardwareSupport() function). Use --hw=0 to show available features only }"
"{ threads | | show configured parallel framework and number of active threads }"
); );
if (parser.has("help")) if (parser.has("help"))
@ -73,10 +89,17 @@ int main(int argc, const char** argv)
{ {
dumpHWFeatures(parser.get<bool>("hw")); dumpHWFeatures(parser.get<bool>("hw"));
} }
if (parser.has("threads"))
{
dumpParallelFramework();
}
#else #else
std::cout << cv::getBuildInformation().c_str() << std::endl; std::cout << cv::getBuildInformation().c_str() << std::endl;
cv::dumpOpenCLInformation(); cv::dumpOpenCLInformation();
dumpHWFeatures(); dumpHWFeatures();
dumpParallelFramework();
MessageBoxA(NULL, "Check console window output", "OpenCV(" CV_VERSION ")", MB_ICONINFORMATION | MB_OK); MessageBoxA(NULL, "Check console window output", "OpenCV(" CV_VERSION ")", MB_ICONINFORMATION | MB_OK);
#endif #endif

View File

@ -215,7 +215,13 @@ if(NOT HAVE_CXX11)
message(FATAL_ERROR "OpenCV 4.x requires C++11") message(FATAL_ERROR "OpenCV 4.x requires C++11")
endif() endif()
if((HAVE_CXX11 set(__OPENCV_ENABLE_ATOMIC_LONG_LONG OFF)
if(HAVE_CXX11 AND (X86 OR X86_64))
set(__OPENCV_ENABLE_ATOMIC_LONG_LONG ON)
endif()
option(OPENCV_ENABLE_ATOMIC_LONG_LONG "Enable C++ compiler support for atomic<long long>" ${__OPENCV_ENABLE_ATOMIC_LONG_LONG})
if((HAVE_CXX11 AND OPENCV_ENABLE_ATOMIC_LONG_LONG
AND NOT MSVC AND NOT MSVC
AND NOT (X86 OR X86_64) AND NOT (X86 OR X86_64)
AND NOT OPENCV_SKIP_LIBATOMIC_COMPILER_CHECK) AND NOT OPENCV_SKIP_LIBATOMIC_COMPILER_CHECK)
@ -226,9 +232,14 @@ if((HAVE_CXX11
list(APPEND CMAKE_REQUIRED_LIBRARIES atomic) list(APPEND CMAKE_REQUIRED_LIBRARIES atomic)
ocv_check_compiler_flag(CXX "" HAVE_CXX_ATOMICS_WITH_LIB "${OpenCV_SOURCE_DIR}/cmake/checks/atomic_check.cpp") ocv_check_compiler_flag(CXX "" HAVE_CXX_ATOMICS_WITH_LIB "${OpenCV_SOURCE_DIR}/cmake/checks/atomic_check.cpp")
if(HAVE_CXX_ATOMICS_WITH_LIB) if(HAVE_CXX_ATOMICS_WITH_LIB)
set(HAVE_ATOMIC_LONG_LONG ON)
list(APPEND OPENCV_LINKER_LIBS atomic) list(APPEND OPENCV_LINKER_LIBS atomic)
else() else()
message(FATAL_ERROR "C++11 compiler must support std::atomic") message(STATUS "Compiler doesn't support std::atomic<long long>")
endif() endif()
else()
set(HAVE_ATOMIC_LONG_LONG ON)
endif() endif()
else(HAVE_CXX11 AND OPENCV_ENABLE_ATOMIC_LONG_LONG)
set(HAVE_ATOMIC_LONG_LONG ${OPENCV_ENABLE_ATOMIC_LONG_LONG})
endif() endif()

View File

@ -1115,6 +1115,8 @@ macro(__ocv_parse_test_sources tests_type)
unset(__currentvar) unset(__currentvar)
endmacro() endmacro()
ocv_check_environment_variables(OPENCV_TEST_EXTRA_CXX_FLAGS_Release)
# this is a command for adding OpenCV performance tests to the module # this is a command for adding OpenCV performance tests to the module
# ocv_add_perf_tests(<extra_dependencies>) # ocv_add_perf_tests(<extra_dependencies>)
function(ocv_add_perf_tests) function(ocv_add_perf_tests)
@ -1279,6 +1281,10 @@ function(ocv_add_accuracy_tests)
_ocv_add_precompiled_headers(${the_target}) _ocv_add_precompiled_headers(${the_target})
endif() endif()
if(OPENCV_TEST_EXTRA_CXX_FLAGS_Release)
target_compile_options(${the_target} PRIVATE "$<$<CONFIG:Release>:${OPENCV_TEST_EXTRA_CXX_FLAGS_Release}>")
endif()
ocv_add_test_from_target("${the_target}" "Accuracy" "${the_target}") ocv_add_test_from_target("${the_target}" "Accuracy" "${the_target}")
else(OCV_DEPENDENCIES_FOUND) else(OCV_DEPENDENCIES_FOUND)
# TODO: warn about unsatisfied dependencies # TODO: warn about unsatisfied dependencies

View File

@ -2138,6 +2138,7 @@ point localization, image resolution, and the image noise.
@param confidence Parameter used for the RANSAC and LMedS methods only. It specifies a desirable level @param confidence Parameter used for the RANSAC and LMedS methods only. It specifies a desirable level
of confidence (probability) that the estimated matrix is correct. of confidence (probability) that the estimated matrix is correct.
@param mask @param mask
@param maxIters The maximum number of robust method iterations.
The epipolar geometry is described by the following equation: The epipolar geometry is described by the following equation:
@ -2171,6 +2172,11 @@ stereoRectifyUncalibrated to compute the rectification transformation. :
findFundamentalMat(points1, points2, FM_RANSAC, 3, 0.99); findFundamentalMat(points1, points2, FM_RANSAC, 3, 0.99);
@endcode @endcode
*/ */
CV_EXPORTS_W Mat findFundamentalMat( InputArray points1, InputArray points2,
int method, double ransacReprojThreshold, double confidence,
int maxIters, OutputArray mask = noArray() );
/** @overload */
CV_EXPORTS_W Mat findFundamentalMat( InputArray points1, InputArray points2, CV_EXPORTS_W Mat findFundamentalMat( InputArray points1, InputArray points2,
int method = FM_RANSAC, int method = FM_RANSAC,
double ransacReprojThreshold = 3., double confidence = 0.99, double ransacReprojThreshold = 3., double confidence = 0.99,

View File

@ -809,7 +809,7 @@ public:
cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2, cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2,
int method, double ransacReprojThreshold, double confidence, int method, double ransacReprojThreshold, double confidence,
OutputArray _mask ) int maxIters, OutputArray _mask )
{ {
CV_INSTRUMENT_REGION(); CV_INSTRUMENT_REGION();
@ -861,7 +861,7 @@ cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2,
confidence = 0.99; confidence = 0.99;
if( (method & ~3) == FM_RANSAC && npoints >= 15 ) if( (method & ~3) == FM_RANSAC && npoints >= 15 )
result = createRANSACPointSetRegistrator(cb, 7, ransacReprojThreshold, confidence)->run(m1, m2, F, _mask); result = createRANSACPointSetRegistrator(cb, 7, ransacReprojThreshold, confidence, maxIters)->run(m1, m2, F, _mask);
else else
result = createLMeDSPointSetRegistrator(cb, 7, confidence)->run(m1, m2, F, _mask); result = createLMeDSPointSetRegistrator(cb, 7, confidence)->run(m1, m2, F, _mask);
} }
@ -872,11 +872,17 @@ cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2,
return F; return F;
} }
cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2, cv::Mat cv::findFundamentalMat( cv::InputArray points1, cv::InputArray points2,
OutputArray _mask, int method, int method, double ransacReprojThreshold, double confidence,
double ransacReprojThreshold , double confidence) cv::OutputArray mask )
{ {
return cv::findFundamentalMat(_points1, _points2, method, ransacReprojThreshold, confidence, _mask); return cv::findFundamentalMat(points1, points2, method, ransacReprojThreshold, confidence, 1000, mask);
}
cv::Mat cv::findFundamentalMat( cv::InputArray points1, cv::InputArray points2, cv::OutputArray mask,
int method, double ransacReprojThreshold, double confidence )
{
return cv::findFundamentalMat(points1, points2, method, ransacReprojThreshold, confidence, 1000, mask);
} }

View File

@ -81,6 +81,23 @@ if(HAVE_MEMALIGN)
ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/alloc.cpp "HAVE_MEMALIGN=1") ocv_append_source_file_compile_definitions(${CMAKE_CURRENT_SOURCE_DIR}/src/alloc.cpp "HAVE_MEMALIGN=1")
endif() endif()
option(OPENCV_ENABLE_ALLOCATOR_STATS "Enable Allocator metrics" ON)
if(NOT OPENCV_ENABLE_ALLOCATOR_STATS)
add_definitions(-DOPENCV_DISABLE_ALLOCATOR_STATS=1)
else()
if(NOT DEFINED OPENCV_ALLOCATOR_STATS_COUNTER_TYPE)
if(HAVE_ATOMIC_LONG_LONG AND OPENCV_ENABLE_ATOMIC_LONG_LONG)
set(OPENCV_ALLOCATOR_STATS_COUNTER_TYPE "long long")
else()
set(OPENCV_ALLOCATOR_STATS_COUNTER_TYPE "int")
endif()
endif()
message(STATUS "Allocator metrics storage type: '${OPENCV_ALLOCATOR_STATS_COUNTER_TYPE}'")
add_definitions("-DOPENCV_ALLOCATOR_STATS_COUNTER_TYPE=${OPENCV_ALLOCATOR_STATS_COUNTER_TYPE}")
endif()
ocv_create_module(${extra_libs}) ocv_create_module(${extra_libs})
ocv_target_link_libraries(${the_module} PRIVATE ocv_target_link_libraries(${the_module} PRIVATE

View File

@ -1564,81 +1564,10 @@ OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_uint32x4, vec_uint4)
OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_int32x4, vec_int4) OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_int32x4, vec_int4)
OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_float32x4, vec_float4) OPENCV_HAL_IMPL_VSX_TRANSPOSE4x4(v_float32x4, vec_float4)
template<int i> template<int i, typename Tvec>
inline v_int8x16 v_broadcast_element(v_int8x16 v) inline Tvec v_broadcast_element(const Tvec& v)
{ { return Tvec(vec_splat(v.val, i)); }
return v_int8x16(vec_perm(v.val, v.val, vec_splats((unsigned char)i)));
}
template<int i>
inline v_uint8x16 v_broadcast_element(v_uint8x16 v)
{
return v_uint8x16(vec_perm(v.val, v.val, vec_splats((unsigned char)i)));
}
template<int i>
inline v_int16x8 v_broadcast_element(v_int16x8 v)
{
unsigned char t0 = 2*i, t1 = 2*i + 1;
vec_uchar16 p = {t0, t1, t0, t1, t0, t1, t0, t1, t0, t1, t0, t1, t0, t1, t0, t1};
return v_int16x8(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_uint16x8 v_broadcast_element(v_uint16x8 v)
{
unsigned char t0 = 2*i, t1 = 2*i + 1;
vec_uchar16 p = {t0, t1, t0, t1, t0, t1, t0, t1, t0, t1, t0, t1, t0, t1, t0, t1};
return v_uint16x8(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_int32x4 v_broadcast_element(v_int32x4 v)
{
unsigned char t0 = 4*i, t1 = 4*i + 1, t2 = 4*i + 2, t3 = 4*i + 3;
vec_uchar16 p = {t0, t1, t2, t3, t0, t1, t2, t3, t0, t1, t2, t3, t0, t1, t2, t3};
return v_int32x4(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_uint32x4 v_broadcast_element(v_uint32x4 v)
{
unsigned char t0 = 4*i, t1 = 4*i + 1, t2 = 4*i + 2, t3 = 4*i + 3;
vec_uchar16 p = {t0, t1, t2, t3, t0, t1, t2, t3, t0, t1, t2, t3, t0, t1, t2, t3};
return v_uint32x4(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_int64x2 v_broadcast_element(v_int64x2 v)
{
unsigned char t0 = 8*i, t1 = 8*i + 1, t2 = 8*i + 2, t3 = 8*i + 3, t4 = 8*i + 4, t5 = 8*i + 5, t6 = 8*i + 6, t7 = 8*i + 7;
vec_uchar16 p = {t0, t1, t2, t3, t4, t5, t6, t7, t0, t1, t2, t3, t4, t5, t6, t7};
return v_int64x2(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_uint64x2 v_broadcast_element(v_uint64x2 v)
{
unsigned char t0 = 8*i, t1 = 8*i + 1, t2 = 8*i + 2, t3 = 8*i + 3, t4 = 8*i + 4, t5 = 8*i + 5, t6 = 8*i + 6, t7 = 8*i + 7;
vec_uchar16 p = {t0, t1, t2, t3, t4, t5, t6, t7, t0, t1, t2, t3, t4, t5, t6, t7};
return v_uint64x2(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_float32x4 v_broadcast_element(v_float32x4 v)
{
unsigned char t0 = 4*i, t1 = 4*i + 1, t2 = 4*i + 2, t3 = 4*i + 3;
vec_uchar16 p = {t0, t1, t2, t3, t0, t1, t2, t3, t0, t1, t2, t3, t0, t1, t2, t3};
return v_float32x4(vec_perm(v.val, v.val, p));
}
template<int i>
inline v_float64x2 v_broadcast_element(v_float64x2 v)
{
unsigned char t0 = 8*i, t1 = 8*i + 1, t2 = 8*i + 2, t3 = 8*i + 3, t4 = 8*i + 4, t5 = 8*i + 5, t6 = 8*i + 6, t7 = 8*i + 7;
vec_uchar16 p = {t0, t1, t2, t3, t4, t5, t6, t7, t0, t1, t2, t3, t4, t5, t6, t7};
return v_float64x2(vec_perm(v.val, v.val, p));
}
CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END CV_CPU_OPTIMIZATION_HAL_NAMESPACE_END

View File

@ -11,32 +11,55 @@
#include <atomic> #include <atomic>
#endif #endif
//#define OPENCV_DISABLE_ALLOCATOR_STATS
namespace cv { namespace utils { namespace cv { namespace utils {
#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE
#if defined(__GNUC__) && (\
(defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 4) || \
(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) \
)
#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE int
#endif
#endif
#ifndef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE
#define OPENCV_ALLOCATOR_STATS_COUNTER_TYPE long long
#endif
#ifdef CV__ALLOCATOR_STATS_LOG #ifdef CV__ALLOCATOR_STATS_LOG
namespace { namespace {
#endif #endif
class AllocatorStatistics : public AllocatorStatisticsInterface class AllocatorStatistics : public AllocatorStatisticsInterface
{ {
protected: #ifdef OPENCV_DISABLE_ALLOCATOR_STATS
#ifdef CV_CXX11
std::atomic<long long> curr, total, total_allocs, peak;
#else
volatile long long curr, total, total_allocs, peak; // overflow is possible, CV_XADD operates with 'int' only
#endif
public: public:
AllocatorStatistics() AllocatorStatistics() {}
#ifndef CV_CXX11
: curr(0), total(0), total_allocs(0), peak(0)
#endif
{}
~AllocatorStatistics() CV_OVERRIDE {} ~AllocatorStatistics() CV_OVERRIDE {}
// AllocatorStatisticsInterface uint64_t getCurrentUsage() const CV_OVERRIDE { return 0; }
uint64_t getTotalUsage() const CV_OVERRIDE { return 0; }
uint64_t getNumberOfAllocations() const CV_OVERRIDE { return 0; }
uint64_t getPeakUsage() const CV_OVERRIDE { return 0; }
/** set peak usage = current usage */
void resetPeakUsage() CV_OVERRIDE {};
void onAllocate(size_t /*sz*/) {}
void onFree(size_t /*sz*/) {}
#elif defined(CV_CXX11)
protected:
typedef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE counter_t;
std::atomic<counter_t> curr, total, total_allocs, peak;
public:
AllocatorStatistics() {}
~AllocatorStatistics() CV_OVERRIDE {}
#ifdef CV_CXX11
uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr.load(); } uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr.load(); }
uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total.load(); } uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total.load(); }
uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs.load(); } uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs.load(); }
@ -52,7 +75,7 @@ public:
CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load())); CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load()));
#endif #endif
long long new_curr = curr.fetch_add((long long)sz) + (long long)sz; counter_t new_curr = curr.fetch_add((counter_t)sz) + (counter_t)sz;
// peak = std::max((uint64_t)peak, new_curr); // peak = std::max((uint64_t)peak, new_curr);
auto prev_peak = peak.load(); auto prev_peak = peak.load();
@ -63,7 +86,7 @@ public:
} }
// end of peak = max(...) // end of peak = max(...)
total += (long long)sz; total += (counter_t)sz;
total_allocs++; total_allocs++;
} }
void onFree(size_t sz) void onFree(size_t sz)
@ -71,10 +94,20 @@ public:
#ifdef CV__ALLOCATOR_STATS_LOG #ifdef CV__ALLOCATOR_STATS_LOG
CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load())); CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr.load()));
#endif #endif
curr -= (long long)sz; curr -= (counter_t)sz;
} }
#else #else // non C++11
protected:
typedef OPENCV_ALLOCATOR_STATS_COUNTER_TYPE counter_t;
volatile counter_t curr, total, total_allocs, peak; // overflow is possible, CV_XADD operates with 'int' only
public:
AllocatorStatistics()
: curr(0), total(0), total_allocs(0), peak(0)
{}
~AllocatorStatistics() CV_OVERRIDE {}
uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr; } uint64_t getCurrentUsage() const CV_OVERRIDE { return (uint64_t)curr; }
uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total; } uint64_t getTotalUsage() const CV_OVERRIDE { return (uint64_t)total; }
uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs; } uint64_t getNumberOfAllocations() const CV_OVERRIDE { return (uint64_t)total_allocs; }
@ -89,21 +122,21 @@ public:
CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr)); CV__ALLOCATOR_STATS_LOG(cv::format("allocate: %lld (curr=%lld)", (long long int)sz, (long long int)curr));
#endif #endif
uint64_t new_curr = (uint64_t)CV_XADD(&curr, (uint64_t)sz) + sz; counter_t new_curr = (counter_t)CV_XADD(&curr, (counter_t)sz) + (counter_t)sz;
peak = std::max((uint64_t)peak, new_curr); // non-thread safe peak = std::max((counter_t)peak, new_curr); // non-thread safe
//CV_XADD(&total, (uint64_t)sz); // overflow with int, non-reliable... //CV_XADD(&total, (uint64_t)sz); // overflow with int, non-reliable...
total += sz; total += sz;
CV_XADD(&total_allocs, (uint64_t)1); CV_XADD(&total_allocs, (counter_t)1);
} }
void onFree(size_t sz) void onFree(size_t sz)
{ {
#ifdef CV__ALLOCATOR_STATS_LOG #ifdef CV__ALLOCATOR_STATS_LOG
CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr)); CV__ALLOCATOR_STATS_LOG(cv::format("free: %lld (curr=%lld)", (long long int)sz, (long long int)curr));
#endif #endif
CV_XADD(&curr, (uint64_t)-sz); CV_XADD(&curr, (counter_t)-sz);
} }
#endif #endif
}; };

View File

@ -72,6 +72,10 @@ public:
CV_Assert(alignment % sizeof(T) == 0); CV_Assert(alignment % sizeof(T) == 0);
CV_Assert((alignment & (alignment - 1)) == 0); CV_Assert((alignment & (alignment - 1)) == 0);
allocate_((void**)(&ptr), static_cast<ushort>(sizeof(T)), count, alignment); allocate_((void**)(&ptr), static_cast<ushort>(sizeof(T)), count, alignment);
#ifndef OPENCV_ENABLE_MEMORY_SANITIZER
if (safe)
#endif
CV_Assert(ptr != NULL);
} }
/** @brief Fill one of buffers with zeroes /** @brief Fill one of buffers with zeroes
@ -118,9 +122,11 @@ private:
private: private:
class Block; class Block;
std::vector<Block> blocks; std::vector<Block> blocks;
#ifndef OPENCV_ENABLE_MEMORY_SANITIZER
void * oneBuf; void * oneBuf;
size_t totalSize; size_t totalSize;
const bool safe; const bool safe;
#endif
}; };
//! @} //! @}

View File

@ -5,14 +5,10 @@
#include "opencv2/core/utils/buffer_area.private.hpp" #include "opencv2/core/utils/buffer_area.private.hpp"
#include "opencv2/core/utils/configuration.private.hpp" #include "opencv2/core/utils/configuration.private.hpp"
#ifdef OPENCV_ENABLE_MEMORY_SANITIZER #ifndef OPENCV_ENABLE_MEMORY_SANITIZER
#define BUFFER_AREA_DEFAULT_MODE true
#else
#define BUFFER_AREA_DEFAULT_MODE false
#endif
static bool CV_BUFFER_AREA_OVERRIDE_SAFE_MODE = static bool CV_BUFFER_AREA_OVERRIDE_SAFE_MODE =
cv::utils::getConfigurationParameterBool("OPENCV_BUFFER_AREA_ALWAYS_SAFE", BUFFER_AREA_DEFAULT_MODE); cv::utils::getConfigurationParameterBool("OPENCV_BUFFER_AREA_ALWAYS_SAFE", false);
#endif
namespace cv { namespace utils { namespace cv { namespace utils {
@ -58,6 +54,7 @@ public:
*ptr = raw_mem; *ptr = raw_mem;
} }
} }
#ifndef OPENCV_ENABLE_MEMORY_SANITIZER
void * fast_allocate(void * buf) const void * fast_allocate(void * buf) const
{ {
CV_Assert(ptr && *ptr == NULL); CV_Assert(ptr && *ptr == NULL);
@ -66,6 +63,7 @@ public:
*ptr = buf; *ptr = buf;
return static_cast<void*>(static_cast<uchar*>(*ptr) + type_size * count); return static_cast<void*>(static_cast<uchar*>(*ptr) + type_size * count);
} }
#endif
bool operator==(void **other) const bool operator==(void **other) const
{ {
CV_Assert(ptr && other); CV_Assert(ptr && other);
@ -86,12 +84,20 @@ private:
//================================================================================================== //==================================================================================================
#ifndef OPENCV_ENABLE_MEMORY_SANITIZER
BufferArea::BufferArea(bool safe_) : BufferArea::BufferArea(bool safe_) :
oneBuf(0), oneBuf(0),
totalSize(0), totalSize(0),
safe(safe_ || CV_BUFFER_AREA_OVERRIDE_SAFE_MODE) safe(safe_ || CV_BUFFER_AREA_OVERRIDE_SAFE_MODE)
{ {
// nothing
} }
#else
BufferArea::BufferArea(bool safe_)
{
CV_UNUSED(safe_);
}
#endif
BufferArea::~BufferArea() BufferArea::~BufferArea()
{ {
@ -101,10 +107,16 @@ BufferArea::~BufferArea()
void BufferArea::allocate_(void **ptr, ushort type_size, size_t count, ushort alignment) void BufferArea::allocate_(void **ptr, ushort type_size, size_t count, ushort alignment)
{ {
blocks.push_back(Block(ptr, type_size, count, alignment)); blocks.push_back(Block(ptr, type_size, count, alignment));
if (safe) #ifndef OPENCV_ENABLE_MEMORY_SANITIZER
blocks.back().real_allocate(); if (!safe)
else {
totalSize += blocks.back().getByteCount(); totalSize += blocks.back().getByteCount();
}
else
#endif
{
blocks.back().real_allocate();
}
} }
void BufferArea::zeroFill_(void **ptr) void BufferArea::zeroFill_(void **ptr)
@ -129,6 +141,7 @@ void BufferArea::zeroFill()
void BufferArea::commit() void BufferArea::commit()
{ {
#ifndef OPENCV_ENABLE_MEMORY_SANITIZER
if (!safe) if (!safe)
{ {
CV_Assert(totalSize > 0); CV_Assert(totalSize > 0);
@ -141,6 +154,7 @@ void BufferArea::commit()
ptr = i->fast_allocate(ptr); ptr = i->fast_allocate(ptr);
} }
} }
#endif
} }
void BufferArea::release() void BufferArea::release()
@ -150,11 +164,13 @@ void BufferArea::release()
i->cleanup(); i->cleanup();
} }
blocks.clear(); blocks.clear();
#ifndef OPENCV_ENABLE_MEMORY_SANITIZER
if (oneBuf) if (oneBuf)
{ {
fastFree(oneBuf); fastFree(oneBuf);
oneBuf = 0; oneBuf = 0;
} }
#endif
} }
//================================================================================================== //==================================================================================================

View File

@ -638,9 +638,9 @@ int getNumThreads(void)
#elif defined HAVE_CONCURRENCY #elif defined HAVE_CONCURRENCY
return 1 + (pplScheduler == 0 return (pplScheduler == 0)
? Concurrency::CurrentScheduler::Get()->GetNumberOfVirtualProcessors() ? Concurrency::CurrentScheduler::Get()->GetNumberOfVirtualProcessors()
: pplScheduler->GetNumberOfVirtualProcessors()); : (1 + pplScheduler->GetNumberOfVirtualProcessors());
#elif defined HAVE_PTHREADS_PF #elif defined HAVE_PTHREADS_PF

View File

@ -160,12 +160,13 @@ public:
PyObject* args = pyopencv_from(inputs); PyObject* args = pyopencv_from(inputs);
PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("forward"), args, NULL); PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("forward"), args, NULL);
Py_DECREF(args); Py_DECREF(args);
PyGILState_Release(gstate);
if (!res) if (!res)
CV_Error(Error::StsNotImplemented, "Failed to call \"forward\" method"); CV_Error(Error::StsNotImplemented, "Failed to call \"forward\" method");
std::vector<Mat> pyOutputs; std::vector<Mat> pyOutputs;
CV_Assert(pyopencv_to(res, pyOutputs, ArgInfo("", 0))); CV_Assert(pyopencv_to(res, pyOutputs, ArgInfo("", 0)));
Py_DECREF(res);
PyGILState_Release(gstate);
CV_Assert(pyOutputs.size() == outputs.size()); CV_Assert(pyOutputs.size() == outputs.size());
for (size_t i = 0; i < outputs.size(); ++i) for (size_t i = 0; i < outputs.size(); ++i)

View File

@ -114,7 +114,7 @@ public:
{ {
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R3) #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R3)
// Lightweight detection // Lightweight detection
const std::vector<std::string> devices = getCore().GetAvailableDevices(); const std::vector<std::string> devices = getCore("").GetAvailableDevices();
for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i) for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i)
{ {
if (std::string::npos != i->find("MYRIAD") && target == DNN_TARGET_MYRIAD) if (std::string::npos != i->find("MYRIAD") && target == DNN_TARGET_MYRIAD)
@ -3557,7 +3557,7 @@ Net Net::readFromModelOptimizer(const String& xml, const String& bin)
InferenceEngine::CNNNetwork ieNet = reader.getNetwork(); InferenceEngine::CNNNetwork ieNet = reader.getNetwork();
#else #else
InferenceEngine::Core& ie = getCore(); InferenceEngine::Core& ie = getCore("");
InferenceEngine::CNNNetwork ieNet = ie.ReadNetwork(xml, bin); InferenceEngine::CNNNetwork ieNet = ie.ReadNetwork(xml, bin);
#endif #endif
@ -3606,7 +3606,7 @@ Net Net::readFromModelOptimizer(
InferenceEngine::CNNNetwork ieNet = reader.getNetwork(); InferenceEngine::CNNNetwork ieNet = reader.getNetwork();
#else #else
InferenceEngine::Core& ie = getCore(); InferenceEngine::Core& ie = getCore("");
std::string model; model.assign((char*)bufferModelConfigPtr, bufferModelConfigSize); std::string model; model.assign((char*)bufferModelConfigPtr, bufferModelConfigSize);

View File

@ -524,7 +524,7 @@ void InfEngineNgraphNet::initPlugin(InferenceEngine::CNNNetwork& net)
try try
{ {
AutoLock lock(getInitializationMutex()); AutoLock lock(getInitializationMutex());
InferenceEngine::Core& ie = getCore(); InferenceEngine::Core& ie = getCore(device_name);
{ {
isInit = true; isInit = true;
std::vector<std::string> candidates; std::vector<std::string> candidates;

View File

@ -431,9 +431,20 @@ void ONNXImporter::populateNet(Net dstNet)
{ {
bool isSub = layer_type == "Sub"; bool isSub = layer_type == "Sub";
CV_CheckEQ(node_proto.input_size(), 2, ""); CV_CheckEQ(node_proto.input_size(), 2, "");
if (layer_id.find(node_proto.input(1)) == layer_id.end()) bool is_const_0 = layer_id.find(node_proto.input(0)) == layer_id.end();
bool is_const_1 = layer_id.find(node_proto.input(1)) == layer_id.end();
if (is_const_0 && is_const_1)
{ {
Mat blob = getBlob(node_proto, constBlobs, 1); Mat blob_0 = getBlob(node_proto, constBlobs, 0);
Mat blob_1 = getBlob(node_proto, constBlobs, 1);
CV_Assert(blob_0.size == blob_1.size);
Mat output = isSub ? (blob_0 - blob_1) : (blob_0 + blob_1);
constBlobs.insert(std::make_pair(layerParams.name, output));
continue;
}
else if (is_const_0 || is_const_1)
{
Mat blob = getBlob(node_proto, constBlobs, is_const_0 ? 0 : 1);
blob = blob.reshape(1, 1); blob = blob.reshape(1, 1);
if (blob.total() == 1) { if (blob.total() == 1) {
layerParams.type = "Power"; layerParams.type = "Power";
@ -808,6 +819,21 @@ void ONNXImporter::populateNet(Net dstNet)
layerParams.set("end_axis", axis); layerParams.set("end_axis", axis);
layerParams.type = "Flatten"; layerParams.type = "Flatten";
} }
else if (layer_type == "Flatten")
{
CV_CheckEQ(node_proto.input_size(), 1, "");
if (constBlobs.find(node_proto.input(0)) != constBlobs.end())
{
Mat input = getBlob(node_proto, constBlobs, 0);
int axis = clamp(layerParams.get<int>("axis", 1), input.dims);
std::vector<int> out_size(&input.size[0], &input.size[0] + axis);
out_size.push_back(input.total(axis));
Mat output = input.reshape(1, out_size);
constBlobs.insert(std::make_pair(layerParams.name, output));
continue;
}
}
else if (layer_type == "Unsqueeze") else if (layer_type == "Unsqueeze")
{ {
CV_Assert(node_proto.input_size() == 1); CV_Assert(node_proto.input_size() == 1);
@ -896,6 +922,31 @@ void ONNXImporter::populateNet(Net dstNet)
constBlobs.insert(std::make_pair(layerParams.name, shapeMat)); constBlobs.insert(std::make_pair(layerParams.name, shapeMat));
continue; continue;
} }
else if (layer_type == "Cast")
{
if (constBlobs.find(node_proto.input(0)) != constBlobs.end())
{
Mat blob = getBlob(node_proto, constBlobs, 0);
int type;
switch (layerParams.get<int>("to"))
{
case opencv_onnx::TensorProto_DataType_FLOAT: type = CV_32F; break;
case opencv_onnx::TensorProto_DataType_UINT8: type = CV_8U; break;
case opencv_onnx::TensorProto_DataType_UINT16: type = CV_16U; break;
case opencv_onnx::TensorProto_DataType_FLOAT16: type = CV_16S; break;
case opencv_onnx::TensorProto_DataType_INT8:
case opencv_onnx::TensorProto_DataType_INT16:
case opencv_onnx::TensorProto_DataType_INT32:
case opencv_onnx::TensorProto_DataType_INT64: type = CV_32S; break;
default: type = blob.type();
}
blob.convertTo(blob, type);
constBlobs.insert(std::make_pair(layerParams.name, blob));
continue;
}
else
layerParams.type = "Identity";
}
else if (layer_type == "Gather") else if (layer_type == "Gather")
{ {
CV_Assert(node_proto.input_size() == 2); CV_Assert(node_proto.input_size() == 2);

View File

@ -604,18 +604,31 @@ static bool init_IE_plugins()
(void)init_core->GetAvailableDevices(); (void)init_core->GetAvailableDevices();
return true; return true;
} }
static InferenceEngine::Core& create_IE_Core_instance() static InferenceEngine::Core& retrieveIECore(const std::string& id, std::map<std::string, std::shared_ptr<InferenceEngine::Core> >& cores)
{ {
static InferenceEngine::Core core; AutoLock lock(getInitializationMutex());
return core; std::map<std::string, std::shared_ptr<InferenceEngine::Core> >::iterator i = cores.find(id);
if (i == cores.end())
{
std::shared_ptr<InferenceEngine::Core> core = std::make_shared<InferenceEngine::Core>();
cores[id] = core;
return *core.get();
}
return *(i->second).get();
} }
static InferenceEngine::Core& create_IE_Core_pointer() static InferenceEngine::Core& create_IE_Core_instance(const std::string& id)
{
static std::map<std::string, std::shared_ptr<InferenceEngine::Core> > cores;
return retrieveIECore(id, cores);
}
static InferenceEngine::Core& create_IE_Core_pointer(const std::string& id)
{ {
// load and hold IE plugins // load and hold IE plugins
static InferenceEngine::Core* core = new InferenceEngine::Core(); // 'delete' is never called static std::map<std::string, std::shared_ptr<InferenceEngine::Core> >* cores =
return *core; new std::map<std::string, std::shared_ptr<InferenceEngine::Core> >();
return retrieveIECore(id, *cores);
} }
InferenceEngine::Core& getCore() InferenceEngine::Core& getCore(const std::string& id)
{ {
// to make happy memory leak tools use: // to make happy memory leak tools use:
// - OPENCV_DNN_INFERENCE_ENGINE_HOLD_PLUGINS=0 // - OPENCV_DNN_INFERENCE_ENGINE_HOLD_PLUGINS=0
@ -631,9 +644,10 @@ InferenceEngine::Core& getCore()
false false
#endif #endif
); );
static InferenceEngine::Core& core = param_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND
? create_IE_Core_pointer() InferenceEngine::Core& core = param_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND
: create_IE_Core_instance(); ? create_IE_Core_pointer(id)
: create_IE_Core_instance(id);
return core; return core;
} }
#endif #endif
@ -641,9 +655,10 @@ InferenceEngine::Core& getCore()
#if !defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT) #if !defined(OPENCV_DNN_IE_VPU_TYPE_DEFAULT)
static bool detectMyriadX_() static bool detectMyriadX_()
{ {
AutoLock lock(getInitializationMutex());
#if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R3) #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R3)
// Lightweight detection // Lightweight detection
InferenceEngine::Core& ie = getCore(); InferenceEngine::Core& ie = getCore("MYRIAD");
const std::vector<std::string> devices = ie.GetAvailableDevices(); const std::vector<std::string> devices = ie.GetAvailableDevices();
for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i) for (std::vector<std::string>::const_iterator i = devices.begin(); i != devices.end(); ++i)
{ {
@ -687,7 +702,6 @@ static bool detectMyriadX_()
#if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R1) #if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R1)
InferenceEngine::InferenceEnginePluginPtr enginePtr; InferenceEngine::InferenceEnginePluginPtr enginePtr;
{ {
AutoLock lock(getInitializationMutex());
auto& sharedPlugins = getSharedPlugins(); auto& sharedPlugins = getSharedPlugins();
auto pluginIt = sharedPlugins.find("MYRIAD"); auto pluginIt = sharedPlugins.find("MYRIAD");
if (pluginIt != sharedPlugins.end()) { if (pluginIt != sharedPlugins.end()) {
@ -706,9 +720,9 @@ static bool detectMyriadX_()
try try
{ {
#if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R3) #if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R3)
auto netExec = getCore().LoadNetwork(cnn, "MYRIAD", {{"VPU_PLATFORM", "VPU_2480"}}); auto netExec = getCore("MYRIAD").LoadNetwork(cnn, "MYRIAD", {{"VPU_PLATFORM", "VPU_2480"}});
#else #else
auto netExec = getCore().LoadNetwork(cnn, "MYRIAD", {{"VPU_MYRIAD_PLATFORM", "VPU_MYRIAD_2480"}}); auto netExec = getCore("MYRIAD").LoadNetwork(cnn, "MYRIAD", {{"VPU_MYRIAD_PLATFORM", "VPU_MYRIAD_2480"}});
#endif #endif
#endif #endif
auto infRequest = netExec.CreateInferRequest(); auto infRequest = netExec.CreateInferRequest();
@ -739,7 +753,7 @@ void InfEngineBackendNet::initPlugin(InferenceEngine::CNNNetwork& net)
} }
else else
#else #else
InferenceEngine::Core& ie = getCore(); InferenceEngine::Core& ie = getCore(device_name);
#endif #endif
{ {
#if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R1) #if INF_ENGINE_VER_MAJOR_LE(INF_ENGINE_RELEASE_2019R1)
@ -1124,7 +1138,7 @@ void resetMyriadDevice()
getSharedPlugins().erase("MYRIAD"); getSharedPlugins().erase("MYRIAD");
#else #else
// Unregister both "MYRIAD" and "HETERO:MYRIAD,CPU" plugins // Unregister both "MYRIAD" and "HETERO:MYRIAD,CPU" plugins
InferenceEngine::Core& ie = getCore(); InferenceEngine::Core& ie = getCore("MYRIAD");
try try
{ {
ie.UnregisterPlugin("MYRIAD"); ie.UnregisterPlugin("MYRIAD");

View File

@ -246,7 +246,7 @@ bool isMyriadX();
CV__DNN_INLINE_NS_END CV__DNN_INLINE_NS_END
InferenceEngine::Core& getCore(); InferenceEngine::Core& getCore(const std::string& id);
template<typename T = size_t> template<typename T = size_t>
static inline std::vector<T> getShape(const Mat& mat) static inline std::vector<T> getShape(const Mat& mat)

View File

@ -458,6 +458,7 @@ private:
tensorflow::GraphDef netTxt; tensorflow::GraphDef netTxt;
std::vector<String> netInputsNames; std::vector<String> netInputsNames;
std::vector<MatShape> netInputShapes;
}; };
TFImporter::TFImporter(const char *model, const char *config) TFImporter::TFImporter(const char *model, const char *config)
@ -1401,6 +1402,27 @@ void TFImporter::populateNet(Net dstNet)
netInputsNames.push_back(name); netInputsNames.push_back(name);
layer_id[name] = 0; layer_id[name] = 0;
} }
if (hasLayerAttr(layer, "shape"))
{
const tensorflow::TensorShapeProto& shape = getLayerAttr(layer, "shape").shape();
MatShape dims(shape.dim_size());
for (int i = 0; i < dims.size(); ++i)
dims[i] = shape.dim(i).size();
if (dims.size() == 4 && predictedLayout == DATA_LAYOUT_NHWC)
{
std::swap(dims[1], dims[3]); // NHWC->NCWH
std::swap(dims[2], dims[3]); // NCWH->NCHW
if (dims[0] == -1) // It's OK to have undetermined batch size
dims[0] = 1;
}
bool hasNeg = false;
for (int i = 0; i < dims.size() && !hasNeg; ++i)
{
hasNeg = dims[i] < 0;
}
if (!hasNeg)
netInputShapes.push_back(dims);
}
} }
else if (type == "Split") { else if (type == "Split") {
// TODO: determining axis index remapping by input dimensions order of input blob // TODO: determining axis index remapping by input dimensions order of input blob
@ -1580,8 +1602,41 @@ void TFImporter::populateNet(Net dstNet)
} }
else else
{ {
layerParams.set("operation", "prod"); // Check if all the inputs have the same shape.
int id = dstNet.addLayer(name, "Eltwise", layerParams); bool equalInpShapes = true;
MatShape outShape0;
for (int ii = 0; ii < layer.input_size() && !netInputShapes.empty(); ii++)
{
Pin pin = parsePin(layer.input(ii));
int inpId = layer_id.find(pin.name)->second;
// Get input shape
MatShape outShape;
std::vector<MatShape> inpShapes, outShapes;
dstNet.getLayerShapes(netInputShapes, inpId, inpShapes, outShapes);
CV_CheckGT(static_cast<int>(outShapes.size()), pin.blobIndex, "");
outShape = outShapes[pin.blobIndex];
if (ii == 0)
{
outShape0 = outShape;
}
else if (outShape != outShape0)
{
equalInpShapes = false;
break;
}
}
int id;
if (equalInpShapes || netInputShapes.empty())
{
layerParams.set("operation", "prod");
id = dstNet.addLayer(name, "Eltwise", layerParams);
}
else
id = dstNet.addLayer(name, "Scale", layerParams);
layer_id[name] = id; layer_id[name] = id;
for (int ii = 0; ii < layer.input_size(); ii++) for (int ii = 0; ii < layer.input_size(); ii++)

View File

@ -199,6 +199,11 @@ TEST_P(Test_ONNX_layers, MaxPooling_Sigmoid)
testONNXModels("maxpooling_sigmoid"); testONNXModels("maxpooling_sigmoid");
} }
TEST_P(Test_ONNX_layers, Cast)
{
testONNXModels("cast");
}
TEST_P(Test_ONNX_layers, Concatenation) TEST_P(Test_ONNX_layers, Concatenation)
{ {
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
@ -402,6 +407,7 @@ TEST_P(Test_ONNX_layers, DynamicReshape)
testONNXModels("dynamic_reshape"); testONNXModels("dynamic_reshape");
testONNXModels("dynamic_reshape_opset_11"); testONNXModels("dynamic_reshape_opset_11");
testONNXModels("flatten_by_prod"); testONNXModels("flatten_by_prod");
testONNXModels("flatten_const");
} }
TEST_P(Test_ONNX_layers, Reshape) TEST_P(Test_ONNX_layers, Reshape)

View File

@ -186,6 +186,13 @@ TEST_P(Test_TensorFlow_layers, eltwise)
runTensorFlowNet("eltwise_sub"); runTensorFlowNet("eltwise_sub");
} }
TEST_P(Test_TensorFlow_layers, channel_broadcast)
{
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
runTensorFlowNet("channel_broadcast");
}
TEST_P(Test_TensorFlow_layers, pad_and_concat) TEST_P(Test_TensorFlow_layers, pad_and_concat)
{ {
runTensorFlowNet("pad_and_concat"); runTensorFlowNet("pad_and_concat");

View File

@ -284,7 +284,7 @@ TEST_P(Objdetect_QRCode_Close, regression)
ASSERT_FALSE(corners.empty()); ASSERT_FALSE(corners.empty());
ASSERT_FALSE(decoded_info.empty()); ASSERT_FALSE(decoded_info.empty());
#else #else
ASSERT_TRUE(qrcode.detect(src, corners)); ASSERT_TRUE(qrcode.detect(barcode, corners));
#endif #endif
const std::string dataset_config = findDataFile(root + "dataset_config.json"); const std::string dataset_config = findDataFile(root + "dataset_config.json");
@ -349,7 +349,7 @@ TEST_P(Objdetect_QRCode_Monitor, regression)
ASSERT_FALSE(corners.empty()); ASSERT_FALSE(corners.empty());
ASSERT_FALSE(decoded_info.empty()); ASSERT_FALSE(decoded_info.empty());
#else #else
ASSERT_TRUE(qrcode.detect(src, corners)); ASSERT_TRUE(qrcode.detect(barcode, corners));
#endif #endif
const std::string dataset_config = findDataFile(root + "dataset_config.json"); const std::string dataset_config = findDataFile(root + "dataset_config.json");

View File

@ -41,6 +41,7 @@ add_subdirectory(python3)
else() # standalone build else() # standalone build
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
project(OpenCVPython CXX C)
include("./standalone.cmake") include("./standalone.cmake")
endif() endif()

View File

@ -0,0 +1,232 @@
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
struct Pix
{
Point next_point;
double cost;
bool operator > (const Pix &b) const
{
return cost > b.cost;
}
};
struct Parameters
{
Mat img, img_pre_render, img_render;
Point end;
std::vector<std::vector<Point> > contours;
std::vector<Point> tmp_contour;
Mat zero_crossing, gradient_magnitude, Ix, Iy, hit_map_x, hit_map_y;
};
static float local_cost(const Point& p, const Point& q, const Mat& gradient_magnitude, const Mat& Iy, const Mat& Ix, const Mat& zero_crossing)
{
float fG = gradient_magnitude.at<float>(q.y, q.x);
float dp;
float dq;
const float WEIGHT_LAP_ZERO_CROSS = 0.43f;
const float WEIGHT_GRADIENT_MAGNITUDE = 0.14f;
const float WEIGHT_GRADIENT_DIRECTION = 0.43f;
bool isDiag = (p.x != q.x) && (p.y != q.y);
if ((Iy.at<float>(p) * (q.x - p.x) - Ix.at<float>(p) * (q.y - p.y)) >= 0)
{
dp = Iy.at<float>(p) * (q.x - p.x) - Ix.at<float>(p) * (q.y - p.y);
dq = Iy.at<float>(q) * (q.x - p.x) - Ix.at<float>(q) * (q.y - p.y);
}
else
{
dp = Iy.at<float>(p) * (p.x - q.x) + (-Ix.at<float>(p)) * (p.y - q.y);
dq = Iy.at<float>(q) * (p.x - q.x) + (-Ix.at<float>(q)) * (p.y - q.y);
}
if (isDiag)
{
dp /= sqrtf(2);
dq /= sqrtf(2);
}
else
{
fG /= sqrtf(2);
}
return WEIGHT_LAP_ZERO_CROSS * zero_crossing.at<uchar>(q) +
WEIGHT_GRADIENT_DIRECTION * (acosf(dp) + acosf(dq)) / static_cast<float>(CV_PI) +
WEIGHT_GRADIENT_MAGNITUDE * fG;
}
static void find_min_path(const Point& start, Parameters* param)
{
Pix begin;
Mat &img = param->img;
Mat cost_map(img.size(), CV_32F, Scalar(FLT_MAX));
Mat expand(img.size(), CV_8UC1, Scalar(0));
Mat processed(img.size(), CV_8UC1, Scalar(0));
Mat removed(img.size(), CV_8UC1, Scalar(0));
std::priority_queue < Pix, std::vector<Pix>, std::greater<Pix> > L;
cost_map.at<float>(start) = 0;
processed.at<uchar>(start) = 1;
begin.cost = 0;
begin.next_point = start;
L.push(begin);
while (!L.empty())
{
Pix P = L.top();
L.pop();
Point p = P.next_point;
processed.at<uchar>(p) = 0;
if (removed.at<uchar>(p) == 0)
{
expand.at<uchar>(p) = 1;
for (int i = -1; i <= 1; i++)
{
for(int j = -1; j <= 1; j++)
{
int tx = p.x + i;
int ty = p.y + j;
if (tx < 0 || tx >= img.cols || ty < 0 || ty >= img.rows)
continue;
if (expand.at<uchar>(ty, tx) == 0)
{
Point q = Point(tx, ty);
float cost = cost_map.at<float>(p) + local_cost(p, q, param->gradient_magnitude, param->Iy, param->Ix, param->zero_crossing);
if (processed.at<uchar>(q) == 1 && cost < cost_map.at<float>(q))
{
removed.at<uchar>(q) = 1;
}
if (processed.at<uchar>(q) == 0)
{
cost_map.at<float>(q) = cost;
param->hit_map_x.at<int>(q)= p.x;
param->hit_map_y.at<int>(q) = p.y;
processed.at<uchar>(q) = 1;
Pix val;
val.cost = cost_map.at<float>(q);
val.next_point = q;
L.push(val);
}
}
}
}
}
}
}
static void onMouse(int event, int x, int y, int , void* userdata)
{
Parameters* param = reinterpret_cast<Parameters*>(userdata);
Point &end = param->end;
std::vector<std::vector<Point> > &contours = param->contours;
std::vector<Point> &tmp_contour = param->tmp_contour;
Mat &img_render = param->img_render;
Mat &img_pre_render = param->img_pre_render;
if (event == EVENT_LBUTTONDOWN)
{
end = Point(x, y);
if (!contours.back().empty())
{
for (int i = static_cast<int>(tmp_contour.size()) - 1; i >= 0; i--)
{
contours.back().push_back(tmp_contour[i]);
}
tmp_contour.clear();
}
else
{
contours.back().push_back(end);
}
find_min_path(end, param);
img_render.copyTo(img_pre_render);
imshow("lasso", img_render);
}
else if (event == EVENT_RBUTTONDOWN)
{
img_pre_render.copyTo(img_render);
drawContours(img_pre_render, contours, static_cast<int>(contours.size()) - 1, Scalar(0,255,0), FILLED);
addWeighted(img_pre_render, 0.3, img_render, 0.7, 0, img_render);
contours.resize(contours.size() + 1);
imshow("lasso", img_render);
}
else if (event == EVENT_MOUSEMOVE && !contours.back().empty())
{
tmp_contour.clear();
img_pre_render.copyTo(img_render);
Point val_point = Point(x, y);
while (val_point != end)
{
tmp_contour.push_back(val_point);
Point cur = Point(param->hit_map_x.at<int>(val_point), param->hit_map_y.at<int>(val_point));
line(img_render, val_point, cur, Scalar(255, 0, 0), 2);
val_point = cur;
}
imshow("lasso", img_render);
}
}
const char* keys =
{
"{help h | |}"
"{@image | fruits.jpg| Path to image to process}"
};
int main( int argc, const char** argv )
{
Parameters param;
const int EDGE_THRESHOLD_LOW = 50;
const int EDGE_THRESHOLD_HIGH = 100;
CommandLineParser parser(argc, argv, keys);
parser.about("\nThis program demonstrates implementation of 'intelligent scissors' algorithm\n"
"To start drawing a new contour select a pixel, click LEFT mouse button.\n"
"To fix a path click LEFT mouse button again.\n"
"To finish drawing a contour click RIGHT mouse button.\n");
if (parser.has("help"))
{
parser.printMessage();
return 1;
}
std::vector<std::vector<Point> > c(1);
param.contours = c;
std::string filename = parser.get<std::string>(0);
Mat grayscale, img_canny;
param.img = imread(samples::findFile(filename));
param.hit_map_x.create(param.img.rows, param.img.cols, CV_32SC1);
param.hit_map_y.create(param.img.rows, param.img.cols, CV_32SC1);
cvtColor(param.img, grayscale, COLOR_BGR2GRAY);
Canny(grayscale, img_canny, EDGE_THRESHOLD_LOW, EDGE_THRESHOLD_HIGH);
threshold(img_canny, param.zero_crossing, 254, 1, THRESH_BINARY_INV);
Sobel(grayscale, param.Ix, CV_32FC1, 1, 0, 1);
Sobel(grayscale, param.Iy, CV_32FC1, 0, 1, 1);
param.Ix.convertTo(param.Ix, CV_32F, 1.0/255);
param.Iy.convertTo(param.Iy, CV_32F, 1.0/255);
// Compute gradients magnitude.
double max_val = 0.0;
magnitude(param.Iy, param.Ix, param.gradient_magnitude);
minMaxLoc(param.gradient_magnitude, 0, &max_val);
param.gradient_magnitude.convertTo(param.gradient_magnitude, CV_32F, -1/max_val, 1.0);
param.img.copyTo(param.img_pre_render);
param.img.copyTo(param.img_render);
namedWindow("lasso");
setMouseCallback("lasso", onMouse, &param);
imshow("lasso", param.img);
waitKey(0);
}

View File

@ -64,7 +64,7 @@ def createSSDGraph(modelPath, configPath, outputPath):
# Nodes that should be kept. # Nodes that should be kept.
keepOps = ['Conv2D', 'BiasAdd', 'Add', 'AddV2', 'Relu', 'Relu6', 'Placeholder', 'FusedBatchNorm', keepOps = ['Conv2D', 'BiasAdd', 'Add', 'AddV2', 'Relu', 'Relu6', 'Placeholder', 'FusedBatchNorm',
'DepthwiseConv2dNative', 'ConcatV2', 'Mul', 'MaxPool', 'AvgPool', 'Identity', 'DepthwiseConv2dNative', 'ConcatV2', 'Mul', 'MaxPool', 'AvgPool', 'Identity',
'Sub', 'ResizeNearestNeighbor', 'Pad', 'FusedBatchNormV3'] 'Sub', 'ResizeNearestNeighbor', 'Pad', 'FusedBatchNormV3', 'Mean']
# Node with which prefixes should be removed # Node with which prefixes should be removed
prefixesToRemove = ('MultipleGridAnchorGenerator/', 'Concatenate/', 'Postprocessor/', 'Preprocessor/map') prefixesToRemove = ('MultipleGridAnchorGenerator/', 'Concatenate/', 'Postprocessor/', 'Preprocessor/map')
@ -235,7 +235,7 @@ def createSSDGraph(modelPath, configPath, outputPath):
# Connect input node to the first layer # Connect input node to the first layer
assert(graph_def.node[0].op == 'Placeholder') assert(graph_def.node[0].op == 'Placeholder')
# assert(graph_def.node[1].op == 'Conv2D') # assert(graph_def.node[1].op == 'Conv2D')
weights = graph_def.node[1].input[0] weights = graph_def.node[1].input[-1]
for i in range(len(graph_def.node[1].input)): for i in range(len(graph_def.node[1].input)):
graph_def.node[1].input.pop() graph_def.node[1].input.pop()
graph_def.node[1].input.append(graph_def.node[0].name) graph_def.node[1].input.append(graph_def.node[0].name)