| /*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) 2000-2008, Intel Corporation, all rights reserved. |
| // Copyright (C) 2009, Willow Garage Inc., all rights reserved. |
| // Copyright (C) 2015, Itseez 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 "precomp.hpp" |
| |
| #ifdef _MSC_VER |
| # if _MSC_VER >= 1700 |
| # pragma warning(disable:4447) // Disable warning 'main' signature found without threading model |
| # endif |
| #endif |
| |
| #if defined ANDROID || defined __linux__ |
| # include <unistd.h> |
| # include <fcntl.h> |
| # include <elf.h> |
| # include <linux/auxvec.h> |
| #endif |
| |
| #if defined WIN32 || defined _WIN32 || defined WINCE |
| #ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?) |
| #define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx |
| #endif |
| #include <windows.h> |
| #if (_WIN32_WINNT >= 0x0602) |
| #include <synchapi.h> |
| #endif |
| #undef small |
| #undef min |
| #undef max |
| #undef abs |
| #include <tchar.h> |
| #if defined _MSC_VER |
| #if _MSC_VER >= 1400 |
| #include <intrin.h> |
| #elif defined _M_IX86 |
| static void __cpuid(int* cpuid_data, int) |
| { |
| __asm |
| { |
| push ebx |
| push edi |
| mov edi, cpuid_data |
| mov eax, 1 |
| cpuid |
| mov [edi], eax |
| mov [edi + 4], ebx |
| mov [edi + 8], ecx |
| mov [edi + 12], edx |
| pop edi |
| pop ebx |
| } |
| } |
| static void __cpuidex(int* cpuid_data, int, int) |
| { |
| __asm |
| { |
| push edi |
| mov edi, cpuid_data |
| mov eax, 7 |
| mov ecx, 0 |
| cpuid |
| mov [edi], eax |
| mov [edi + 4], ebx |
| mov [edi + 8], ecx |
| mov [edi + 12], edx |
| pop edi |
| } |
| } |
| #endif |
| #endif |
| |
| #ifdef WINRT |
| #include <wrl/client.h> |
| #ifndef __cplusplus_winrt |
| #include <windows.storage.h> |
| #pragma comment(lib, "runtimeobject.lib") |
| #endif |
| |
| std::wstring GetTempPathWinRT() |
| { |
| #ifdef __cplusplus_winrt |
| return std::wstring(Windows::Storage::ApplicationData::Current->TemporaryFolder->Path->Data()); |
| #else |
| Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationDataStatics> appdataFactory; |
| Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationData> appdataRef; |
| Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFolder> storagefolderRef; |
| Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageItem> storageitemRef; |
| HSTRING str; |
| HSTRING_HEADER hstrHead; |
| std::wstring wstr; |
| if (FAILED(WindowsCreateStringReference(RuntimeClass_Windows_Storage_ApplicationData, |
| (UINT32)wcslen(RuntimeClass_Windows_Storage_ApplicationData), &hstrHead, &str))) |
| return wstr; |
| if (FAILED(RoGetActivationFactory(str, IID_PPV_ARGS(appdataFactory.ReleaseAndGetAddressOf())))) |
| return wstr; |
| if (FAILED(appdataFactory->get_Current(appdataRef.ReleaseAndGetAddressOf()))) |
| return wstr; |
| if (FAILED(appdataRef->get_TemporaryFolder(storagefolderRef.ReleaseAndGetAddressOf()))) |
| return wstr; |
| if (FAILED(storagefolderRef.As(&storageitemRef))) |
| return wstr; |
| str = NULL; |
| if (FAILED(storageitemRef->get_Path(&str))) |
| return wstr; |
| wstr = WindowsGetStringRawBuffer(str, NULL); |
| WindowsDeleteString(str); |
| return wstr; |
| #endif |
| } |
| |
| std::wstring GetTempFileNameWinRT(std::wstring prefix) |
| { |
| wchar_t guidStr[40]; |
| GUID g; |
| CoCreateGuid(&g); |
| wchar_t* mask = L"%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x"; |
| swprintf(&guidStr[0], sizeof(guidStr)/sizeof(wchar_t), mask, |
| g.Data1, g.Data2, g.Data3, UINT(g.Data4[0]), UINT(g.Data4[1]), |
| UINT(g.Data4[2]), UINT(g.Data4[3]), UINT(g.Data4[4]), |
| UINT(g.Data4[5]), UINT(g.Data4[6]), UINT(g.Data4[7])); |
| |
| return prefix.append(std::wstring(guidStr)); |
| } |
| |
| #endif |
| #else |
| #include <pthread.h> |
| #include <sys/time.h> |
| #include <time.h> |
| |
| #if defined __MACH__ && defined __APPLE__ |
| #include <mach/mach.h> |
| #include <mach/mach_time.h> |
| #endif |
| |
| #endif |
| |
| #ifdef _OPENMP |
| #include "omp.h" |
| #endif |
| |
| #include <stdarg.h> |
| |
| #if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__ |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| #if defined ANDROID |
| #include <sys/sysconf.h> |
| #endif |
| #endif |
| |
| #ifdef ANDROID |
| # include <android/log.h> |
| #endif |
| |
| namespace cv |
| { |
| |
| Exception::Exception() { code = 0; line = 0; } |
| |
| Exception::Exception(int _code, const String& _err, const String& _func, const String& _file, int _line) |
| : code(_code), err(_err), func(_func), file(_file), line(_line) |
| { |
| formatMessage(); |
| } |
| |
| Exception::~Exception() throw() {} |
| |
| /*! |
| \return the error description and the context as a text string. |
| */ |
| const char* Exception::what() const throw() { return msg.c_str(); } |
| |
| void Exception::formatMessage() |
| { |
| if( func.size() > 0 ) |
| msg = format("%s:%d: error: (%d) %s in function %s\n", file.c_str(), line, code, err.c_str(), func.c_str()); |
| else |
| msg = format("%s:%d: error: (%d) %s\n", file.c_str(), line, code, err.c_str()); |
| } |
| |
| struct HWFeatures |
| { |
| enum { MAX_FEATURE = CV_HARDWARE_MAX_FEATURE }; |
| |
| HWFeatures(void) |
| { |
| memset( have, 0, sizeof(have) ); |
| x86_family = 0; |
| } |
| |
| static HWFeatures initialize(void) |
| { |
| HWFeatures f; |
| int cpuid_data[4] = { 0, 0, 0, 0 }; |
| |
| #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) |
| __cpuid(cpuid_data, 1); |
| #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) |
| #ifdef __x86_64__ |
| asm __volatile__ |
| ( |
| "movl $1, %%eax\n\t" |
| "cpuid\n\t" |
| :[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3]) |
| : |
| : "cc" |
| ); |
| #else |
| asm volatile |
| ( |
| "pushl %%ebx\n\t" |
| "movl $1,%%eax\n\t" |
| "cpuid\n\t" |
| "popl %%ebx\n\t" |
| : "=a"(cpuid_data[0]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3]) |
| : |
| : "cc" |
| ); |
| #endif |
| #endif |
| |
| f.x86_family = (cpuid_data[0] >> 8) & 15; |
| if( f.x86_family >= 6 ) |
| { |
| f.have[CV_CPU_MMX] = (cpuid_data[3] & (1 << 23)) != 0; |
| f.have[CV_CPU_SSE] = (cpuid_data[3] & (1<<25)) != 0; |
| f.have[CV_CPU_SSE2] = (cpuid_data[3] & (1<<26)) != 0; |
| f.have[CV_CPU_SSE3] = (cpuid_data[2] & (1<<0)) != 0; |
| f.have[CV_CPU_SSSE3] = (cpuid_data[2] & (1<<9)) != 0; |
| f.have[CV_CPU_FMA3] = (cpuid_data[2] & (1<<12)) != 0; |
| f.have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0; |
| f.have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0; |
| f.have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0; |
| f.have[CV_CPU_AVX] = (((cpuid_data[2] & (1<<28)) != 0)&&((cpuid_data[2] & (1<<27)) != 0));//OS uses XSAVE_XRSTORE and CPU support AVX |
| |
| // make the second call to the cpuid command in order to get |
| // information about extended features like AVX2 |
| #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) |
| __cpuidex(cpuid_data, 7, 0); |
| #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) |
| #ifdef __x86_64__ |
| asm __volatile__ |
| ( |
| "movl $7, %%eax\n\t" |
| "movl $0, %%ecx\n\t" |
| "cpuid\n\t" |
| :[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3]) |
| : |
| : "cc" |
| ); |
| #else |
| asm volatile |
| ( |
| "pushl %%ebx\n\t" |
| "movl $7,%%eax\n\t" |
| "movl $0,%%ecx\n\t" |
| "cpuid\n\t" |
| "movl %%ebx, %0\n\t" |
| "popl %%ebx\n\t" |
| : "=r"(cpuid_data[1]), "=c"(cpuid_data[2]) |
| : |
| : "cc" |
| ); |
| #endif |
| #endif |
| f.have[CV_CPU_AVX2] = (cpuid_data[1] & (1<<5)) != 0; |
| |
| f.have[CV_CPU_AVX_512F] = (cpuid_data[1] & (1<<16)) != 0; |
| f.have[CV_CPU_AVX_512DQ] = (cpuid_data[1] & (1<<17)) != 0; |
| f.have[CV_CPU_AVX_512IFMA512] = (cpuid_data[1] & (1<<21)) != 0; |
| f.have[CV_CPU_AVX_512PF] = (cpuid_data[1] & (1<<26)) != 0; |
| f.have[CV_CPU_AVX_512ER] = (cpuid_data[1] & (1<<27)) != 0; |
| f.have[CV_CPU_AVX_512CD] = (cpuid_data[1] & (1<<28)) != 0; |
| f.have[CV_CPU_AVX_512BW] = (cpuid_data[1] & (1<<30)) != 0; |
| f.have[CV_CPU_AVX_512VL] = (cpuid_data[1] & (1<<31)) != 0; |
| f.have[CV_CPU_AVX_512VBMI] = (cpuid_data[2] & (1<<1)) != 0; |
| } |
| |
| #if defined ANDROID || defined __linux__ |
| #ifdef __aarch64__ |
| f.have[CV_CPU_NEON] = true; |
| #else |
| int cpufile = open("/proc/self/auxv", O_RDONLY); |
| |
| if (cpufile >= 0) |
| { |
| Elf32_auxv_t auxv; |
| const size_t size_auxv_t = sizeof(auxv); |
| |
| while ((size_t)read(cpufile, &auxv, size_auxv_t) == size_auxv_t) |
| { |
| if (auxv.a_type == AT_HWCAP) |
| { |
| f.have[CV_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0; |
| break; |
| } |
| } |
| |
| close(cpufile); |
| } |
| #endif |
| #elif (defined __clang__ || defined __APPLE__) && (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__)) |
| f.have[CV_CPU_NEON] = true; |
| #endif |
| |
| return f; |
| } |
| |
| int x86_family; |
| bool have[MAX_FEATURE+1]; |
| }; |
| |
| static HWFeatures featuresEnabled = HWFeatures::initialize(), featuresDisabled = HWFeatures(); |
| static HWFeatures* currentFeatures = &featuresEnabled; |
| |
| bool checkHardwareSupport(int feature) |
| { |
| CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE ); |
| return currentFeatures->have[feature]; |
| } |
| |
| |
| volatile bool useOptimizedFlag = true; |
| #ifdef HAVE_IPP |
| struct IPPInitializer |
| { |
| IPPInitializer(void) |
| { |
| #if IPP_VERSION_MAJOR >= 8 |
| ippInit(); |
| #else |
| ippStaticInit(); |
| #endif |
| } |
| }; |
| |
| IPPInitializer ippInitializer; |
| #endif |
| |
| volatile bool USE_SSE2 = featuresEnabled.have[CV_CPU_SSE2]; |
| volatile bool USE_SSE4_2 = featuresEnabled.have[CV_CPU_SSE4_2]; |
| volatile bool USE_AVX = featuresEnabled.have[CV_CPU_AVX]; |
| volatile bool USE_AVX2 = featuresEnabled.have[CV_CPU_AVX2]; |
| |
| void setUseOptimized( bool flag ) |
| { |
| useOptimizedFlag = flag; |
| currentFeatures = flag ? &featuresEnabled : &featuresDisabled; |
| USE_SSE2 = currentFeatures->have[CV_CPU_SSE2]; |
| |
| ipp::setUseIPP(flag); |
| ocl::setUseOpenCL(flag); |
| #ifdef HAVE_TEGRA_OPTIMIZATION |
| ::tegra::setUseTegra(flag); |
| #endif |
| } |
| |
| bool useOptimized(void) |
| { |
| return useOptimizedFlag; |
| } |
| |
| int64 getTickCount(void) |
| { |
| #if defined WIN32 || defined _WIN32 || defined WINCE |
| LARGE_INTEGER counter; |
| QueryPerformanceCounter( &counter ); |
| return (int64)counter.QuadPart; |
| #elif defined __linux || defined __linux__ |
| struct timespec tp; |
| clock_gettime(CLOCK_MONOTONIC, &tp); |
| return (int64)tp.tv_sec*1000000000 + tp.tv_nsec; |
| #elif defined __MACH__ && defined __APPLE__ |
| return (int64)mach_absolute_time(); |
| #else |
| struct timeval tv; |
| struct timezone tz; |
| gettimeofday( &tv, &tz ); |
| return (int64)tv.tv_sec*1000000 + tv.tv_usec; |
| #endif |
| } |
| |
| double getTickFrequency(void) |
| { |
| #if defined WIN32 || defined _WIN32 || defined WINCE |
| LARGE_INTEGER freq; |
| QueryPerformanceFrequency(&freq); |
| return (double)freq.QuadPart; |
| #elif defined __linux || defined __linux__ |
| return 1e9; |
| #elif defined __MACH__ && defined __APPLE__ |
| static double freq = 0; |
| if( freq == 0 ) |
| { |
| mach_timebase_info_data_t sTimebaseInfo; |
| mach_timebase_info(&sTimebaseInfo); |
| freq = sTimebaseInfo.denom*1e9/sTimebaseInfo.numer; |
| } |
| return freq; |
| #else |
| return 1e6; |
| #endif |
| } |
| |
| #if defined __GNUC__ && (defined __i386__ || defined __x86_64__ || defined __ppc__) |
| #if defined(__i386__) |
| |
| int64 getCPUTickCount(void) |
| { |
| int64 x; |
| __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); |
| return x; |
| } |
| #elif defined(__x86_64__) |
| |
| int64 getCPUTickCount(void) |
| { |
| unsigned hi, lo; |
| __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); |
| return (int64)lo | ((int64)hi << 32); |
| } |
| |
| #elif defined(__ppc__) |
| |
| int64 getCPUTickCount(void) |
| { |
| int64 result = 0; |
| unsigned upper, lower, tmp; |
| __asm__ volatile( |
| "0: \n" |
| "\tmftbu %0 \n" |
| "\tmftb %1 \n" |
| "\tmftbu %2 \n" |
| "\tcmpw %2,%0 \n" |
| "\tbne 0b \n" |
| : "=r"(upper),"=r"(lower),"=r"(tmp) |
| ); |
| return lower | ((int64)upper << 32); |
| } |
| |
| #else |
| |
| #error "RDTSC not defined" |
| |
| #endif |
| |
| #elif defined _MSC_VER && defined WIN32 && defined _M_IX86 |
| |
| int64 getCPUTickCount(void) |
| { |
| __asm _emit 0x0f; |
| __asm _emit 0x31; |
| } |
| |
| #else |
| |
| //#ifdef HAVE_IPP |
| //int64 getCPUTickCount(void) |
| //{ |
| // return ippGetCpuClocks(); |
| //} |
| //#else |
| int64 getCPUTickCount(void) |
| { |
| return getTickCount(); |
| } |
| //#endif |
| |
| #endif |
| |
| const String& getBuildInformation() |
| { |
| static String build_info = |
| #include "version_string.inc" |
| ; |
| return build_info; |
| } |
| |
| String format( const char* fmt, ... ) |
| { |
| AutoBuffer<char, 1024> buf; |
| |
| for ( ; ; ) |
| { |
| va_list va; |
| va_start(va, fmt); |
| int bsize = static_cast<int>(buf.size()), |
| len = vsnprintf((char *)buf, bsize, fmt, va); |
| va_end(va); |
| |
| if (len < 0 || len >= bsize) |
| { |
| buf.resize(std::max(bsize << 1, len + 1)); |
| continue; |
| } |
| return String((char *)buf, len); |
| } |
| } |
| |
| String tempfile( const char* suffix ) |
| { |
| String fname; |
| #ifndef WINRT |
| const char *temp_dir = getenv("OPENCV_TEMP_PATH"); |
| #endif |
| |
| #if defined WIN32 || defined _WIN32 |
| #ifdef WINRT |
| RoInitialize(RO_INIT_MULTITHREADED); |
| std::wstring temp_dir = GetTempPathWinRT(); |
| |
| std::wstring temp_file = GetTempFileNameWinRT(L"ocv"); |
| if (temp_file.empty()) |
| return String(); |
| |
| temp_file = temp_dir.append(std::wstring(L"\\")).append(temp_file); |
| DeleteFileW(temp_file.c_str()); |
| |
| char aname[MAX_PATH]; |
| size_t copied = wcstombs(aname, temp_file.c_str(), MAX_PATH); |
| CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1)); |
| fname = String(aname); |
| RoUninitialize(); |
| #else |
| char temp_dir2[MAX_PATH] = { 0 }; |
| char temp_file[MAX_PATH] = { 0 }; |
| |
| if (temp_dir == 0 || temp_dir[0] == 0) |
| { |
| ::GetTempPathA(sizeof(temp_dir2), temp_dir2); |
| temp_dir = temp_dir2; |
| } |
| if(0 == ::GetTempFileNameA(temp_dir, "ocv", 0, temp_file)) |
| return String(); |
| |
| DeleteFileA(temp_file); |
| |
| fname = temp_file; |
| #endif |
| # else |
| # ifdef ANDROID |
| //char defaultTemplate[] = "/mnt/sdcard/__opencv_temp.XXXXXX"; |
| char defaultTemplate[] = "/data/local/tmp/__opencv_temp.XXXXXX"; |
| # else |
| char defaultTemplate[] = "/tmp/__opencv_temp.XXXXXX"; |
| # endif |
| |
| if (temp_dir == 0 || temp_dir[0] == 0) |
| fname = defaultTemplate; |
| else |
| { |
| fname = temp_dir; |
| char ech = fname[fname.size() - 1]; |
| if(ech != '/' && ech != '\\') |
| fname = fname + "/"; |
| fname = fname + "__opencv_temp.XXXXXX"; |
| } |
| |
| const int fd = mkstemp((char*)fname.c_str()); |
| if (fd == -1) return String(); |
| |
| close(fd); |
| remove(fname.c_str()); |
| # endif |
| |
| if (suffix) |
| { |
| if (suffix[0] != '.') |
| return fname + "." + suffix; |
| else |
| return fname + suffix; |
| } |
| return fname; |
| } |
| |
| static CvErrorCallback customErrorCallback = 0; |
| static void* customErrorCallbackData = 0; |
| static bool breakOnError = false; |
| |
| bool setBreakOnError(bool value) |
| { |
| bool prevVal = breakOnError; |
| breakOnError = value; |
| return prevVal; |
| } |
| |
| void error( const Exception& exc ) |
| { |
| if (customErrorCallback != 0) |
| customErrorCallback(exc.code, exc.func.c_str(), exc.err.c_str(), |
| exc.file.c_str(), exc.line, customErrorCallbackData); |
| else |
| { |
| const char* errorStr = cvErrorStr(exc.code); |
| char buf[1 << 16]; |
| |
| sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d", |
| errorStr, exc.err.c_str(), exc.func.size() > 0 ? |
| exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line ); |
| fprintf( stderr, "%s\n", buf ); |
| fflush( stderr ); |
| # ifdef __ANDROID__ |
| __android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf); |
| # endif |
| } |
| |
| if(breakOnError) |
| { |
| static volatile int* p = 0; |
| *p = 0; |
| } |
| |
| throw exc; |
| } |
| |
| void error(int _code, const String& _err, const char* _func, const char* _file, int _line) |
| { |
| error(cv::Exception(_code, _err, _func, _file, _line)); |
| } |
| |
| CvErrorCallback |
| redirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata) |
| { |
| if( prevUserdata ) |
| *prevUserdata = customErrorCallbackData; |
| |
| CvErrorCallback prevCallback = customErrorCallback; |
| |
| customErrorCallback = errCallback; |
| customErrorCallbackData = userdata; |
| |
| return prevCallback; |
| } |
| |
| } |
| |
| CV_IMPL int cvCheckHardwareSupport(int feature) |
| { |
| CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE ); |
| return cv::currentFeatures->have[feature]; |
| } |
| |
| CV_IMPL int cvUseOptimized( int flag ) |
| { |
| int prevMode = cv::useOptimizedFlag; |
| cv::setUseOptimized( flag != 0 ); |
| return prevMode; |
| } |
| |
| CV_IMPL int64 cvGetTickCount(void) |
| { |
| return cv::getTickCount(); |
| } |
| |
| CV_IMPL double cvGetTickFrequency(void) |
| { |
| return cv::getTickFrequency()*1e-6; |
| } |
| |
| CV_IMPL CvErrorCallback |
| cvRedirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata) |
| { |
| return cv::redirectError(errCallback, userdata, prevUserdata); |
| } |
| |
| CV_IMPL int cvNulDevReport( int, const char*, const char*, |
| const char*, int, void* ) |
| { |
| return 0; |
| } |
| |
| CV_IMPL int cvStdErrReport( int, const char*, const char*, |
| const char*, int, void* ) |
| { |
| return 0; |
| } |
| |
| CV_IMPL int cvGuiBoxReport( int, const char*, const char*, |
| const char*, int, void* ) |
| { |
| return 0; |
| } |
| |
| CV_IMPL int cvGetErrInfo( const char**, const char**, const char**, int* ) |
| { |
| return 0; |
| } |
| |
| |
| CV_IMPL const char* cvErrorStr( int status ) |
| { |
| static char buf[256]; |
| |
| switch (status) |
| { |
| case CV_StsOk : return "No Error"; |
| case CV_StsBackTrace : return "Backtrace"; |
| case CV_StsError : return "Unspecified error"; |
| case CV_StsInternal : return "Internal error"; |
| case CV_StsNoMem : return "Insufficient memory"; |
| case CV_StsBadArg : return "Bad argument"; |
| case CV_StsNoConv : return "Iterations do not converge"; |
| case CV_StsAutoTrace : return "Autotrace call"; |
| case CV_StsBadSize : return "Incorrect size of input array"; |
| case CV_StsNullPtr : return "Null pointer"; |
| case CV_StsDivByZero : return "Division by zero occured"; |
| case CV_BadStep : return "Image step is wrong"; |
| case CV_StsInplaceNotSupported : return "Inplace operation is not supported"; |
| case CV_StsObjectNotFound : return "Requested object was not found"; |
| case CV_BadDepth : return "Input image depth is not supported by function"; |
| case CV_StsUnmatchedFormats : return "Formats of input arguments do not match"; |
| case CV_StsUnmatchedSizes : return "Sizes of input arguments do not match"; |
| case CV_StsOutOfRange : return "One of arguments\' values is out of range"; |
| case CV_StsUnsupportedFormat : return "Unsupported format or combination of formats"; |
| case CV_BadCOI : return "Input COI is not supported"; |
| case CV_BadNumChannels : return "Bad number of channels"; |
| case CV_StsBadFlag : return "Bad flag (parameter or structure field)"; |
| case CV_StsBadPoint : return "Bad parameter of type CvPoint"; |
| case CV_StsBadMask : return "Bad type of mask argument"; |
| case CV_StsParseError : return "Parsing error"; |
| case CV_StsNotImplemented : return "The function/feature is not implemented"; |
| case CV_StsBadMemBlock : return "Memory block has been corrupted"; |
| case CV_StsAssert : return "Assertion failed"; |
| case CV_GpuNotSupported : return "No CUDA support"; |
| case CV_GpuApiCallError : return "Gpu API call"; |
| case CV_OpenGlNotSupported : return "No OpenGL support"; |
| case CV_OpenGlApiCallError : return "OpenGL API call"; |
| }; |
| |
| sprintf(buf, "Unknown %s code %d", status >= 0 ? "status":"error", status); |
| return buf; |
| } |
| |
| CV_IMPL int cvGetErrMode(void) |
| { |
| return 0; |
| } |
| |
| CV_IMPL int cvSetErrMode(int) |
| { |
| return 0; |
| } |
| |
| CV_IMPL int cvGetErrStatus(void) |
| { |
| return 0; |
| } |
| |
| CV_IMPL void cvSetErrStatus(int) |
| { |
| } |
| |
| |
| CV_IMPL void cvError( int code, const char* func_name, |
| const char* err_msg, |
| const char* file_name, int line ) |
| { |
| cv::error(cv::Exception(code, err_msg, func_name, file_name, line)); |
| } |
| |
| /* function, which converts int to int */ |
| CV_IMPL int |
| cvErrorFromIppStatus( int status ) |
| { |
| switch (status) |
| { |
| case CV_BADSIZE_ERR: return CV_StsBadSize; |
| case CV_BADMEMBLOCK_ERR: return CV_StsBadMemBlock; |
| case CV_NULLPTR_ERR: return CV_StsNullPtr; |
| case CV_DIV_BY_ZERO_ERR: return CV_StsDivByZero; |
| case CV_BADSTEP_ERR: return CV_BadStep; |
| case CV_OUTOFMEM_ERR: return CV_StsNoMem; |
| case CV_BADARG_ERR: return CV_StsBadArg; |
| case CV_NOTDEFINED_ERR: return CV_StsError; |
| case CV_INPLACE_NOT_SUPPORTED_ERR: return CV_StsInplaceNotSupported; |
| case CV_NOTFOUND_ERR: return CV_StsObjectNotFound; |
| case CV_BADCONVERGENCE_ERR: return CV_StsNoConv; |
| case CV_BADDEPTH_ERR: return CV_BadDepth; |
| case CV_UNMATCHED_FORMATS_ERR: return CV_StsUnmatchedFormats; |
| case CV_UNSUPPORTED_COI_ERR: return CV_BadCOI; |
| case CV_UNSUPPORTED_CHANNELS_ERR: return CV_BadNumChannels; |
| case CV_BADFLAG_ERR: return CV_StsBadFlag; |
| case CV_BADRANGE_ERR: return CV_StsBadArg; |
| case CV_BADCOEF_ERR: return CV_StsBadArg; |
| case CV_BADFACTOR_ERR: return CV_StsBadArg; |
| case CV_BADPOINT_ERR: return CV_StsBadPoint; |
| |
| default: |
| return CV_StsError; |
| } |
| } |
| |
| namespace cv { |
| bool __termination = false; |
| } |
| |
| namespace cv |
| { |
| |
| #if defined WIN32 || defined _WIN32 || defined WINCE |
| |
| struct Mutex::Impl |
| { |
| Impl() |
| { |
| #if (_WIN32_WINNT >= 0x0600) |
| ::InitializeCriticalSectionEx(&cs, 1000, 0); |
| #else |
| ::InitializeCriticalSection(&cs); |
| #endif |
| refcount = 1; |
| } |
| ~Impl() { DeleteCriticalSection(&cs); } |
| |
| void lock() { EnterCriticalSection(&cs); } |
| bool trylock() { return TryEnterCriticalSection(&cs) != 0; } |
| void unlock() { LeaveCriticalSection(&cs); } |
| |
| CRITICAL_SECTION cs; |
| int refcount; |
| }; |
| |
| #else |
| |
| struct Mutex::Impl |
| { |
| Impl() |
| { |
| pthread_mutexattr_t attr; |
| pthread_mutexattr_init(&attr); |
| pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); |
| pthread_mutex_init(&mt, &attr); |
| pthread_mutexattr_destroy(&attr); |
| |
| refcount = 1; |
| } |
| ~Impl() { pthread_mutex_destroy(&mt); } |
| |
| void lock() { pthread_mutex_lock(&mt); } |
| bool trylock() { return pthread_mutex_trylock(&mt) == 0; } |
| void unlock() { pthread_mutex_unlock(&mt); } |
| |
| pthread_mutex_t mt; |
| int refcount; |
| }; |
| |
| #endif |
| |
| Mutex::Mutex() |
| { |
| impl = new Mutex::Impl; |
| } |
| |
| Mutex::~Mutex() |
| { |
| if( CV_XADD(&impl->refcount, -1) == 1 ) |
| delete impl; |
| impl = 0; |
| } |
| |
| Mutex::Mutex(const Mutex& m) |
| { |
| impl = m.impl; |
| CV_XADD(&impl->refcount, 1); |
| } |
| |
| Mutex& Mutex::operator = (const Mutex& m) |
| { |
| CV_XADD(&m.impl->refcount, 1); |
| if( CV_XADD(&impl->refcount, -1) == 1 ) |
| delete impl; |
| impl = m.impl; |
| return *this; |
| } |
| |
| void Mutex::lock() { impl->lock(); } |
| void Mutex::unlock() { impl->unlock(); } |
| bool Mutex::trylock() { return impl->trylock(); } |
| |
| |
| //////////////////////////////// thread-local storage //////////////////////////////// |
| |
| class TLSStorage |
| { |
| std::vector<void*> tlsData_; |
| public: |
| TLSStorage() { tlsData_.reserve(16); } |
| ~TLSStorage(); |
| inline void* getData(int key) const |
| { |
| CV_DbgAssert(key >= 0); |
| return (key < (int)tlsData_.size()) ? tlsData_[key] : NULL; |
| } |
| inline void setData(int key, void* data) |
| { |
| CV_DbgAssert(key >= 0); |
| if (key >= (int)tlsData_.size()) |
| { |
| tlsData_.resize(key + 1, NULL); |
| } |
| tlsData_[key] = data; |
| } |
| |
| inline static TLSStorage* get(); |
| }; |
| |
| #ifdef WIN32 |
| #ifdef _MSC_VER |
| #pragma warning(disable:4505) // unreferenced local function has been removed |
| #endif |
| |
| #ifdef WINRT |
| // using C++11 thread attribute for local thread data |
| static __declspec( thread ) TLSStorage* g_tlsdata = NULL; |
| |
| static void deleteThreadData() |
| { |
| if (g_tlsdata) |
| { |
| delete g_tlsdata; |
| g_tlsdata = NULL; |
| } |
| } |
| |
| inline TLSStorage* TLSStorage::get() |
| { |
| if (!g_tlsdata) |
| { |
| g_tlsdata = new TLSStorage; |
| } |
| return g_tlsdata; |
| } |
| #else |
| #ifdef WINCE |
| # define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) |
| #endif |
| static DWORD tlsKey = TLS_OUT_OF_INDEXES; |
| |
| static void deleteThreadData() |
| { |
| if(tlsKey != TLS_OUT_OF_INDEXES) |
| { |
| delete (TLSStorage*)TlsGetValue(tlsKey); |
| TlsSetValue(tlsKey, NULL); |
| } |
| } |
| |
| inline TLSStorage* TLSStorage::get() |
| { |
| if (tlsKey == TLS_OUT_OF_INDEXES) |
| { |
| tlsKey = TlsAlloc(); |
| CV_Assert(tlsKey != TLS_OUT_OF_INDEXES); |
| } |
| TLSStorage* d = (TLSStorage*)TlsGetValue(tlsKey); |
| if (!d) |
| { |
| d = new TLSStorage; |
| TlsSetValue(tlsKey, d); |
| } |
| return d; |
| } |
| #endif //WINRT |
| |
| #if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE |
| #ifdef WINRT |
| #pragma warning(disable:4447) // Disable warning 'main' signature found without threading model |
| #endif |
| |
| extern "C" |
| 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; |
| } |
| else |
| { |
| // Not allowed to free resources if lpReserved is non-null |
| // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx |
| cv::deleteThreadAllocData(); |
| cv::deleteThreadData(); |
| } |
| } |
| return TRUE; |
| } |
| #endif |
| |
| #else |
| static pthread_key_t tlsKey = 0; |
| static pthread_once_t tlsKeyOnce = PTHREAD_ONCE_INIT; |
| |
| static void deleteTLSStorage(void* data) |
| { |
| delete (TLSStorage*)data; |
| } |
| |
| static void makeKey() |
| { |
| int errcode = pthread_key_create(&tlsKey, deleteTLSStorage); |
| CV_Assert(errcode == 0); |
| } |
| |
| inline TLSStorage* TLSStorage::get() |
| { |
| pthread_once(&tlsKeyOnce, makeKey); |
| TLSStorage* d = (TLSStorage*)pthread_getspecific(tlsKey); |
| if( !d ) |
| { |
| d = new TLSStorage; |
| pthread_setspecific(tlsKey, d); |
| } |
| return d; |
| } |
| #endif |
| |
| class TLSContainerStorage |
| { |
| cv::Mutex mutex_; |
| std::vector<TLSDataContainer*> tlsContainers_; |
| public: |
| TLSContainerStorage() { } |
| ~TLSContainerStorage() |
| { |
| for (size_t i = 0; i < tlsContainers_.size(); i++) |
| { |
| CV_DbgAssert(tlsContainers_[i] == NULL); // not all keys released |
| tlsContainers_[i] = NULL; |
| } |
| } |
| |
| int allocateKey(TLSDataContainer* pContainer) |
| { |
| cv::AutoLock lock(mutex_); |
| tlsContainers_.push_back(pContainer); |
| return (int)tlsContainers_.size() - 1; |
| } |
| void releaseKey(int id, TLSDataContainer* pContainer) |
| { |
| cv::AutoLock lock(mutex_); |
| CV_Assert(tlsContainers_[id] == pContainer); |
| tlsContainers_[id] = NULL; |
| // currently, we don't go into thread's TLSData and release data for this key |
| } |
| |
| void destroyData(int key, void* data) |
| { |
| cv::AutoLock lock(mutex_); |
| TLSDataContainer* k = tlsContainers_[key]; |
| if (!k) |
| return; |
| try |
| { |
| k->deleteDataInstance(data); |
| } |
| catch (...) |
| { |
| CV_DbgAssert(k == NULL); // Debug this! |
| } |
| } |
| }; |
| |
| // This is a wrapper function that will ensure 'tlsContainerStorage' is constructed on first use. |
| // For more information: http://www.parashift.com/c++-faq/static-init-order-on-first-use.html |
| static TLSContainerStorage& getTLSContainerStorage() |
| { |
| static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage(); |
| return *tlsContainerStorage; |
| } |
| |
| TLSDataContainer::TLSDataContainer() |
| : key_(-1) |
| { |
| key_ = getTLSContainerStorage().allocateKey(this); |
| } |
| |
| TLSDataContainer::~TLSDataContainer() |
| { |
| getTLSContainerStorage().releaseKey(key_, this); |
| key_ = -1; |
| } |
| |
| void* TLSDataContainer::getData() const |
| { |
| CV_Assert(key_ >= 0); |
| TLSStorage* tlsData = TLSStorage::get(); |
| void* data = tlsData->getData(key_); |
| if (!data) |
| { |
| data = this->createDataInstance(); |
| CV_DbgAssert(data != NULL); |
| tlsData->setData(key_, data); |
| } |
| return data; |
| } |
| |
| TLSStorage::~TLSStorage() |
| { |
| for (int i = 0; i < (int)tlsData_.size(); i++) |
| { |
| void*& data = tlsData_[i]; |
| if (data) |
| { |
| getTLSContainerStorage().destroyData(i, data); |
| data = NULL; |
| } |
| } |
| tlsData_.clear(); |
| } |
| |
| |
| |
| TLSData<CoreTLSData>& getCoreTlsData() |
| { |
| static TLSData<CoreTLSData> *value = new TLSData<CoreTLSData>(); |
| return *value; |
| } |
| |
| |
| |
| #ifdef CV_COLLECT_IMPL_DATA |
| ImplCollector& getImplData() |
| { |
| static ImplCollector *value = new ImplCollector(); |
| return *value; |
| } |
| |
| void setImpl(int flags) |
| { |
| cv::AutoLock lock(getImplData().mutex); |
| |
| getImplData().implFlags = flags; |
| getImplData().implCode.clear(); |
| getImplData().implFun.clear(); |
| } |
| |
| void addImpl(int flag, const char* func) |
| { |
| cv::AutoLock lock(getImplData().mutex); |
| |
| getImplData().implFlags |= flag; |
| if(func) // use lazy collection if name was not specified |
| { |
| size_t index = getImplData().implCode.size(); |
| if(!index || (getImplData().implCode[index-1] != flag || getImplData().implFun[index-1].compare(func))) // avoid duplicates |
| { |
| getImplData().implCode.push_back(flag); |
| getImplData().implFun.push_back(func); |
| } |
| } |
| } |
| |
| int getImpl(std::vector<int> &impl, std::vector<String> &funName) |
| { |
| cv::AutoLock lock(getImplData().mutex); |
| |
| impl = getImplData().implCode; |
| funName = getImplData().implFun; |
| return getImplData().implFlags; // return actual flags for lazy collection |
| } |
| |
| bool useCollection() |
| { |
| return getImplData().useCollection; |
| } |
| |
| void setUseCollection(bool flag) |
| { |
| cv::AutoLock lock(getImplData().mutex); |
| |
| getImplData().useCollection = flag; |
| } |
| #endif |
| |
| namespace ipp |
| { |
| |
| static int ippStatus = 0; // 0 - all is ok, -1 - IPP functions failed |
| static const char * funcname = NULL, * filename = NULL; |
| static int linen = 0; |
| |
| void setIppStatus(int status, const char * const _funcname, const char * const _filename, int _line) |
| { |
| ippStatus = status; |
| funcname = _funcname; |
| filename = _filename; |
| linen = _line; |
| } |
| |
| int getIppStatus() |
| { |
| return ippStatus; |
| } |
| |
| String getIppErrorLocation() |
| { |
| return format("%s:%d %s", filename ? filename : "", linen, funcname ? funcname : ""); |
| } |
| |
| bool useIPP() |
| { |
| #ifdef HAVE_IPP |
| CoreTLSData* data = getCoreTlsData().get(); |
| if(data->useIPP < 0) |
| { |
| const char* pIppEnv = getenv("OPENCV_IPP"); |
| if(pIppEnv && (cv::String(pIppEnv) == "disabled")) |
| data->useIPP = false; |
| else |
| data->useIPP = true; |
| } |
| return (data->useIPP > 0); |
| #else |
| return false; |
| #endif |
| } |
| |
| void setUseIPP(bool flag) |
| { |
| CoreTLSData* data = getCoreTlsData().get(); |
| #ifdef HAVE_IPP |
| data->useIPP = flag; |
| #else |
| (void)flag; |
| data->useIPP = false; |
| #endif |
| } |
| |
| } // namespace ipp |
| |
| } // namespace cv |
| |
| #ifdef HAVE_TEGRA_OPTIMIZATION |
| |
| namespace tegra { |
| |
| bool useTegra() |
| { |
| cv::CoreTLSData* data = cv::getCoreTlsData().get(); |
| |
| if (data->useTegra < 0) |
| { |
| const char* pTegraEnv = getenv("OPENCV_TEGRA"); |
| if (pTegraEnv && (cv::String(pTegraEnv) == "disabled")) |
| data->useTegra = false; |
| else |
| data->useTegra = true; |
| } |
| |
| return (data->useTegra > 0); |
| } |
| |
| void setUseTegra(bool flag) |
| { |
| cv::CoreTLSData* data = cv::getCoreTlsData().get(); |
| data->useTegra = flag; |
| } |
| |
| } // namespace tegra |
| |
| #endif |
| |
| /* End of file. */ |