core: add utils::findDataFile() / samples::findFile()
This commit is contained in:
@@ -0,0 +1,398 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
#include "opencv_data_config.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#include <opencv2/core/utils/logger.defines.hpp>
|
||||
#undef CV_LOG_STRIP_LEVEL
|
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
#include "opencv2/core/utils/filesystem.hpp"
|
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef small
|
||||
#undef min
|
||||
#undef max
|
||||
#undef abs
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_MAC
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace cv { namespace utils {
|
||||
|
||||
static cv::Ptr< std::vector<cv::String> > g_data_search_path;
|
||||
static cv::Ptr< std::vector<cv::String> > g_data_search_subdir;
|
||||
|
||||
static std::vector<cv::String>& _getDataSearchPath()
|
||||
{
|
||||
if (g_data_search_path.empty())
|
||||
g_data_search_path.reset(new std::vector<cv::String>());
|
||||
return *(g_data_search_path.get());
|
||||
}
|
||||
|
||||
static std::vector<cv::String>& _getDataSearchSubDirectory()
|
||||
{
|
||||
if (g_data_search_subdir.empty())
|
||||
{
|
||||
g_data_search_subdir.reset(new std::vector<cv::String>());
|
||||
g_data_search_subdir->push_back("data");
|
||||
g_data_search_subdir->push_back("");
|
||||
}
|
||||
return *(g_data_search_subdir.get());
|
||||
}
|
||||
|
||||
|
||||
CV_EXPORTS void addDataSearchPath(const cv::String& path)
|
||||
{
|
||||
if (utils::fs::isDirectory(path))
|
||||
_getDataSearchPath().push_back(path);
|
||||
}
|
||||
CV_EXPORTS void addDataSearchSubDirectory(const cv::String& subdir)
|
||||
{
|
||||
_getDataSearchSubDirectory().push_back(subdir);
|
||||
}
|
||||
|
||||
static bool isPathSep(char c)
|
||||
{
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
static bool isSubDirectory_(const cv::String& base_path, const cv::String& path)
|
||||
{
|
||||
size_t N = base_path.size();
|
||||
if (N == 0)
|
||||
return false;
|
||||
if (isPathSep(base_path[N - 1]))
|
||||
N--;
|
||||
if (path.size() < N)
|
||||
return false;
|
||||
for (size_t i = 0; i < N; i++)
|
||||
{
|
||||
if (path[i] == base_path[i])
|
||||
continue;
|
||||
if (isPathSep(path[i]) && isPathSep(base_path[i]))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
size_t M = path.size();
|
||||
if (M > N)
|
||||
{
|
||||
if (!isPathSep(path[N]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool isSubDirectory(const cv::String& base_path, const cv::String& path)
|
||||
{
|
||||
bool res = isSubDirectory_(base_path, path);
|
||||
CV_LOG_VERBOSE(NULL, 0, "isSubDirectory(): base: " << base_path << " path: " << path << " => result: " << (res ? "TRUE" : "FALSE"));
|
||||
return res;
|
||||
}
|
||||
|
||||
static cv::String getModuleLocation(const void* addr)
|
||||
{
|
||||
CV_UNUSED(addr);
|
||||
#ifdef _WIN32
|
||||
HMODULE m = 0;
|
||||
#if _WIN32_WINNT >= 0x0501
|
||||
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
reinterpret_cast<LPCTSTR>(addr),
|
||||
&m);
|
||||
#endif
|
||||
if (m)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
const size_t path_size = sizeof(path)/sizeof(*path);
|
||||
size_t sz = GetModuleFileNameA(m, path, path_size); // no unicode support
|
||||
if (sz > 0 && sz < path_size)
|
||||
{
|
||||
path[sz] = '\0';
|
||||
return cv::String(path);
|
||||
}
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
std::ifstream fs("/proc/self/maps");
|
||||
std::string line;
|
||||
while (std::getline(fs, line, '\n'))
|
||||
{
|
||||
long long int addr_begin = 0, addr_end = 0;
|
||||
if (2 == sscanf(line.c_str(), "%llx-%llx", &addr_begin, &addr_end))
|
||||
{
|
||||
if ((intptr_t)addr >= (intptr_t)addr_begin && (intptr_t)addr < (intptr_t)addr_end)
|
||||
{
|
||||
size_t pos = line.rfind(" "); // 2 spaces
|
||||
if (pos == cv::String::npos)
|
||||
pos = line.rfind(' '); // 1 spaces
|
||||
else
|
||||
pos++;
|
||||
if (pos == cv::String::npos)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "Can't parse module path: '" << line << '\'');
|
||||
}
|
||||
return line.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
# if TARGET_OS_MAC
|
||||
Dl_info info;
|
||||
if (0 != dladdr(addr, &info))
|
||||
{
|
||||
return cv::String(info.dli_fname);
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
// not supported, skip
|
||||
#endif
|
||||
return cv::String();
|
||||
}
|
||||
|
||||
cv::String findDataFile(const cv::String& relative_path,
|
||||
const char* configuration_parameter,
|
||||
const std::vector<String>* search_paths,
|
||||
const std::vector<String>* subdir_paths)
|
||||
{
|
||||
configuration_parameter = configuration_parameter ? configuration_parameter : "OPENCV_DATA_PATH";
|
||||
CV_LOG_DEBUG(NULL, cv::format("utils::findDataFile('%s', %s)", relative_path.c_str(), configuration_parameter));
|
||||
|
||||
#define TRY_FILE_WITH_PREFIX(prefix) \
|
||||
{ \
|
||||
cv::String path = utils::fs::join(prefix, relative_path); \
|
||||
CV_LOG_DEBUG(NULL, cv::format("... Line %d: trying open '%s'", __LINE__, path.c_str())); \
|
||||
FILE* f = fopen(path.c_str(), "rb"); \
|
||||
if(f) { \
|
||||
fclose(f); \
|
||||
return path; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
// Step 0: check current directory or absolute path at first
|
||||
TRY_FILE_WITH_PREFIX("");
|
||||
|
||||
|
||||
// Step 1
|
||||
const std::vector<cv::String>& search_path = search_paths ? *search_paths : _getDataSearchPath();
|
||||
for(size_t i = search_path.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& prefix = search_path[i - 1];
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
|
||||
const std::vector<cv::String>& search_subdir = subdir_paths ? *subdir_paths : _getDataSearchSubDirectory();
|
||||
|
||||
|
||||
// Step 2
|
||||
const cv::String configuration_parameter_s(configuration_parameter ? configuration_parameter : "");
|
||||
const cv::utils::Paths& search_hint = configuration_parameter_s.empty() ? cv::utils::Paths()
|
||||
: getConfigurationParameterPaths((configuration_parameter_s + "_HINT").c_str());
|
||||
for (size_t k = 0; k < search_hint.size(); k++)
|
||||
{
|
||||
cv::String datapath = search_hint[k];
|
||||
if (datapath.empty())
|
||||
continue;
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): trying " << configuration_parameter << "_HINT=" << datapath);
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_WARNING(NULL, configuration_parameter << "_HINT is specified but it is not a directory: " << datapath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Step 3
|
||||
const cv::utils::Paths& override_paths = configuration_parameter_s.empty() ? cv::utils::Paths()
|
||||
: getConfigurationParameterPaths(configuration_parameter);
|
||||
for (size_t k = 0; k < override_paths.size(); k++)
|
||||
{
|
||||
cv::String datapath = override_paths[k];
|
||||
if (datapath.empty())
|
||||
continue;
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): trying " << configuration_parameter << "=" << datapath);
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_WARNING(NULL, configuration_parameter << " is specified but it is not a directory: " << datapath);
|
||||
}
|
||||
}
|
||||
if (!override_paths.empty())
|
||||
{
|
||||
CV_LOG_INFO(NULL, "utils::findDataFile(): can't find data file via " << configuration_parameter << " configuration override: " << relative_path);
|
||||
return cv::String();
|
||||
}
|
||||
|
||||
|
||||
// Steps: 4, 5, 6
|
||||
cv::String cwd = utils::fs::getcwd();
|
||||
cv::String build_dir(OPENCV_BUILD_DIR);
|
||||
bool has_tested_build_directory = false;
|
||||
if (isSubDirectory(build_dir, cwd) || isSubDirectory(utils::fs::canonical(build_dir), utils::fs::canonical(cwd)))
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): the current directory is build sub-directory: " << cwd);
|
||||
const char* build_subdirs[] = { OPENCV_DATA_BUILD_DIR_SEARCH_PATHS };
|
||||
for (size_t k = 0; k < sizeof(build_subdirs)/sizeof(build_subdirs[0]); k++)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): <build>/" << build_subdirs[k]);
|
||||
cv::String datapath = utils::fs::join(build_dir, build_subdirs[k]);
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
has_tested_build_directory = true;
|
||||
}
|
||||
|
||||
cv::String source_dir;
|
||||
cv::String try_source_dir = cwd;
|
||||
for (int levels = 0; levels < 3; ++levels)
|
||||
{
|
||||
if (utils::fs::exists(utils::fs::join(try_source_dir, "modules/core/include/opencv2/core/version.hpp")))
|
||||
{
|
||||
source_dir = try_source_dir;
|
||||
break;
|
||||
}
|
||||
try_source_dir = utils::fs::join(try_source_dir, "/..");
|
||||
}
|
||||
if (!source_dir.empty())
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): the current directory is source sub-directory: " << source_dir);
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): <source>" << source_dir);
|
||||
cv::String datapath = source_dir;
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::String module_path = getModuleLocation((void*)getModuleLocation); // use code addr, doesn't work with static linkage!
|
||||
CV_LOG_DEBUG(NULL, "Detected module path: '" << module_path << '\'');
|
||||
|
||||
if (!has_tested_build_directory &&
|
||||
(isSubDirectory(build_dir, module_path) || isSubDirectory(utils::fs::canonical(build_dir), utils::fs::canonical(module_path)))
|
||||
)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): the binary module directory is build sub-directory: " << module_path);
|
||||
const char* build_subdirs[] = { OPENCV_DATA_BUILD_DIR_SEARCH_PATHS };
|
||||
for (size_t k = 0; k < sizeof(build_subdirs)/sizeof(build_subdirs[0]); k++)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): <build>/" << build_subdirs[k]);
|
||||
cv::String datapath = utils::fs::join(build_dir, build_subdirs[k]);
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined OPENCV_INSTALL_DATA_DIR_RELATIVE
|
||||
if (!module_path.empty()) // require module path
|
||||
{
|
||||
size_t pos = module_path.rfind('/');
|
||||
if (pos == cv::String::npos)
|
||||
pos = module_path.rfind('\\');
|
||||
cv::String module_dir = (pos == cv::String::npos) ? module_path : module_path.substr(0, pos);
|
||||
const char* install_subdirs[] = { OPENCV_INSTALL_DATA_DIR_RELATIVE };
|
||||
for (size_t k = 0; k < sizeof(install_subdirs)/sizeof(install_subdirs[0]); k++)
|
||||
{
|
||||
cv::String datapath = utils::fs::join(module_dir, install_subdirs[k]);
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): trying install path (from binary path): " << datapath);
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): ... skip, not a valid directory: " << datapath);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined OPENCV_INSTALL_PREFIX && defined OPENCV_DATA_INSTALL_PATH
|
||||
cv::String install_dir(OPENCV_INSTALL_PREFIX);
|
||||
// use core/world module path and verify that library is running from installation directory
|
||||
// It is neccessary to avoid touching of unrelated common /usr/local path
|
||||
if (module_path.empty()) // can't determine
|
||||
module_path = install_dir;
|
||||
if (isSubDirectory(install_dir, module_path) || isSubDirectory(utils::fs::canonical(install_dir), utils::fs::canonical(module_path)))
|
||||
{
|
||||
cv::String datapath = utils::fs::join(install_dir, OPENCV_DATA_INSTALL_PATH);
|
||||
if (utils::fs::isDirectory(datapath))
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "utils::findDataFile(): trying install path: " << datapath);
|
||||
for(size_t i = search_subdir.size(); i > 0; i--)
|
||||
{
|
||||
const cv::String& subdir = search_subdir[i - 1];
|
||||
cv::String prefix = utils::fs::join(datapath, subdir);
|
||||
TRY_FILE_WITH_PREFIX(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return cv::String(); // not found
|
||||
}
|
||||
|
||||
cv::String findDataFile(const cv::String& relative_path, bool required, const char* configuration_parameter)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, cv::format("cv::utils::findDataFile('%s', %s, %s)",
|
||||
relative_path.c_str(), required ? "true" : "false",
|
||||
configuration_parameter ? configuration_parameter : "NULL"));
|
||||
cv::String result = cv::utils::findDataFile(relative_path,
|
||||
configuration_parameter,
|
||||
NULL,
|
||||
NULL);
|
||||
if (result.empty() && required)
|
||||
CV_Error(cv::Error::StsError, cv::format("OpenCV: Can't find required data file: %s", relative_path.c_str()));
|
||||
return result;
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -85,6 +85,20 @@ cv::String join(const cv::String& base, const cv::String& path)
|
||||
|
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT
|
||||
|
||||
cv::String canonical(const cv::String& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char* result = _fullpath(NULL, path.c_str(), 0);
|
||||
#else
|
||||
const char* result = realpath(path.c_str(), NULL);
|
||||
#endif
|
||||
if (result)
|
||||
return cv::String(result);
|
||||
// no error handling, just return input
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
bool exists(const cv::String& path)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
@@ -543,11 +557,12 @@ cv::String getCacheDirectory(const char* sub_directory_name, const char* configu
|
||||
|
||||
#else
|
||||
#define NOT_IMPLEMENTED CV_Error(Error::StsNotImplemented, "");
|
||||
CV_EXPORTS bool exists(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
CV_EXPORTS void remove_all(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
CV_EXPORTS bool createDirectory(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
CV_EXPORTS bool createDirectories(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
CV_EXPORTS cv::String getCacheDirectory(const char* /*sub_directory_name*/, const char* /*configuration_name = NULL*/) { NOT_IMPLEMENTED }
|
||||
cv::String canonical(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
bool exists(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
void remove_all(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
bool createDirectory(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
bool createDirectories(const cv::String& /*path*/) { NOT_IMPLEMENTED }
|
||||
cv::String getCacheDirectory(const char* /*sub_directory_name*/, const char* /*configuration_name = NULL*/) { NOT_IMPLEMENTED }
|
||||
#undef NOT_IMPLEMENTED
|
||||
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core/utils/logger.defines.hpp>
|
||||
#undef CV_LOG_STRIP_LEVEL
|
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
#include "opencv2/core/utils/filesystem.hpp"
|
||||
|
||||
namespace cv { namespace samples {
|
||||
|
||||
static cv::Ptr< std::vector<cv::String> > g_data_search_path;
|
||||
static cv::Ptr< std::vector<cv::String> > g_data_search_subdir;
|
||||
|
||||
static std::vector<cv::String>& _getDataSearchPath()
|
||||
{
|
||||
if (g_data_search_path.empty())
|
||||
g_data_search_path.reset(new std::vector<cv::String>());
|
||||
return *(g_data_search_path.get());
|
||||
}
|
||||
|
||||
static std::vector<cv::String>& _getDataSearchSubDirectory()
|
||||
{
|
||||
if (g_data_search_subdir.empty())
|
||||
{
|
||||
g_data_search_subdir.reset(new std::vector<cv::String>());
|
||||
g_data_search_subdir->push_back("samples/data");
|
||||
g_data_search_subdir->push_back("data");
|
||||
g_data_search_subdir->push_back("");
|
||||
}
|
||||
return *(g_data_search_subdir.get());
|
||||
}
|
||||
|
||||
|
||||
CV_EXPORTS void addSamplesDataSearchPath(const cv::String& path)
|
||||
{
|
||||
if (utils::fs::isDirectory(path))
|
||||
_getDataSearchPath().push_back(path);
|
||||
}
|
||||
CV_EXPORTS void addSamplesDataSearchSubDirectory(const cv::String& subdir)
|
||||
{
|
||||
_getDataSearchSubDirectory().push_back(subdir);
|
||||
}
|
||||
|
||||
cv::String findFile(const cv::String& relative_path, bool required, bool silentMode)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, cv::format("cv::samples::findFile('%s', %s)", relative_path.c_str(), required ? "true" : "false"));
|
||||
cv::String result = cv::utils::findDataFile(relative_path,
|
||||
"OPENCV_SAMPLES_DATA_PATH",
|
||||
&_getDataSearchPath(),
|
||||
&_getDataSearchSubDirectory());
|
||||
if (result != relative_path && !silentMode)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "cv::samples::findFile('" << relative_path << "') => '" << result << "'");
|
||||
}
|
||||
if (result.empty() && required)
|
||||
CV_Error(cv::Error::StsError, cv::format("OpenCV samples: Can't find required data file: %s", relative_path.c_str()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace
|
||||
Reference in New Issue
Block a user