diff --git a/.appveyor.yml b/.appveyor.yml index 7acf33a10..f0c62c275 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -106,3 +106,7 @@ build_script: test_script: #- cmd: ctest --build-config %Configuration% --parallel 4 --output-on-failure #- sh: ctest -j4 + +on_success: + - cmd: 7z a OpenMVS_x64.7z "C:\projects\openmvs\bin\bin\x64\%Configuration%\*.exe" "C:\projects\openmvs\bin\bin\x64\%Configuration%\*.dll" + - cmd: appveyor PushArtifact OpenMVS_x64.7z diff --git a/.gitignore b/.gitignore index b8bd0267b..3748365f0 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,13 @@ *.exe *.out *.app + +# Custom +*.tmp +.DS_Store +CMakeSettings.json +.vs/ +.idea/ +.vscode/ +bin/ +binaries/ diff --git a/README.md b/README.md index aed3fb5d4..ac9a7cfad 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ See the complete [documentation](https://github.com/cdcseacave/openMVS/wiki) on ## Build See the [building](https://github.com/cdcseacave/openMVS/wiki/Building) wiki page. Windows and Ubuntu x64 continuous integration status [![Build Status](https://ci.appveyor.com/api/projects/status/github/cdcseacave/openmvs?branch=master&svg=true)](https://ci.appveyor.com/project/cdcseacave/openmvs) +Automatic Windows x64 binary builds can be found for each commit on its Appveyor Artifacts page. ## Example diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index e16cc16ec..dfc4f88f8 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,4 +1,5 @@ # Add applications +ADD_SUBDIRECTORY(InterfaceCOLMAP) ADD_SUBDIRECTORY(InterfaceVisualSFM) ADD_SUBDIRECTORY(DensifyPointCloud) ADD_SUBDIRECTORY(ReconstructMesh) diff --git a/apps/InterfaceCOLMAP/CMakeLists.txt b/apps/InterfaceCOLMAP/CMakeLists.txt new file mode 100644 index 000000000..6c8ae3f3a --- /dev/null +++ b/apps/InterfaceCOLMAP/CMakeLists.txt @@ -0,0 +1,17 @@ +if(MSVC) + FILE(GLOB LIBRARY_FILES_C "*.cpp" "*.rc") +else() + FILE(GLOB LIBRARY_FILES_C "*.cpp") +endif() +FILE(GLOB LIBRARY_FILES_H "*.h" "*.inl") + +cxx_executable_with_flags_no_pch(InterfaceCOLMAP "Apps" "${cxx_default}" "MVS" ${LIBRARY_FILES_C} ${LIBRARY_FILES_H}) + +if(3Dnovator_USE_BREAKPAD AND BREAKPAD_FOUND) + target_link_libraries(InterfaceCOLMAP ${BREAKPAD_LIBS}) +endif() + +# Install +INSTALL(TARGETS InterfaceCOLMAP + EXPORT 3DnovatorTargets + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin) diff --git a/apps/InterfaceCOLMAP/InterfaceCOLMAP.cpp b/apps/InterfaceCOLMAP/InterfaceCOLMAP.cpp new file mode 100644 index 000000000..052004a2b --- /dev/null +++ b/apps/InterfaceCOLMAP/InterfaceCOLMAP.cpp @@ -0,0 +1,824 @@ +/* + * InterfaceCOLMAP.cpp + * + * Copyright (c) 2014-2018 SEACAVE + * + * Author(s): + * + * cDc + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * + * Additional Terms: + * + * You are required to preserve legal notices and author attributions in + * that material or in the Appropriate Legal Notices displayed by works + * containing it. + */ + +#include "../../libs/MVS/Common.h" +#include "../../libs/MVS/Scene.h" +#define _USE_OPENCV +#include "../../libs/MVS/Interface.h" +#include + +using namespace MVS; + + +// D E F I N E S /////////////////////////////////////////////////// + +#define APPNAME _T("InterfaceCOLMAP") +#define MVS_EXT _T(".mvs") +#define COLMAP_IMAGES_FOLDER _T("images/") +#define COLMAP_SPARSE_FOLDER _T("sparse/") +#define COLMAP_CAMERAS COLMAP_SPARSE_FOLDER _T("cameras.txt") +#define COLMAP_IMAGES COLMAP_SPARSE_FOLDER _T("images.txt") +#define COLMAP_POINTS COLMAP_SPARSE_FOLDER _T("points3D.txt") +#define COLMAP_DENSE_POINTS _T("fused.ply") +#define COLMAP_DENSE_POINTS_VISIBILITY _T("fused.ply.vis") +#define COLMAP_STEREO_FOLDER _T("stereo/") +#define COLMAP_FUSION COLMAP_STEREO_FOLDER _T("fusion.cfg") +#define COLMAP_PATCHMATCH COLMAP_STEREO_FOLDER _T("patch-match.cfg") +#define COLMAP_STEREO_CONSISTENCYGRAPHS_FOLDER COLMAP_STEREO_FOLDER _T("consistency_graphs/") +#define COLMAP_STEREO_DEPTHMAPS_FOLDER COLMAP_STEREO_FOLDER _T("depth_maps/") +#define COLMAP_STEREO_NORMALMAPS_FOLDER COLMAP_STEREO_FOLDER _T("normal_maps/") + + +// S T R U C T S /////////////////////////////////////////////////// + +namespace OPT { +bool b3Dnovator2COLMAP; // conversion direction +bool bNormalizeIntrinsics; +String strInputFileName; +String strOutputFileName; +String strImageFolder; +unsigned nArchiveType; +int nProcessPriority; +unsigned nMaxThreads; +String strConfigFileName; +boost::program_options::variables_map vm; +} // namespace OPT + +// initialize and parse the command line parameters +bool Initialize(size_t argc, LPCTSTR* argv) +{ + // initialize log and console + OPEN_LOG(); + OPEN_LOGCONSOLE(); + + // group of options allowed only on command line + boost::program_options::options_description generic("Generic options"); + generic.add_options() + ("help,h", "produce this help message") + ("working-folder,w", boost::program_options::value(&WORKING_FOLDER), "working directory (default current directory)") + ("config-file,c", boost::program_options::value(&OPT::strConfigFileName)->default_value(APPNAME _T(".cfg")), "file name containing program options") + ("archive-type", boost::program_options::value(&OPT::nArchiveType)->default_value(2), "project archive type: 0-text, 1-binary, 2-compressed binary") + ("process-priority", boost::program_options::value(&OPT::nProcessPriority)->default_value(-1), "process priority (below normal by default)") + ("max-threads", boost::program_options::value(&OPT::nMaxThreads)->default_value(0), "maximum number of threads (0 for using all available cores)") + #if TD_VERBOSE != TD_VERBOSE_OFF + ("verbosity,v", boost::program_options::value(&g_nVerbosityLevel)->default_value( + #if TD_VERBOSE == TD_VERBOSE_DEBUG + 3 + #else + 2 + #endif + ), "verbosity level") + #endif + ; + + // group of options allowed both on command line and in config file + boost::program_options::options_description config("Main options"); + config.add_options() + ("input-file,i", boost::program_options::value(&OPT::strInputFileName), "input COLMAP folder containing cameras, images and points files OR input MVS project file") + ("output-file,o", boost::program_options::value(&OPT::strOutputFileName), "output filename for storing the MVS project") + ("image-folder", boost::program_options::value(&OPT::strImageFolder)->default_value(COLMAP_IMAGES_FOLDER), "folder to the undistorted images") + ("normalize,f", boost::program_options::value(&OPT::bNormalizeIntrinsics)->default_value(true), "normalize intrinsics while exporting to MVS format") + ; + + boost::program_options::options_description cmdline_options; + cmdline_options.add(generic).add(config); + + boost::program_options::options_description config_file_options; + config_file_options.add(config); + + boost::program_options::positional_options_description p; + p.add("input-file", -1); + + try { + // parse command line options + boost::program_options::store(boost::program_options::command_line_parser((int)argc, argv).options(cmdline_options).positional(p).run(), OPT::vm); + boost::program_options::notify(OPT::vm); + INIT_WORKING_FOLDER; + // parse configuration file + std::ifstream ifs(MAKE_PATH_SAFE(OPT::strConfigFileName)); + if (ifs) { + boost::program_options::store(parse_config_file(ifs, config_file_options), OPT::vm); + boost::program_options::notify(OPT::vm); + } + } + catch (const std::exception& e) { + LOG(e.what()); + return false; + } + + // initialize the log file + OPEN_LOGFILE(MAKE_PATH(APPNAME _T("-")+Util::getUniqueName(0)+_T(".log"))); + + // print application details: version and command line + Util::LogBuild(); + LOG(_T("Command line: ") APPNAME _T("%s"), Util::CommandLineToString(argc, argv).c_str()); + + // validate input + Util::ensureValidPath(OPT::strInputFileName); + const String strInputFileNameExt(Util::getFileExt(OPT::strInputFileName).ToLower()); + OPT::b3Dnovator2COLMAP = (strInputFileNameExt == MVS_EXT); + const bool bInvalidCommand(OPT::strInputFileName.empty()); + if (OPT::vm.count("help") || bInvalidCommand) { + boost::program_options::options_description visible("Available options"); + visible.add(generic).add(config); + GET_LOG() << _T("\n" + "Import/export 3D reconstruction from/to COLMAP format as TXT (the only documented format).\n" + "In order to import a scene, run COLMAP SfM and next undistort the images (only PINHOLE\n" + "camera model supported for the moment); and convert the BIN scene to TXT by importing in\n" + "COLMAP the sparse scene stored in 'dense' folder and exporting it as TXT.\n" + "\n") + << visible; + } + if (bInvalidCommand) + return false; + + // initialize optional options + Util::ensureValidFolderPath(OPT::strImageFolder); + Util::ensureValidPath(OPT::strOutputFileName); + if (OPT::b3Dnovator2COLMAP) { + if (OPT::strOutputFileName.empty()) + OPT::strOutputFileName = Util::getFilePath(OPT::strInputFileName); + } else { + Util::ensureFolderSlash(OPT::strInputFileName); + if (OPT::strOutputFileName.empty()) + OPT::strOutputFileName = OPT::strInputFileName + _T("scene") MVS_EXT; + else + OPT::strImageFolder = Util::getRelativePath(Util::getFilePath(OPT::strOutputFileName), OPT::strInputFileName+OPT::strImageFolder); + } + + // initialize global options + Process::setCurrentProcessPriority((Process::Priority)OPT::nProcessPriority); + #ifdef _USE_OPENMP + if (OPT::nMaxThreads != 0) + omp_set_num_threads(OPT::nMaxThreads); + #endif + + #ifdef _USE_BREAKPAD + // start memory dumper + MiniDumper::Create(APPNAME, WORKING_FOLDER); + #endif + return true; +} + +// finalize application instance +void Finalize() +{ + #if TD_VERBOSE != TD_VERBOSE_OFF + // print memory statistics + Util::LogMemoryInfo(); + #endif + + CLOSE_LOGFILE(); + CLOSE_LOGCONSOLE(); + CLOSE_LOG(); +} + +namespace COLMAP { +// tools +bool NextLine(std::istream& stream, std::istringstream& in, bool bIgnoreEmpty=true) { + String line; + do { + std::getline(stream, line); + Util::strTrim(line, _T(" ")); + if (stream.fail()) + return false; + } while (((bIgnoreEmpty && line.empty()) || line[0u] == '#') && stream.good()); + in.clear(); + in.str(line); + return true; +} +// structure describing a camera +struct Camera { + uint32_t ID; // ID of the camera + String model; // camera model name + uint32_t width, height; // camera resolution + std::vector params; // camera parameters + + Camera() {} + Camera(uint32_t _ID) : ID(_ID) {} + bool operator < (const Camera& rhs) const { return ID < rhs.ID; } + + struct CameraHash { + size_t operator()(const Camera& camera) const { + const size_t h1(std::hash()(camera.model)); + const size_t h2(std::hash()(camera.width)); + const size_t h3(std::hash()(camera.height)); + size_t h(h1 ^ ((h2 ^ (h3 << 1)) << 1)); + for (REAL p: camera.params) + h = std::hash()(p) ^ (h << 1); + return h; + } + }; + struct CameraEqualTo { + bool operator()(const Camera& _Left, const Camera& _Right) const { + return _Left.model == _Right.model && + _Left.width == _Right.width && _Left.height == _Right.height && + _Left.params == _Right.params; + } + }; + + // Camera list with one line of data per camera: + // CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[] + bool Read(std::istream& stream) { + std::istringstream in; + if (!NextLine(stream, in)) + return false; + in >> ID >> model >> width >> height; + if (in.fail()) + return false; + if (model != _T("PINHOLE")) + return false; + params.resize(4); + in >> params[0] >> params[1] >> params[2] >> params[3]; + return !in.fail(); + } + bool Write(std::ostream& out) const { + out << ID+1 << _T(" ") << model << _T(" ") << width << _T(" ") << height; + if (out.fail()) + return false; + for (REAL param: params) { + out << _T(" ") << param; + if (out.fail()) + return false; + } + out << std::endl; + return true; + } +}; +typedef std::vector Cameras; +// structure describing an image +struct Image { + struct Proj { + Eigen::Vector2f p; + uint32_t idPoint; + }; + uint32_t ID; // ID of the image + Eigen::Quaterniond q; // rotation + Eigen::Vector3d t; // translation + uint32_t idCamera; // ID of the associated camera + String name; // image file name + std::vector projs; // known image projections + + Image() {} + Image(uint32_t _ID) : ID(_ID) {} + bool operator < (const Image& rhs) const { return ID < rhs.ID; } + + // Image list with two lines of data per image: + // IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME + // POINTS2D[] as (X, Y, POINT3D_ID) + bool Read(std::istream& stream) { + std::istringstream in; + if (!NextLine(stream, in)) + return false; + in >> ID + >> q.w() >> q.x() >> q.y() >> q.z() + >> t(0) >> t(1) >> t(2) + >> idCamera >> name; + if (in.fail()) + return false; + Util::ensureValidPath(name); + if (!NextLine(stream, in, false)) + return false; + projs.clear(); + while (true) { + Proj proj; + in >> proj.p(0) >> proj.p(1) >> (int&)proj.idPoint; + if (in.fail()) + break; + projs.push_back(proj); + } + return true; + } + bool Write(std::ostream& out) const { + ASSERT(!projs.empty()); + out << ID+1 << _T(" ") + << q.w() << _T(" ") << q.x() << _T(" ") << q.y() << _T(" ") << q.z() << _T(" ") + << t(0) << _T(" ") << t(1) << _T(" ") << t(2) << _T(" ") + << idCamera+1 << _T(" ") << name + << std::endl; + for (const Proj& proj: projs) { + out << proj.p(0) << _T(" ") << proj.p(1) << _T(" ") << (int)proj.idPoint+1 << _T(" "); + if (out.fail()) + return false; + } + out << std::endl; + return !out.fail(); + } +}; +typedef std::vector Images; +// structure describing a 3D point +struct Point { + struct Track { + uint32_t idImage; + uint32_t idProj; + }; + uint32_t ID; // ID of the point + Interface::Pos3f p; // position + Interface::Col3 c; // BGR color + float e; // error + std::vector tracks; // point track + + Point() {} + Point(uint32_t _ID) : ID(_ID) {} + bool operator < (const Image& rhs) const { return ID < rhs.ID; } + + // 3D point list with one line of data per point: + // POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX) + bool Read(std::istream& stream) { + std::istringstream in; + if (!NextLine(stream, in)) + return false; + int r,g,b; + in >> ID + >> p.x >> p.y >> p.z + >> r >> g >> b + >> e; + c.x = CLAMP(b,0,255); + c.y = CLAMP(g,0,255); + c.z = CLAMP(r,0,255); + if (in.fail()) + return false; + tracks.clear(); + while (true) { + Track track; + in >> track.idImage >> track.idProj; + if (in.fail()) + break; + tracks.push_back(track); + } + return !tracks.empty(); + } + bool Write(std::ostream& out) const { + ASSERT(!tracks.empty()); + const int r(c.z),g(c.y),b(c.x); + out << ID+1 << _T(" ") + << p.x << _T(" ") << p.y << _T(" ") << p.z << _T(" ") + << r << _T(" ") << g << _T(" ") << b << _T(" ") + << e << _T(" "); + for (const Track& track: tracks) { + out << track.idImage+1 << _T(" ") << track.idProj+1 << _T(" "); + if (out.fail()) + return false; + } + out << std::endl; + return !out.fail(); + } +}; +typedef std::vector Points; +} // namespace COLMAP + +typedef Eigen::Matrix EMat33d; +typedef Eigen::Matrix EVec3d; + +bool ImportScene(const String& strFolder, Interface& scene) +{ + // read camera list + typedef std::unordered_map CamerasMap; + CamerasMap mapCameras; + { + const String filenameCameras(strFolder+COLMAP_CAMERAS); + LOG_OUT() << "Reading cameras: " << filenameCameras << std::endl; + std::ifstream file(filenameCameras); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenameCameras.c_str()); + return false; + } + typedef std::unordered_set CamerasSet; + CamerasSet setCameras; + { + COLMAP::Camera camera; + while (file.good() && camera.Read(file)) + setCameras.emplace(camera); + } + mapCameras.reserve(setCameras.size()); + for (const COLMAP::Camera& colmapCamera: setCameras) { + mapCameras[colmapCamera.ID] = (uint32_t)scene.platforms.size(); + Interface::Platform platform; + platform.name = String::FormatString(_T("platform%03u"), colmapCamera.ID); // only one camera per platform supported + Interface::Platform::Camera camera; + camera.name = colmapCamera.model; + camera.K = Interface::Mat33d::eye(); + camera.K(0,0) = colmapCamera.params[0]; + camera.K(1,1) = colmapCamera.params[1]; + camera.K(0,2) = colmapCamera.params[2]; + camera.K(1,2) = colmapCamera.params[3]; + camera.R = Interface::Mat33d::eye(); + camera.C = Interface::Pos3d(0,0,0); + if (OPT::bNormalizeIntrinsics) { + // normalize camera intrinsics + const double fScale(1.0/Camera::GetNormalizationScale(colmapCamera.width, colmapCamera.height)); + camera.K(0,0) *= fScale; + camera.K(1,1) *= fScale; + camera.K(0,2) *= fScale; + camera.K(1,2) *= fScale; + } else { + camera.width = colmapCamera.width; + camera.height = colmapCamera.height; + } + platform.cameras.push_back(camera); + scene.platforms.push_back(platform); + } + } + + // read images list + typedef std::map ImagesMap; + ImagesMap mapImages; + { + const String filenameImages(strFolder+COLMAP_IMAGES); + LOG_OUT() << "Reading images: " << filenameImages << std::endl; + std::ifstream file(filenameImages); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenameImages.c_str()); + return false; + } + { + COLMAP::Image image; + while (file.good() && image.Read(file)) + mapImages[image]; + } + for (ImagesMap::value_type& it: mapImages) { + it.second = (uint32_t)scene.images.size(); + Interface::Platform::Pose pose; + Eigen::Map(pose.R.val) = it.first.q.toRotationMatrix(); + EnsureRotationMatrix((Matrix3x3d&)pose.R); + Eigen::Map(&pose.C.x) = -(it.first.q.inverse() * it.first.t); + Interface::Image image; + image.name = OPT::strImageFolder+it.first.name; + image.platformID = mapCameras.at(it.first.idCamera); + image.cameraID = 0; + Interface::Platform& platform = scene.platforms[image.platformID]; + image.poseID = (uint32_t)platform.poses.size(); + platform.poses.push_back(pose); + scene.images.push_back(image); + } + } + + // read points list + const String filenameDensePoints(strFolder+COLMAP_DENSE_POINTS); + const String filenameDenseVisPoints(strFolder+COLMAP_DENSE_POINTS_VISIBILITY); + if (!File::access(filenameDensePoints) || !File::access(filenameDenseVisPoints)) { + // parse sparse point-cloud + const String filenamePoints(strFolder+COLMAP_POINTS); + LOG_OUT() << "Reading points: " << filenamePoints << std::endl; + std::ifstream file(filenamePoints); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenamePoints.c_str()); + return false; + } + COLMAP::Point point; + while (file.good() && point.Read(file)) { + Interface::Vertex vertex; + vertex.X = point.p; + for (const COLMAP::Point::Track& track: point.tracks) { + Interface::Vertex::View view; + view.imageID = mapImages.at(COLMAP::Image(track.idImage)); + view.confidence = 0; + vertex.views.emplace_back(view); + } + std::sort(vertex.views.begin(), vertex.views.end(), + [](const Interface::Vertex::View& view0, const Interface::Vertex::View& view1) { return view0.imageID < view1.imageID; }); + scene.vertices.emplace_back(std::move(vertex)); + scene.verticesColor.emplace_back(Interface::Color{point.c}); + } + } else { + // parse dense point-cloud + LOG_OUT() << "Reading points: " << filenameDensePoints << " and " << filenameDenseVisPoints << std::endl; + PointCloud pointcloud; + if (!pointcloud.Load(filenameDensePoints)) { + VERBOSE("error: unable to open file '%s'", filenameDensePoints.c_str()); + return false; + } + File file(filenameDenseVisPoints, File::READ, File::OPEN); + if (!file.isOpen()) { + VERBOSE("error: unable to open file '%s'", filenameDenseVisPoints.c_str()); + return false; + } + uint64_t numPoints(0); + file.read(&numPoints, sizeof(uint64_t)); + if (pointcloud.GetSize() != numPoints) { + VERBOSE("error: point-cloud and visibility have different size"); + return false; + } + for (size_t i=0; iname.c_str()))); + if (ptrImage == NULL) + return false; + cam.width = ptrImage->GetWidth(); + cam.height = ptrImage->GetHeight(); + // denormalize camera intrinsics + const double fScale(MVS::Camera::GetNormalizationScale(cam.width, cam.height)); + cam.params[0] *= fScale; + cam.params[1] *= fScale; + cam.params[2] *= fScale; + cam.params[3] *= fScale; + } else { + cam.width = camera.width; + cam.height = camera.height; + } + if (!cam.Write(file)) + return false; + KMatrix& K = Ks.AddEmpty(); + K = KMatrix::IDENTITY; + K(0,0) = cam.params[0]; + K(1,1) = cam.params[1]; + K(0,2) = cam.params[2]; + K(1,2) = cam.params[3]; + } + } + + // create images list + COLMAP::Images images; + CameraArr cameras; + { + images.resize(scene.images.size()); + cameras.resize(scene.images.size()); + for (uint32_t ID=0; ID<(uint32_t)scene.images.size(); ++ID) { + const Interface::Image& image = scene.images[ID]; + if (image.poseID == NO_ID) + continue; + const Interface::Platform& platform = scene.platforms[image.platformID]; + const Interface::Platform::Pose& pose = platform.poses[image.poseID]; + ASSERT(image.cameraID == 0); + COLMAP::Image& img = images[ID]; + img.ID = ID; + img.q = Eigen::Quaterniond(Eigen::Map(pose.R.val)); + img.t = -(img.q * Eigen::Map(&pose.C.x)); + img.idCamera = image.platformID; + img.name = MAKE_PATH_REL(OPT::strImageFolder, image.name); + Camera& camera = cameras[ID]; + camera.K = Ks[image.platformID]; + camera.R = pose.R; + camera.C = pose.C; + camera.ComposeP(); + } + } + + // write points list + { + const String filenamePoints(strFolder+COLMAP_POINTS); + LOG_OUT() << "Writing points: " << filenamePoints << std::endl; + std::ofstream file(filenamePoints); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenamePoints.c_str()); + return false; + } + file << _T("# 3D point list with one line of data per point:") << std::endl; + file << _T("# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)") << std::endl; + for (uint32_t ID=0; ID<(uint32_t)scene.vertices.size(); ++ID) { + const Interface::Vertex& vertex = scene.vertices[ID]; + COLMAP::Point point; + point.ID = ID; + point.p = vertex.X; + for (const Interface::Vertex::View& view: vertex.views) { + COLMAP::Image& img = images[view.imageID]; + COLMAP::Point::Track track; + track.idImage = view.imageID; + track.idProj = (uint32_t)img.projs.size(); + point.tracks.push_back(track); + COLMAP::Image::Proj proj; + proj.idPoint = ID; + const Point3 X(vertex.X); + ProjectVertex_3x4_3_2(cameras[view.imageID].P.val, X.ptr(), proj.p.data()); + img.projs.push_back(proj); + } + point.c = scene.verticesColor.empty() ? Interface::Col3(255,255,255) : scene.verticesColor[ID].c; + point.e = 0; + if (!point.Write(file)) + return false; + } + } + + // write images list + { + const String filenameImages(strFolder+COLMAP_IMAGES); + LOG_OUT() << "Writing images: " << filenameImages << std::endl; + std::ofstream file(filenameImages); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenameImages.c_str()); + return false; + } + file << _T("# Image list with two lines of data per image:") << std::endl; + file << _T("# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME") << std::endl; + file << _T("# POINTS2D[] as (X, Y, POINT3D_ID)") << std::endl; + for (const COLMAP::Image& img: images) { + if (!img.projs.empty() && !img.Write(file)) + return false; + } + } + + Util::ensureFolder(strFolder+COLMAP_STEREO_FOLDER); + + // write fusion list + { + const String filenameFusion(strFolder+COLMAP_FUSION); + LOG_OUT() << "Writing fusion configuration: " << filenameFusion << std::endl; + std::ofstream file(filenameFusion); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenameFusion.c_str()); + return false; + } + for (const COLMAP::Image& img: images) { + if (img.projs.empty()) + continue; + file << img.name << std::endl; + if (file.fail()) + return false; + } + } + + // write patch-match list + { + const String filenameFusion(strFolder+COLMAP_PATCHMATCH); + LOG_OUT() << "Writing patch-match configuration: " << filenameFusion << std::endl; + std::ofstream file(filenameFusion); + if (!file.good()) { + VERBOSE("error: unable to open file '%s'", filenameFusion.c_str()); + return false; + } + for (const COLMAP::Image& img: images) { + if (img.projs.empty()) + continue; + file << img.name << std::endl; + if (file.fail()) + return false; + file << _T("__auto__, 20") << std::endl; + if (file.fail()) + return false; + } + } + + Util::ensureFolder(strFolder+COLMAP_STEREO_CONSISTENCYGRAPHS_FOLDER); + Util::ensureFolder(strFolder+COLMAP_STEREO_DEPTHMAPS_FOLDER); + Util::ensureFolder(strFolder+COLMAP_STEREO_NORMALMAPS_FOLDER); + return true; +} + + +// export image poses in log format +// see: http://redwood-data.org/indoor/fileformat.html +// to support: https://www.tanksandtemples.org/tutorial +bool ExportImagesLog(const String& fileName, const Interface& scene) +{ + LOG_OUT() << "Writing poses: " << fileName << std::endl; + Util::ensureFolder(fileName); + std::ofstream out(fileName); + if (!out.good()) { + VERBOSE("error: unable to open file '%s'", fileName.c_str()); + return false; + } + out << std::setprecision(12); + for (uint32_t ID=0; ID<(uint32_t)scene.images.size(); ++ID) { + const Interface::Image& image = scene.images[ID]; + Eigen::Matrix3d R(Eigen::Matrix3d::Identity()); + Eigen::Vector3d t(Eigen::Vector3d::Zero()); + if (image.poseID != NO_ID) { + const Interface::Platform& platform = scene.platforms[image.platformID]; + const Interface::Platform::Pose& pose = platform.poses[image.poseID]; + R = Eigen::Map(pose.R.val).transpose(); + t = Eigen::Map(&pose.C.x); + } + Eigen::Matrix4d T(Eigen::Matrix4d::Identity()); + T.topLeftCorner<3,3>() = R; + T.topRightCorner<3,1>() = t; + out << ID << _T(" ") << ID << _T(" ") << 0 << _T("\n"); + out << T(0,0) << _T(" ") << T(0,1) << _T(" ") << T(0,2) << _T(" ") << T(0,3) << _T("\n"); + out << T(1,0) << _T(" ") << T(1,1) << _T(" ") << T(1,2) << _T(" ") << T(1,3) << _T("\n"); + out << T(2,0) << _T(" ") << T(2,1) << _T(" ") << T(2,2) << _T(" ") << T(2,3) << _T("\n"); + out << T(3,0) << _T(" ") << T(3,1) << _T(" ") << T(3,2) << _T(" ") << T(3,3) << _T("\n"); + } + return !out.fail(); +} + +int main(int argc, LPCTSTR* argv) +{ + #ifdef _DEBUGINFO + // set _crtBreakAlloc index to stop in at allocation + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);// | _CRTDBG_CHECK_ALWAYS_DF); + #endif + + if (!Initialize(argc, argv)) + return EXIT_FAILURE; + + TD_TIMER_START(); + + if (OPT::b3Dnovator2COLMAP) { + // read MVS input data + Interface scene; + if (!ARCHIVE::SerializeLoad(scene, MAKE_PATH_SAFE(OPT::strInputFileName))) + return EXIT_FAILURE; + if (Util::getFileExt(OPT::strOutputFileName) == _T(".log")) { + // write poses in log format + ExportImagesLog(MAKE_PATH_SAFE(OPT::strOutputFileName), scene); + } else { + // write COLMAP input data + Util::ensureFolderSlash(OPT::strOutputFileName); + ExportScene(MAKE_PATH_SAFE(OPT::strOutputFileName), scene); + } + VERBOSE("Input data exported: %u images & %u vertices (%s)", scene.images.size(), scene.vertices.size(), TD_TIMER_GET_FMT().c_str()); + } else { + // read COLMAP input data + Interface scene; + if (!ImportScene(MAKE_PATH_SAFE(OPT::strInputFileName), scene)) + return EXIT_FAILURE; + // write MVS input data + Util::ensureFolder(Util::getFullPath(MAKE_PATH_FULL(WORKING_FOLDER_FULL, OPT::strOutputFileName))); + if (!ARCHIVE::SerializeSave(scene, MAKE_PATH_SAFE(OPT::strOutputFileName), (uint32_t)OPT::bNormalizeIntrinsics?0:1)) + return EXIT_FAILURE; + VERBOSE("Exported data: %u images & %u vertices (%s)", scene.images.size(), scene.vertices.size(), TD_TIMER_GET_FMT().c_str()); + } + + Finalize(); + return EXIT_SUCCESS; +} +/*----------------------------------------------------------------*/ diff --git a/apps/InterfaceVisualSFM/InterfaceVisualSFM.cpp b/apps/InterfaceVisualSFM/InterfaceVisualSFM.cpp index 1b0a131ae..bfb563e66 100644 --- a/apps/InterfaceVisualSFM/InterfaceVisualSFM.cpp +++ b/apps/InterfaceVisualSFM/InterfaceVisualSFM.cpp @@ -374,7 +374,7 @@ int main(int argc, LPCTSTR* argv) #pragma omp flush (bAbort) continue; #else - return false; + return EXIT_FAILURE; #endif } MVS::UndistortImage(imageData.camera, cameraNVM.GetNormalizedMeasurementDistortion(), imageData.image, imageData.image); @@ -386,7 +386,7 @@ int main(int argc, LPCTSTR* argv) #pragma omp flush (bAbort) continue; #else - return false; + return EXIT_FAILURE; #endif } imageData.ReleaseImage(); diff --git a/apps/ReconstructMesh/ReconstructMesh.cpp b/apps/ReconstructMesh/ReconstructMesh.cpp index 7a58c670b..14d325e01 100644 --- a/apps/ReconstructMesh/ReconstructMesh.cpp +++ b/apps/ReconstructMesh/ReconstructMesh.cpp @@ -279,7 +279,7 @@ int main(int argc, LPCTSTR* argv) #if TD_VERBOSE != TD_VERBOSE_OFF if (VERBOSITY_LEVEL > 2) { // dump raw mesh - scene.mesh.Save(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName)+_T("_raw")+OPT::strExportType)); + scene.mesh.Save(MAKE_PATH_SAFE(Util::getFileFullName(OPT::strOutputFileName))+_T("_raw")+OPT::strExportType); } #endif } else { diff --git a/apps/Viewer/Camera.cpp b/apps/Viewer/Camera.cpp index b93460eb1..b217c2d6b 100644 --- a/apps/Viewer/Camera.cpp +++ b/apps/Viewer/Camera.cpp @@ -103,12 +103,30 @@ void Camera::SetFOV(double _fov) Eigen::Vector3d Camera::GetPosition() const { - const Eigen::Matrix3d r(rotation.toRotationMatrix()); + const Eigen::Matrix3d R(rotation.toRotationMatrix()); const Eigen::Vector3d eye(0, 0, dist); - return r * eye + center; + return R * eye + center; } -void Camera::GetLookAt(Eigen::Vector3d& _eye, Eigen::Vector3d& _center, Eigen::Vector3d& _up) +Eigen::Matrix4d Camera::GetLookAt() const +{ + const Eigen::Matrix3d R(rotation.toRotationMatrix()); + const Eigen::Vector3d eye(R.col(2) * dist + center); + const Eigen::Vector3d up(R.col(1)); + + const Eigen::Vector3d n((center-eye).normalized()); + const Eigen::Vector3d s(n.cross(up)); + const Eigen::Vector3d v(s.cross(n)); + + Eigen::Matrix4d m; + m << + s(0), s(1), s(2), -eye.dot(s), + v(0), v(1), v(2), -eye.dot(v), + -n(0), -n(1), -n(2), eye.dot(n), + 0.0, 0.0, 0.0, 1.0; + return m; +} +void Camera::GetLookAt(Eigen::Vector3d& _eye, Eigen::Vector3d& _center, Eigen::Vector3d& _up) const { const Eigen::Matrix3d R(rotation.toRotationMatrix()); const Eigen::Vector3d eye(0, 0, dist); diff --git a/apps/Viewer/Camera.h b/apps/Viewer/Camera.h index a152936e9..37d982386 100644 --- a/apps/Viewer/Camera.h +++ b/apps/Viewer/Camera.h @@ -46,6 +46,8 @@ namespace VIEWER { class Camera { public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + AABB3d box; int width, height; Eigen::Quaterniond rotation; @@ -66,7 +68,8 @@ class Camera void SetFOV(double _fov); Eigen::Vector3d GetPosition() const; - void GetLookAt(Eigen::Vector3d& eye, Eigen::Vector3d& center, Eigen::Vector3d& up); + Eigen::Matrix4d GetLookAt() const; + void GetLookAt(Eigen::Vector3d& eye, Eigen::Vector3d& center, Eigen::Vector3d& up) const; void Rotate(const Eigen::Vector2d& pos, const Eigen::Vector2d& prevPos); protected: diff --git a/apps/Viewer/Image.cpp b/apps/Viewer/Image.cpp index a46cd040d..4268196e9 100644 --- a/apps/Viewer/Image.cpp +++ b/apps/Viewer/Image.cpp @@ -77,6 +77,10 @@ void Image::AssignImage(cv::InputArray img) { ASSERT(IsImageLoading()); ImagePtrInt pImg(new cv::Mat(img.getMat())); + if (pImg.pImage->cols%4 != 0) { + // make sure the width is multiple of 4 (seems to be an OpenGL limitation) + cv::resize(*pImg.pImage, *pImg.pImage, cv::Size((pImg.pImage->cols/4)*4, pImg.pImage->rows), 0, 0, cv::INTER_AREA); + } Thread::safeExchange(pImage.ptr, pImg.ptr); } bool Image::TransferImage() diff --git a/apps/Viewer/Scene.cpp b/apps/Viewer/Scene.cpp index 7684b7793..703ce2625 100644 --- a/apps/Viewer/Scene.cpp +++ b/apps/Viewer/Scene.cpp @@ -349,7 +349,7 @@ bool Scene::Open(LPCTSTR fileName, LPCTSTR meshFileName) // load the scene WORKING_FOLDER = Util::getFilePath(fileName); INIT_WORKING_FOLDER; - if (!scene.Load(fileName)) + if (!scene.Load(fileName, true)) return false; if (meshFileName) { // load given mesh diff --git a/apps/Viewer/Window.cpp b/apps/Viewer/Window.cpp index 2e4fc368c..f39784f61 100644 --- a/apps/Viewer/Window.cpp +++ b/apps/Viewer/Window.cpp @@ -124,7 +124,6 @@ void Window::Reset() void Window::UpdateView(const ImageArr& images, const MVS::ImageArr& sceneImages) { glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); if (camera->prevCamID != camera->currentCamID && camera->currentCamID != NO_ID) { // enable camera view mode // apply current camera transform @@ -132,13 +131,12 @@ void Window::UpdateView(const ImageArr& images, const MVS::ImageArr& sceneImages const MVS::Image& imageData = sceneImages[image.idx]; const MVS::Camera& camera = imageData.camera; const Eigen::Matrix4d trans(TransW2L((const Matrix3x3::EMat)camera.R, camera.GetT())); - glMultMatrixf((GLfloat*)gs_convert); + glLoadMatrixf((GLfloat*)gs_convert); glMultMatrixd((GLdouble*)trans.data()); } else { // apply view point transform - Eigen::Vector3d eye, center, up; - camera->GetLookAt(eye, center, up); - gluLookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z()); + const Eigen::Matrix4d trans(camera->GetLookAt()); + glLoadMatrixd((GLdouble*)trans.data()); } } @@ -165,7 +163,7 @@ void Window::Resize(GLFWwindow* window, int width, int height) g_mapWindows[window]->Resize(width, height); } -void Window::Key(int k, int scancode, int action, int mod) +void Window::Key(int k, int /*scancode*/, int action, int mod) { switch (k) { case GLFW_KEY_ESCAPE: @@ -278,7 +276,7 @@ void Window::Key(GLFWwindow* window, int k, int scancode, int action, int mod) g_mapWindows[window]->Key(k, scancode, action, mod); } -void Window::MouseButton(int button, int action, int mods) +void Window::MouseButton(int button, int action, int /*mods*/) { if (clbkRayScene != NULL && button == GLFW_MOUSE_BUTTON_LEFT) { typedef Eigen::Matrix Mat4; @@ -305,7 +303,7 @@ void Window::MouseButton(GLFWwindow* window, int button, int action, int mods) g_mapWindows[window]->MouseButton(button, action, mods); } -void Window::Scroll(double xoffset, double yoffset) +void Window::Scroll(double /*xoffset*/, double yoffset) { camera->dist *= (yoffset>0 ? POW(1.11,yoffset) : POW(0.9,-yoffset)); } diff --git a/build/Modules/FindCGAL.cmake b/build/Modules/FindCGAL.cmake index b3895e0d4..325d36d49 100644 --- a/build/Modules/FindCGAL.cmake +++ b/build/Modules/FindCGAL.cmake @@ -7,7 +7,7 @@ # CGAL_LIBS - CGAL libraries # CGAL_VERSION - MAJOR.MINOR #---------------------------------------------------------- - + set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) if(NOT CGAL_DIR) @@ -21,8 +21,9 @@ if(NOT CGAL_DIR) # Construct a set of paths relative to the system search path. set(CGAL_DIR_SEARCH "") foreach(dir ${CGAL_DIR_SEARCH2}) - list(APPEND CGAL_DIR_SEARCH "${dir}/../lib/CGAL") + set(CGAL_DIR_SEARCH ${CGAL_DIR_SEARCH} ${dir}/../lib/CGAL) endforeach() + set(CGAL_DIR_SEARCH ${CGAL_DIR_SEARCH} "lib" "lib64") # # Look for an installation or build tree. @@ -35,7 +36,7 @@ if(NOT CGAL_DIR) ${CGAL_DIR_SEARCH} # Look in standard UNIX install locations. - "/usr" "/usr/local" "/usr/lib" "/usr/lib/x86_64-linux-gnu/cmake" + PATHS "/usr" "/usr/local" "/usr/share" "/usr/local/share" "/usr/lib/cmake" "/usr/local/lib/cmake" "/usr/include" "/usr/lib/x86_64-linux-gnu/cmake" # Read from the CMakeSetup registry entries. It is likely that # CGAL will have been recently built. diff --git a/build/Utils.cmake b/build/Utils.cmake index 0cec41664..6c33c1f74 100644 --- a/build/Utils.cmake +++ b/build/Utils.cmake @@ -67,20 +67,22 @@ macro(GetOperatingSystemArchitectureBitness) endif() # Detect Microsoft compiler: + set(MSVC64 0) if(CMAKE_CL_64) set(MSVC64 1) endif() - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CLANG 0) + if(CMAKE_C_COMPILER_ID MATCHES "^(Apple)?Clang$") set(CLANG 1) if(NOT APPLE) - set(CMAKE_COMPILER_IS_GNUCXX 1) + set(CMAKE_COMPILER_IS_GNUCC 1) endif() endif() - if(CMAKE_C_COMPILER_ID STREQUAL "Clang") - set(CLANG 1) + if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") + math(EXPR CLANG "${CLANG}+2") if(NOT APPLE) - set(CMAKE_COMPILER_IS_GNUCC 1) + set(CMAKE_COMPILER_IS_GNUCXX 1) endif() endif() @@ -100,21 +102,22 @@ macro(GetOperatingSystemArchitectureBitness) elseif(__INTEL_COMPILER) set(FLG_ICC __INTEL_COMPILER) elseif(CMAKE_C_COMPILER MATCHES "icc") - set(FLG_ICC icc_matches_c_compiler) + set(FLG_ICC __ICC_C_COMPILER) endif() endif() if(MSVC AND CMAKE_C_COMPILER MATCHES "icc") - set(FLG_ICC __INTEL_COMPILER_FOR_WINDOWS) + set(FLG_ICC __INTEL_COMPILER_FOR_WINDOWS) endif() - if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR (UNIX AND FLG_ICC)) + if(CMAKE_COMPILER_IS_GNUCXX OR ${CLANG} GREATER 1 OR (UNIX AND FLG_ICC)) set(FLG_COMPILER_IS_GNU TRUE) else() set(FLG_COMPILER_IS_GNU FALSE) endif() # Detect GNU version: + set(CMAKE_FLG_GCC_VERSION_NUM 0) if(CMAKE_COMPILER_IS_GNUCXX) execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE CMAKE_FLG_GCC_VERSION_FULL @@ -430,7 +433,7 @@ macro(optimize_default_compiler_settings) endif() endif() - if(CMAKE_COMPILER_IS_GNUCXX) + if(FLG_COMPILER_IS_GNU) # High level of warnings. add_extra_compiler_option(-W) add_extra_compiler_option(-Wall) @@ -454,17 +457,21 @@ macro(optimize_default_compiler_settings) add_extra_compiler_option(-Wmissing-prototypes) add_extra_compiler_option(-Wpointer-arith) add_extra_compiler_option(-Wundef) + add_extra_compiler_option(-Wswitch) + add_extra_compiler_option(-Wswitch-enum) + add_extra_compiler_option(-Wswitch-default) else() - add_extra_compiler_option(-Wno-undef) + add_extra_compiler_option(-Wno-undef) + add_extra_compiler_option(-Wno-switch) + add_extra_compiler_option(-Wno-switch-enum) + add_extra_compiler_option(-Wno-switch-default) add_extra_compiler_option(-Wno-comment) add_extra_compiler_option(-Wno-narrowing) add_extra_compiler_option(-Wno-attributes) add_extra_compiler_option(-Wno-enum-compare) - add_extra_compiler_option(-Wno-missing-declarations) - add_extra_compiler_option(-Wno-missing-prototypes) add_extra_compiler_option(-Wno-missing-field-initializers) - add_extra_compiler_option(-Wno-unused-local-typedefs) - add_extra_compiler_option(-Wno-delete-non-virtual-dtor) + add_extra_compiler_option(-Wno-unused-parameter) + add_extra_compiler_option(-Wno-delete-incomplete) add_extra_compiler_option(-Wno-unnamed-type-template-args) endif() add_extra_compiler_option(-fdiagnostics-show-option) @@ -493,12 +500,14 @@ macro(optimize_default_compiler_settings) add_extra_compiler_option(-fomit-frame-pointer) else() add_extra_compiler_option(-fno-omit-frame-pointer) - endif() + endif() + if(NOT CLANG) if(ENABLE_FAST_MATH) add_extra_compiler_option(-ffast-math) else() add_extra_compiler_option(-frounding-math) endif() + endif() if(ENABLE_POWERPC) add_extra_compiler_option("-mcpu=G3 -mtune=G5") endif() @@ -568,7 +577,7 @@ macro(optimize_default_compiler_settings) endif() set(BUILD_EXTRA_FLAGS_RELEASE "${BUILD_EXTRA_FLAGS_RELEASE} -DNDEBUG") - set(BUILD_EXTRA_FLAGS_DEBUG "${BUILD_EXTRA_FLAGS_DEBUG} -O0 -DDEBUG -D_DEBUG") + set(BUILD_EXTRA_FLAGS_DEBUG "${BUILD_EXTRA_FLAGS_DEBUG} -O0 -D_DEBUG") if(BUILD_WITH_DEBUG_INFO) set(BUILD_EXTRA_FLAGS_DEBUG "${BUILD_EXTRA_FLAGS_DEBUG} -ggdb3") endif() diff --git a/libs/Common/Common.h b/libs/Common/Common.h index 0f47c4cab..8942f1e14 100644 --- a/libs/Common/Common.h +++ b/libs/Common/Common.h @@ -92,7 +92,7 @@ extern String g_strWorkingFolderFull; // full path to current folder #endif #define INIT_WORKING_FOLDER {SEACAVE::Util::ensureValidFolderPath(WORKING_FOLDER); WORKING_FOLDER_FULL = SEACAVE::Util::getFullPath(WORKING_FOLDER);} // initialize working folders #define MAKE_PATH(str) SEACAVE::Util::getSimplifiedPath(WORKING_FOLDER+(str)) // add working directory to the given file name -#define MAKE_PATH_SAFE(str) (SEACAVE::Util::isFullPath((str).c_str()) ? SEACAVE::String(str) : MAKE_PATH(str)) // add working directory to the given file name only if not full path already +#define MAKE_PATH_SAFE(str) (SEACAVE::Util::isFullPath(str) ? SEACAVE::String(str) : MAKE_PATH(str)) // add working directory to the given file name only if not full path already #define MAKE_PATH_FULL(p,s) (SEACAVE::Util::isFullPath((s).c_str()) ? SEACAVE::String(s) : SEACAVE::Util::getSimplifiedPath((p)+(s))) // add the given path to the given file name #define MAKE_PATH_REL(p,s) ((s).compare(0,(p).size(),p) ? SEACAVE::String(s) : SEACAVE::String(SEACAVE::String((s).substr((p).size())))) // remove the given path from the given file name #define GET_PATH_FULL(str) (SEACAVE::Util::isFullPath((str).c_str()) ? SEACAVE::Util::getFilePath(str) : SEACAVE::Util::getSimplifiedPath(WORKING_FOLDER_FULL+SEACAVE::Util::getFilePath(str))) // retrieve the full path to the given file diff --git a/libs/Common/Hash.h b/libs/Common/Hash.h index 67d08af3b..c344b3982 100644 --- a/libs/Common/Hash.h +++ b/libs/Common/Hash.h @@ -60,6 +60,7 @@ class cHashTable public: typedef uint32_t Key; typedef uint16_t Idx; + typedef uint32_t Size; typedef cList Values; typedef cList Keys; typedef cList Indices; @@ -93,9 +94,9 @@ class cHashTable inline Values& GetArrValues() { return m_values; } private: - inline UINT _StaticKeyToID(Key key, UINT size) const { return key & (size-1); } - inline UINT _KeyToID(Key key) const { return _StaticKeyToID(key, (UINT)m_indices.GetSize()); } - inline Idx _IDToIndex(UINT id) const { return m_indices[id] - 1; } + inline Size _StaticKeyToID(Key key, Size size) const { return key & (size-1); } + inline Size _KeyToID(Key key) const { return _StaticKeyToID(key, (Size)m_indices.GetSize()); } + inline Idx _IDToIndex(Size id) const { return m_indices[id] - 1; } inline Idx _KeyToIndex(Key key) const { return (m_indices.IsEmpty() ? KEY_NA : _IDToIndex(_KeyToID(key))); } // Completely discards then rebuilds all indices based on the current set of keys @@ -106,7 +107,7 @@ class cHashTable // Run through all keys and recreate the indices for (Idx i=0; i0; ) + for (Size i=m_indices.GetSize(); i>0; ) { if (m_indices[--i] > index) { @@ -184,7 +185,7 @@ class cHashTable { // Setting the key was unsuccessful due to another entry colliding with our key; // we must expand the indices until we find a set of keys that will match. - UINT newSize = m_indices.GetSize(); + Size newSize = m_indices.GetSize(); while (newSize < (KEY_MAXSIZE>>1)) { newSize = newSize << 1; @@ -202,7 +203,7 @@ class cHashTable } // assert the total number of values stored is in Idx range - ASSERT(m_keys.GetSize() < (UINT)((Idx)-1)); + ASSERT(m_keys.GetSize() < (Size)((Idx)-1)); // Append the new key to the end m_keys.Insert(key); @@ -217,7 +218,7 @@ class cHashTable public: // Fowler / Noll / Vo (FNV) Hash // magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ - static inline Key HashKeyFNV(const uint8_t* data, UINT size) + static inline Key HashKeyFNV(const uint8_t* data, Size size) { Key hash = 2166136261U; //InitialFNV for (size_t i = 0; i < size; i++) @@ -229,11 +230,11 @@ class cHashTable } // Function that calculates a hash value from a given data // tested for random binary data (3 <= size <= 33) and performs VERY bad - static inline Key HashKeyR5(const uint8_t* data, UINT size) + static inline Key HashKeyR5(const uint8_t* data, Size size) { Key key = 0; Key offset = 1357980759; - for (UINT i=0; i> 15); @@ -241,9 +242,9 @@ class cHashTable } return key; } - static inline Key HashKey(const uint8_t* data, UINT size) { return HashKeyFNV(data, size); } - static inline Key HashKey(LPCTSTR sz) { return HashKey((const uint8_t*)sz, (UINT)_tcslen(sz)); } - static inline Key HashKey(const String& str) { return HashKey((const uint8_t*)str.c_str(), (UINT)str.size()); } + static inline Key HashKey(const uint8_t* data, Size size) { return HashKeyFNV(data, size); } + static inline Key HashKey(LPCTSTR sz) { return HashKey((const uint8_t*)sz, (Size)_tcslen(sz)); } + static inline Key HashKey(const String& str) { return HashKey((const uint8_t*)str.c_str(), (Size)str.size()); } // Convenience functions inline Type* Find (LPCTSTR key) { return Find ( HashKey(key) ); } diff --git a/libs/Common/List.h b/libs/Common/List.h index 885587f86..e94672fd1 100644 --- a/libs/Common/List.h +++ b/libs/Common/List.h @@ -68,8 +68,8 @@ #define CLISTREFVECTOR(CLIST, var, vec) uint8_t _ArrData##var[sizeof(CLIST)]; new(_ArrData##var) CLIST(vec.size(), &vec[0]); const CLIST& var(*((const CLIST*)_ArrData##var)) #endif -#define CLISTDEF(TYPE) SEACAVE::cList< TYPE, const TYPE&, 1 > #define CLISTDEF0(TYPE) SEACAVE::cList< TYPE, const TYPE&, 0 > +#define CLISTDEF2(TYPE) SEACAVE::cList< TYPE, const TYPE&, 2 > #define CLISTDEFIDX(TYPE,IDXTYPE) SEACAVE::cList< TYPE, const TYPE&, 1, 16, IDXTYPE > #define CLISTDEF0IDX(TYPE,IDXTYPE) SEACAVE::cList< TYPE, const TYPE&, 0, 16, IDXTYPE > diff --git a/libs/Common/Log.cpp b/libs/Common/Log.cpp index 5be288988..da19bd157 100644 --- a/libs/Common/Log.cpp +++ b/libs/Common/Log.cpp @@ -33,7 +33,7 @@ Log::Log() #ifndef DEFAULT_LOGTYPE String appName = Util::getAppName(); appName = (Util::getFileExt(appName) == _T(".exe") ? Util::getFileName(appName) : Util::getFileNameExt(appName)); - UINT n = MINF((UINT)appName.length(), (UINT)LOGTYPE_SIZE); + Idx n = MINF((Idx)appName.length(), (Idx)LOGTYPE_SIZE); _tcsncpy(g_appType.szName, appName, n); while (n < LOGTYPE_SIZE) g_appType.szName[n++] = _T(' '); @@ -58,12 +58,12 @@ void Log::UnregisterListener(ClbkRecordMsg clbk) } //Register a new type of log messages (LOGTYPE_SIZE chars) -UINT Log::RegisterType(LPCTSTR lt) +Log::Idx Log::RegisterType(LPCTSTR lt) { ASSERT(strlen(lt) == LOGTYPE_SIZE); - const UINT idx = (UINT)m_arrLogTypes.GetSize(); + const Idx idx = (Idx)m_arrLogTypes.GetSize(); LogType& logType = m_arrLogTypes.AddEmpty(); - UINT n = MINF((UINT)strlen(lt), (UINT)LOGTYPE_SIZE); + Idx n = MINF((Idx)strlen(lt), (Idx)LOGTYPE_SIZE); _tcsncpy(logType.szName, lt, n); while (n < LOGTYPE_SIZE) logType.szName[n++] = _T(' '); @@ -88,7 +88,7 @@ void Log::Write(LPCTSTR szFormat, ...) _Record(NO_ID, szFormat, args); va_end(args); } -void Log::Write(UINT lt, LPCTSTR szFormat, ...) +void Log::Write(Idx lt, LPCTSTR szFormat, ...) { if (m_arrRecordClbk == NULL) return; @@ -100,11 +100,11 @@ void Log::Write(UINT lt, LPCTSTR szFormat, ...) /** * Write message to the log if this exists - * -> IN: UINT - log type + * -> IN: Idx - log type * LPCTSTR - format message * ... - values */ -void Log::_Record(UINT lt, LPCTSTR szFormat, va_list args) +void Log::_Record(Idx lt, LPCTSTR szFormat, va_list args) { ASSERT(m_arrRecordClbk != NULL); if (m_arrRecordClbk->IsEmpty()) diff --git a/libs/Common/Log.h b/libs/Common/Log.h index 157cc6136..44eb14d5d 100644 --- a/libs/Common/Log.h +++ b/libs/Common/Log.h @@ -25,9 +25,9 @@ #define DEFAULT_LOGTYPE _T("App ") #define DECLARE_LOG() \ - protected: static const UINT ms_nLogType; + protected: static const Log::Idx ms_nLogType; #define DEFINE_LOG(classname, log) \ - const UINT classname::ms_nLogType(REGISTER_LOG(log)); + const Log::Idx classname::ms_nLogType(REGISTER_LOG(log)); #ifdef LOG_THREAD #include "CriticalSection.h" @@ -43,6 +43,7 @@ class GENERAL_API Log DECLARE_SINGLETON(Log); public: + typedef uint32_t Idx; typedef DELEGATE ClbkRecordMsg; typedef cList ClbkRecordMsgArray; typedef CSharedPtr ClbkRecordMsgArrayPtr; @@ -54,10 +55,10 @@ class GENERAL_API Log void Join(Log& log) { m_arrRecordClbk = log.m_arrRecordClbk; } void RegisterListener(ClbkRecordMsg); void UnregisterListener(ClbkRecordMsg); - UINT RegisterType(LPCTSTR); + Idx RegisterType(LPCTSTR); void ResetTypes(); void Write(LPCTSTR, ...); - void Write(UINT, LPCTSTR, ...); + void Write(Idx, LPCTSTR, ...); #ifdef LOG_STREAM template inline Log& operator<<(const T& val) { @@ -95,7 +96,7 @@ class GENERAL_API Log protected: // write a message of a certain type to the log - void _Record(UINT, LPCTSTR, va_list); + void _Record(Idx, LPCTSTR, va_list); protected: struct LogType { diff --git a/libs/Common/Plane.h b/libs/Common/Plane.h index 05544d1e0..a293c94d2 100644 --- a/libs/Common/Plane.h +++ b/libs/Common/Plane.h @@ -53,8 +53,8 @@ class TPlane inline TYPE Distance(const POINT&) const; inline TYPE DistanceAbs(const POINT&) const; - inline UINT Classify(const POINT&) const; - inline UINT Classify(const AABB&) const; + inline GCLASS Classify(const POINT&) const; + inline GCLASS Classify(const AABB&) const; bool Clip(const RAY&, TYPE, RAY*, RAY*) const; @@ -100,9 +100,9 @@ class TFrustum void Set(const MATRIX4x4&, TYPE width, TYPE height, TYPE near=TYPE(0.0001), TYPE far=TYPE(1000)); void Set(const MATRIX3x4&, TYPE width, TYPE height, TYPE near=TYPE(0.0001), TYPE far=TYPE(1000)); - UINT Classify(const POINT&) const; - UINT Classify(const SPHERE&) const; - UINT Classify(const AABB&) const; + GCLASS Classify(const POINT&) const; + GCLASS Classify(const SPHERE&) const; + GCLASS Classify(const AABB&) const; inline TYPE& operator [] (BYTE i) { ASSERT(i::DistanceAbs(const POINT& p) const // Classify point to plane. template -inline UINT TPlane::Classify(const POINT& p) const +inline GCLASS TPlane::Classify(const POINT& p) const { const TYPE f(Distance(p)); if (f > ZEROTOLERANCE()) return FRONT; @@ -113,10 +113,10 @@ inline UINT TPlane::Classify(const POINT& p) const // Classify bounding box to plane. template -inline UINT TPlane::Classify(const AABB& aabb) const +inline GCLASS TPlane::Classify(const AABB& aabb) const { - const UINT classMin = Classify(aabb.ptMin); - const UINT classMax = Classify(aabb.ptMax); + const GCLASS classMin = Classify(aabb.ptMin); + const GCLASS classMax = Classify(aabb.ptMax); if (classMin == classMax) return classMin; return CLIPPED; } @@ -133,7 +133,7 @@ bool TPlane::Clip(const RAY& ray, TYPE fL, RAY* pF, RAY* pB) const if (!ray.Intersects(*this, false, fL, NULL, &ptHit)) return false; - UINT n = Classify(ray.m_pOrig); + GCLASS n = Classify(ray.m_pOrig); // ray comes from planes backside if ( n == BACK ) { @@ -195,7 +195,7 @@ bool TPlane::Intersects(const TPlane& plane, RAY& ray) const template bool TPlane::Intersects(const POINT& p0, const POINT& p1, const POINT& p2) const { - const UINT n(Classify(p0)); + const GCLASS n(Classify(p0)); if ((n == Classify(p1)) && (n == Classify(p2))) return false; @@ -206,7 +206,7 @@ bool TPlane::Intersects(const POINT& p0, const POINT& p1, const POINT // Intersection with AABB. Search for AABB diagonal that is most // aligned to plane normal. Test its two vertices against plane. -// (Möller/Haines, "Real-Time Rendering") +// (M�ller/Haines, "Real-Time Rendering") template bool TPlane::Intersects(const AABB& aabb) const { @@ -403,7 +403,7 @@ void TFrustum::Set(const MATRIX3x4& m, TYPE w, TYPE h, TYPE n, TYPE f * CULLED - point outside frustum */ template -UINT TFrustum::Classify(const POINT& p) const +GCLASS TFrustum::Classify(const POINT& p) const { // check if on the front side of any of the planes for (int i=0; i::Classify(const POINT& p) const * CULLED - sphere outside frustum */ template -UINT TFrustum::Classify(const SPHERE& s) const +GCLASS TFrustum::Classify(const SPHERE& s) const { // compute distances to each of the planes for (int i=0; i::Classify(const SPHERE& s) const * CULLED - aabb totally outside frustum */ template -UINT TFrustum::Classify(const AABB& aabb) const +GCLASS TFrustum::Classify(const AABB& aabb) const { bool bIntersects = false; diff --git a/libs/Common/SML.cpp b/libs/Common/SML.cpp index 3e35414c2..70f7904e5 100644 --- a/libs/Common/SML.cpp +++ b/libs/Common/SML.cpp @@ -141,7 +141,7 @@ bool SML::ParseSection(TokenIStream& filter, MemFile& memFile) ASSERT(!filter.isEOS()); if (lenName == 0) return false; // Parse Error: invalid section name - const String strChildName((LPCTSTR)memFile.getData(), (UINT)lenName); + const String strChildName((LPCTSTR)memFile.getData(), lenName); memFile.growSize(-((size_f_t)(lenName*sizeof(TCHAR)))); ASSERT(memFile.getSize() == 0); // create the child with the given name diff --git a/libs/Common/Sphere.h b/libs/Common/Sphere.h index 3cc9b5b87..f5d79e54f 100644 --- a/libs/Common/Sphere.h +++ b/libs/Common/Sphere.h @@ -44,7 +44,7 @@ class TSphere inline void Enlarge(TYPE); inline void EnlargePercent(TYPE); - inline UINT Classify(const POINT&) const; + inline GCLASS Classify(const POINT&) const; }; // class TSphere /*----------------------------------------------------------------*/ diff --git a/libs/Common/Sphere.inl b/libs/Common/Sphere.inl index 9ef22c779..6a46826f1 100644 --- a/libs/Common/Sphere.inl +++ b/libs/Common/Sphere.inl @@ -71,7 +71,7 @@ inline void TSphere::EnlargePercent(TYPE x) // Classify point to sphere. template -inline UINT TSphere::Classify(const POINT& p) const +inline GCLASS TSphere::Classify(const POINT& p) const { if ((center - p).squaredNorm() > SQUARE(radius)) return CULLED; diff --git a/libs/Common/Types.h b/libs/Common/Types.h index 6a0813003..9e1ceab42 100644 --- a/libs/Common/Types.h +++ b/libs/Common/Types.h @@ -196,6 +196,10 @@ namespace cv { namespace gpu = cuda; } #ifndef __THREAD__ # ifdef _MSC_VER # define __THREAD__ ((unsigned)GetCurrentThreadId()) +# elif defined(__APPLE__) +# include +inline pid_t GetCurrentThreadId() { uint64_t tid64; pthread_threadid_np(NULL, &tid64); return (pid_t)tid64; } +# define __THREAD__ ((unsigned)GetCurrentThreadId()) # else # include # define __THREAD__ ((unsigned)((pid_t)syscall(SYS_gettid))) @@ -227,19 +231,14 @@ namespace cv { namespace gpu = cuda; } // Type defines #ifndef _MSC_VER +typedef int32_t HRESULT; + typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; typedef uint64_t QWORD; typedef char CHAR; -typedef int BOOL; -typedef signed int INT; -typedef unsigned int UINT; -typedef long LONG; - -typedef int32_t HRESULT; - typedef CHAR* LPSTR; typedef const CHAR* LPCSTR; typedef CHAR TCHAR; @@ -309,13 +308,6 @@ typedef int64_t size_f_t; #define NULL 0 #endif -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - #ifdef max #undef max #endif @@ -395,21 +387,6 @@ typedef TAliasCast CastD2I; namespace SEACAVE { -// maximum number of vertices in one list -#define MAXNUMVERTS 65535 -// maximum number of indices in one list -#define MAXNUMINDIS (MAXNUMVERTS*8) -typedef WORD INDEX; -// maximum number of bone indices in one list -#define MAXNUMBONES 255 -typedef BYTE BONEIDX; -// maximum number of frames in one animation -#define MAXNUMFRAMES 65535 -typedef WORD FRAMEIDX; - -typedef class GENERAL_API cList CINDEXArray; -typedef class GENERAL_API cList CUINTArray; - typedef class GENERAL_API CSharedPtr FilePtr; typedef class GENERAL_API CSharedPtr ISTREAMPTR; @@ -587,6 +564,7 @@ typedef class GENERAL_API cList DoubleArr; #define FZERO_TOLERANCE 0.0001f #define FINV_ZERO 1000000.f +#define GCLASS unsigned #define FRONT 0 #define BACK 1 #define PLANAR 2 @@ -748,24 +726,22 @@ inline T TANH(const T& x) { // cube root approximation using bit hack for 32-bit float (5 decimals) // (exploits the properties of IEEE 754 floating point numbers // by leveraging the fact that their binary representation is close to a log2 representation) -inline float cbrt5(float f) { - #if 1 - (int&)f = (((int&)f-(127<<23))/3+(127<<23)); +inline float cbrt5(float x) { + #if 0 + CastF2I c(x); + c.i = ((c.i-(127<<23))/3+(127<<23)); #else - unsigned* p = (unsigned*)&f; - *p = *p/3 + 709921077; + TAliasCast c(x); + c.i = c.i/3 + 709921077u; #endif - return f; + return c.f; } // cube root approximation using bit hack for 64-bit float // adapted from Kahan's cbrt (5 decimals) -inline double cbrt5(double d) { - const unsigned B1 = 715094163; - double t = 0.0; - unsigned* pt = (unsigned*)&t; - unsigned* px = (unsigned*)&d; - pt[1]=px[1]/3+B1; - return t; +inline double cbrt5(double x) { + TAliasCast c(0.0), d(x); + c.i[1] = d.i[1]/3 + 715094163u; + return c.f; } // iterative cube root approximation using Halley's method // faster convergence than Newton's method: (R/(a*a)+a*2)/3 @@ -813,20 +789,9 @@ const double _float2int_doublemagic = 6755399441055744.0; //2^52 * 1.5, const double _float2int_doublemagicdelta = (1.5e-8); const double _float2int_doublemagicroundeps = (.5f-_float2int_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit) FORCEINLINE int CRound2Int(const double& x) { - #if 1 - union CastD2I { - double d; - int32_t i; - }; - CastD2I c; - c.d = x + _float2int_doublemagic; + const CastD2I c(x + _float2int_doublemagic); ASSERT(int32_t(floor(x+.5)) == c.i); return c.i; - #else - x = x + _float2int_doublemagic; - ASSERT(int32_t(floor(x+.5)) == ((int32_t*)&x)[0]); - return ((int32_t*)&x)[0]; - #endif } #endif FORCEINLINE int Floor2Int(float x) { diff --git a/libs/Common/Types.inl b/libs/Common/Types.inl index 34eb5c552..0dc277ffb 100644 --- a/libs/Common/Types.inl +++ b/libs/Common/Types.inl @@ -35,12 +35,12 @@ INT_TYPE cvRANSACUpdateNumIters(REAL_TYPE p, REAL_TYPE ep, INT_TYPE modelPoints, ASSERT(p>=0 && p<=1); ASSERT(ep>=0 && ep<=1); // avoid inf's & nan's - REAL_TYPE num = MAXF(REAL_TYPE(1)-p, EPSILONTOLERANCE()); + REAL_TYPE num = MAXF(REAL_TYPE(1)-p, SEACAVE::EPSILONTOLERANCE()); REAL_TYPE denom = REAL_TYPE(1)-POWI(REAL_TYPE(1)-ep, modelPoints); - if (denom < EPSILONTOLERANCE()) + if (denom < SEACAVE::EPSILONTOLERANCE()) return 0; - num = LOGN(num); - denom = LOGN(denom); + num = SEACAVE::LOGN(num); + denom = SEACAVE::LOGN(denom); return (denom >= 0 || -num >= (-denom)*maxIters ? maxIters : (INT_TYPE)ROUND2INT(num/denom)); } #endif @@ -2059,9 +2059,9 @@ void TImage::toGray(TImage& out, int code, bool bNormalize) const const T &cb(coeffs[0]), &cg(coeffs[1]), &cr(coeffs[2]); if (out.rows!=rows || out.cols!=cols) out.create(rows, cols); - ASSERT(this->isContinuous()); + ASSERT(cv::Mat::isContinuous()); ASSERT(out.cv::Mat::isContinuous()); - const int scn(this->channels()); + const int scn(cv::Mat::channels()); T* dst = out.cv::Mat::template ptr(); T* const dstEnd = dst + out.area(); typedef typename cv::DataType::channel_type ST; @@ -2274,7 +2274,7 @@ inline void _ProcessScanLine(int y, const TPoint3& pa, const TPoint3& pb, } } // Raster the given triangle and output the position and depth of each pixel of the triangle; -// based on "Learning how to write a 3D software engine – Rasterization & Z-Buffering" by Nick (David Rousset) +// based on "Learning how to write a 3D software engine – Rasterization & Z-Buffering" by Nick (David Rousset) // http://blogs.msdn.com/b/davrous/archive/2013/06/21/tutorial-part-4-learning-how-to-write-a-3d-software-engine-in-c-ts-or-js-rasterization-amp-z-buffering.aspx template template diff --git a/libs/Common/Util.cpp b/libs/Common/Util.cpp index 1674f7941..53df906b2 100644 --- a/libs/Common/Util.cpp +++ b/libs/Common/Util.cpp @@ -38,7 +38,7 @@ typedef struct CPUINFO_TYP { bool bSSE41; // Streaming SIMD Extensions 4.1 bool bSSE42; // Streaming SIMD Extensions 4.2 bool bAVX; // Advanced Vector Extensions - bool bFMA; // Fused Multiply–Add + bool bFMA; // Fused Multiply�Add bool b3DNOW; // 3DNow! (vendor independent) bool b3DNOWEX; // 3DNow! (AMD specific extensions) bool bMMX; // MMX support @@ -556,7 +556,7 @@ bool OSSupportsAVX() { #ifndef _WIN64 // try AVX instruction - UINT flag; + unsigned flag; _asm { mov ecx, 0; //specify 0 for XFEATURE_ENABLED_MASK register XGETBV; //result in EDX:EAX diff --git a/libs/Common/Util.h b/libs/Common/Util.h index a14792dd1..d41b829ed 100644 --- a/libs/Common/Util.h +++ b/libs/Common/Util.h @@ -398,6 +398,64 @@ class GENERAL_API Util return simplifyPath(path); } + static String getRelativePath(const String& currentPath, const String& targetPath) { + // returns the path to the target relative to the current path; + // both current and target paths must be full paths; + // current path is assumed to be a folder, while target path can be also a file + CLISTDEF2(String) currentPathValues, targetPathValues; + Util::strSplit(currentPath, PATH_SEPARATOR, currentPathValues); + if (currentPathValues.back().empty()) + currentPathValues.pop_back(); + Util::strSplit(targetPath, PATH_SEPARATOR, targetPathValues); + size_t idxCurrentPath(0), idxTargetPath(0); + while ( + idxCurrentPath < currentPathValues.size() && + idxTargetPath < targetPathValues.size() && + #ifdef _MSC_VER + _tcsicmp(currentPathValues[idxCurrentPath], targetPathValues[idxTargetPath]) == 0 + #else + _tcscmp(currentPathValues[idxCurrentPath], targetPathValues[idxTargetPath]) == 0 + #endif + ) + ++idxCurrentPath, ++idxTargetPath; + if (idxCurrentPath == 0) + return targetPath; + String relativePath; + relativePath.reserve(targetPath.size()); + while (idxCurrentPath < currentPathValues.size()) { + relativePath += _T("..") PATH_SEPARATOR_STR; + ++idxCurrentPath; + } + const size_t idxFirstTarget(idxTargetPath); + while (idxTargetPath < targetPathValues.size()) { + if (idxTargetPath > idxFirstTarget) + relativePath += PATH_SEPARATOR; + relativePath += targetPathValues[idxTargetPath++]; + } + return relativePath; + } + + static String& getCommonPath(String& commonPath, const String& path) { + // returns the path shared by the given paths + #ifdef _MSC_VER + while (_tcsnicmp(commonPath, path, commonPath.length()) != 0) { + #else + while (_tcsncmp(commonPath, path, commonPath.length()) != 0) { + #endif + commonPath.pop_back(); + commonPath = getFilePath(commonPath); + } + return commonPath; + } + static String getCommonPath(const String* arrPaths, size_t numPaths) { + // returns the path shared by all given paths + ASSERT(numPaths > 0); + String commonPath(arrPaths[0]); + for (size_t i=1; !commonPath.empty() && i& values) { - if (delim.empty()) - return false; - values.clear(); - String::size_type start(0); - String::size_type end(String::npos -1); + static void strSplit(const String& str, TCHAR delim, CLISTDEF2(String)& values) { + values.Empty(); + String::size_type start(0), end(0); + while (end != String::npos) { + end = str.find(delim, start); + values.AddConstruct(str.substr(start, end-start)); + start = end + 1; + } + } + static void strSplit(const String& str, const String& delim, CLISTDEF2(String)& values) { + ASSERT(!delim.empty()); + values.Empty(); + String::size_type start(0), end(0); while (end != String::npos) { end = str.find(delim, start); - values.push_back(str.substr(start, end-start)); + values.AddConstruct(str.substr(start, end-start)); start = end + delim.size(); } - return (values.size() >= 2); } static String getShortTimeString() { @@ -525,38 +589,38 @@ class GENERAL_API Util // format given time in milliseconds to higher units static String formatTime(int64_t sTime, uint32_t nAproximate = 0) { char buf[128]; - UINT len = 0; - UINT nrNumbers = 0; + uint32_t len = 0; + uint32_t nrNumbers = 0; - UINT rez = (UINT)(sTime / ((int64_t)24*3600*1000)); + uint32_t rez = (uint32_t)(sTime / ((int64_t)24*3600*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%ud", rez); } if (nAproximate > 3 && nrNumbers > 0) return buf; - rez = (UINT)((sTime%((int64_t)24*3600*1000)) / (3600*1000)); + rez = (uint32_t)((sTime%((int64_t)24*3600*1000)) / (3600*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%uh", rez); } if (nAproximate > 2 && nrNumbers > 0) return buf; - rez = (UINT)((sTime%((int64_t)3600*1000)) / (60*1000)); + rez = (uint32_t)((sTime%((int64_t)3600*1000)) / (60*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%um", rez); } if (nAproximate > 1 && nrNumbers > 0) return buf; - rez = (UINT)((sTime%((int64_t)60*1000)) / (1*1000)); + rez = (uint32_t)((sTime%((int64_t)60*1000)) / (1*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%us", rez); } if (nAproximate > 0 && nrNumbers > 0) return buf; - rez = (UINT)(sTime%((int64_t)1*1000)); + rez = (uint32_t)(sTime%((int64_t)1*1000)); if (rez || !nrNumbers) len += _stprintf(buf+len, "%ums", rez); diff --git a/libs/IO/Image.cpp b/libs/IO/Image.cpp index 3a0d8d410..0a9de141f 100644 --- a/libs/IO/Image.cpp +++ b/libs/IO/Image.cpp @@ -21,7 +21,7 @@ DEFINE_LOG(CImage, _T("IO ")); // Set the image details; // if image's data is not NULL, but its size is too small, // data's buffer is not allocated and _BUFFERSIZE is returned. -HRESULT CImage::Reset(UINT width, UINT height, PIXELFORMAT pixFormat, UINT levels, bool bAllocate) +HRESULT CImage::Reset(Size width, Size height, PIXELFORMAT pixFormat, Size levels, bool bAllocate) { // reinitialize image with given params const size_t oldDataSize = GetDataSize(); @@ -92,7 +92,7 @@ HRESULT CImage::ReadHeader() } // ReadHeader /*----------------------------------------------------------------*/ -HRESULT CImage::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImage::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { // read data if (dataFormat == m_format && nStride == m_stride) { @@ -102,14 +102,14 @@ HRESULT CImage::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT if (nSize != m_pStream->read(pData, nSize)) return _INVALIDFILE; } else { - for (UINT j=0; jread(pData, m_lineWidth)) return _INVALIDFILE; } } else { // read image to a buffer and convert it CAutoPtrArr const buffer(new uint8_t[m_lineWidth]); - for (UINT j=0; jread(buffer, m_lineWidth)) return _INVALIDFILE; if (!FilterFormat(pData, dataFormat, nStride, buffer, m_format, m_stride, m_dataWidth)) @@ -124,7 +124,7 @@ HRESULT CImage::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT /*----------------------------------------------------------------*/ -HRESULT CImage::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, BYTE numLevels) +HRESULT CImage::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels) { // write header m_numLevels = numLevels; @@ -138,7 +138,7 @@ HRESULT CImage::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, BY } // WriteHeader /*----------------------------------------------------------------*/ -HRESULT CImage::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImage::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { // write data if (dataFormat == m_format && nStride == m_stride) { @@ -148,14 +148,14 @@ HRESULT CImage::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UIN if (nSize != m_pStream->write(pData, nSize)) return _INVALIDFILE; } else { - for (UINT j=0; jwrite(pData, m_lineWidth)) return _INVALIDFILE; } } else { // convert data to a buffer and write it CAutoPtrArr const buffer(new uint8_t[m_lineWidth]); - for (UINT j=0; jwrite(buffer, m_lineWidth)) @@ -170,11 +170,11 @@ HRESULT CImage::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UIN /*----------------------------------------------------------------*/ -UINT CImage::GetDataSizes(UINT mipLevel, UINT& width, UINT& height) const +CImage::Size CImage::GetDataSizes(Size mipLevel, Size& width, Size& height) const { // Bump by the mip level. - height = MAXF((UINT)1, m_height >> mipLevel); - width = MAXF((UINT)1, m_width >> mipLevel); + height = MAXF((Size)1, m_height >> mipLevel); + width = MAXF((Size)1, m_width >> mipLevel); // if compressed, divide dims by 4 if (m_format >= PF_DXT1) @@ -188,7 +188,7 @@ UINT CImage::GetDataSizes(UINT mipLevel, UINT& width, UINT& height) const /*----------------------------------------------------------------*/ -UINT CImage::GetStride(PIXELFORMAT pixFormat) +CImage::Size CImage::GetStride(PIXELFORMAT pixFormat) { switch (pixFormat) { @@ -253,7 +253,7 @@ bool CImage::FormatHasAlpha(PIXELFORMAT format) // Convert from one format to another. // nSzize is the number of pixels to process. -bool CImage::FilterFormat(void* pDst, PIXELFORMAT formatDst, UINT strideDst, const void* pSrc, PIXELFORMAT formatSrc, UINT strideSrc, UINT nSzize) +bool CImage::FilterFormat(void* pDst, PIXELFORMAT formatDst, Size strideDst, const void* pSrc, PIXELFORMAT formatSrc, Size strideSrc, Size nSzize) { //ASSERT(formatDst != formatSrc || strideDst != strideSrc) switch (formatDst) @@ -272,13 +272,13 @@ bool CImage::FilterFormat(void* pDst, PIXELFORMAT formatDst, UINT strideDst, con case PF_GRAY8: // from PF_A8 to PF_A8 (just copy) ASSERT(strideDst != strideSrc); - for (UINT i=0; i m_data; // image's data buffer - UINT m_width; // image width in pixels - UINT m_height; // image height in pixels - UINT m_dataWidth; // image's data width including mipmaps - UINT m_dataHeight; // image's data height - UINT m_stride; // bytes per pixel - UINT m_lineWidth; // image canvas width in bytes + Size m_width; // image width in pixels + Size m_height; // image height in pixels + Size m_dataWidth; // image's data width including mipmaps + Size m_dataHeight; // image's data height + Size m_stride; // bytes per pixel + Size m_lineWidth; // image canvas width in bytes PIXELFORMAT m_format; // image format (pixel type) BYTE m_numLevels; // number of mipmap levels (0 = auto-generate) BYTE m_level; // index of the mipmap level currently reading diff --git a/libs/IO/ImageBMP.cpp b/libs/IO/ImageBMP.cpp index 98a8f40e2..e67c205ec 100644 --- a/libs/IO/ImageBMP.cpp +++ b/libs/IO/ImageBMP.cpp @@ -19,6 +19,7 @@ using namespace SEACAVE; // S T R U C T S /////////////////////////////////////////////////// #ifndef _MSC_VER +typedef long LONG; typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; @@ -130,7 +131,7 @@ HRESULT CImageBMP::ReadHeader() /*----------------------------------------------------------------*/ -HRESULT CImageBMP::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageBMP::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { // read data const size_t nSize = m_width*m_stride; @@ -139,14 +140,14 @@ HRESULT CImageBMP::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, U if (dataFormat == m_format && nStride == m_stride) { // read image directly to the data buffer (BYTE*&)pData += (m_height-1)*lineWidth; - for (UINT j=0; jread(pData, nSize) || (nPad && nPad != m_pStream->read(bufferPad, nPad))) return _INVALIDFILE; } else { // read image to a buffer and convert it CAutoPtrArr const buffer(new uint8_t[m_lineWidth]); - for (UINT j=0; jread(buffer, m_lineWidth)) return _INVALIDFILE; if (!FilterFormat((uint8_t*)pData+(m_height-j-1)*lineWidth, dataFormat, nStride, buffer, m_format, m_stride, m_width)) @@ -158,7 +159,7 @@ HRESULT CImageBMP::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, U /*----------------------------------------------------------------*/ -HRESULT CImageBMP::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, BYTE /*numLevels*/) +HRESULT CImageBMP::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE /*numLevels*/) { // write header m_numLevels = 0; @@ -230,7 +231,7 @@ HRESULT CImageBMP::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, /*----------------------------------------------------------------*/ -HRESULT CImageBMP::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageBMP::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { // write data const size_t nSize = m_width*m_stride; @@ -239,14 +240,14 @@ HRESULT CImageBMP::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, if (nPad) memset(bufferPad, 0, nPad); if (dataFormat == m_format && nStride == m_stride) { // write data buffer directly to the image - for (UINT j=0; jwrite((uint8_t*)pData+(m_height-j-1)*lineWidth, nSize) || (nPad && nPad != m_pStream->write(bufferPad, nPad))) return _INVALIDFILE; } else { // convert data to a buffer and write it CAutoPtrArr const buffer(new uint8_t[m_lineWidth]); - for (UINT j=0; jwrite(buffer, m_lineWidth)) diff --git a/libs/IO/ImageBMP.h b/libs/IO/ImageBMP.h index c092a2ca3..43ae47591 100644 --- a/libs/IO/ImageBMP.h +++ b/libs/IO/ImageBMP.h @@ -25,9 +25,9 @@ class IO_API CImageBMP : public CImage virtual ~CImageBMP(); HRESULT ReadHeader(); - HRESULT ReadData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); - HRESULT WriteHeader(PIXELFORMAT, UINT width, UINT height, BYTE numLevels); - HRESULT WriteData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); + HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth); + HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels); + HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth); }; // class CImageBMP /*----------------------------------------------------------------*/ diff --git a/libs/IO/ImageDDS.cpp b/libs/IO/ImageDDS.cpp index 56a996378..09e1e2680 100644 --- a/libs/IO/ImageDDS.cpp +++ b/libs/IO/ImageDDS.cpp @@ -294,7 +294,7 @@ HRESULT CImageDDS::ReadHeader() /*----------------------------------------------------------------*/ -HRESULT CImageDDS::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageDDS::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { // read data if (dataFormat == m_format && nStride == m_stride) { @@ -304,14 +304,14 @@ HRESULT CImageDDS::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, U if (nSize != m_pStream->read(pData, nSize)) return _INVALIDFILE; } else { - for (UINT j=0; jread(pData, m_lineWidth)) return _INVALIDFILE; } } else { // read image to a buffer and convert it CAutoPtrArr const buffer(new uint8_t[m_lineWidth]); - for (UINT j=0; jread(buffer, m_lineWidth)) return _INVALIDFILE; if (!FilterFormat(pData, dataFormat, nStride, buffer, m_format, m_stride, m_dataWidth)) @@ -325,14 +325,14 @@ HRESULT CImageDDS::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, U /*----------------------------------------------------------------*/ -HRESULT CImageDDS::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, BYTE numLevels) +HRESULT CImageDDS::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels) { return _FAIL; } // WriteHeader /*----------------------------------------------------------------*/ -HRESULT CImageDDS::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageDDS::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { return _FAIL; } // WriteData diff --git a/libs/IO/ImageDDS.h b/libs/IO/ImageDDS.h index e0dcd7466..268d9631b 100644 --- a/libs/IO/ImageDDS.h +++ b/libs/IO/ImageDDS.h @@ -25,9 +25,9 @@ class IO_API CImageDDS : public CImage virtual ~CImageDDS(); HRESULT ReadHeader(); - HRESULT ReadData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); - HRESULT WriteHeader(PIXELFORMAT, UINT width, UINT height, BYTE numLevels); - HRESULT WriteData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); + HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth); + HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels); + HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth); }; // class CImageDDS /*----------------------------------------------------------------*/ diff --git a/libs/IO/ImageEXIF.cpp b/libs/IO/ImageEXIF.cpp index 6a90ce007..3e7c507a9 100644 --- a/libs/IO/ImageEXIF.cpp +++ b/libs/IO/ImageEXIF.cpp @@ -133,20 +133,20 @@ HRESULT CImageEXIF::ReadHeader() } // ReadHeader /*----------------------------------------------------------------*/ -HRESULT CImageEXIF::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageEXIF::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { return _FAIL; } // ReadData /*----------------------------------------------------------------*/ -HRESULT CImageEXIF::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, BYTE numLevels) +HRESULT CImageEXIF::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels) { //TODO: to implement the EXIF encoder return _OK; } // WriteHeader /*----------------------------------------------------------------*/ -HRESULT CImageEXIF::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageEXIF::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { //TODO: to implement the EXIF encoder return _OK; diff --git a/libs/IO/ImageEXIF.h b/libs/IO/ImageEXIF.h index 478f2a555..a4703ca6e 100644 --- a/libs/IO/ImageEXIF.h +++ b/libs/IO/ImageEXIF.h @@ -32,9 +32,9 @@ class IO_API CImageEXIF : public CImage void Close(); HRESULT ReadHeader(); - HRESULT ReadData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); - HRESULT WriteHeader(PIXELFORMAT, UINT width, UINT height, BYTE numLevels); - HRESULT WriteData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); + HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth); + HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels); + HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth); bool HasEXIF() const; bool HasIPTC() const; diff --git a/libs/IO/ImageJPG.cpp b/libs/IO/ImageJPG.cpp index c6c5ccd08..7ed958e36 100644 --- a/libs/IO/ImageJPG.cpp +++ b/libs/IO/ImageJPG.cpp @@ -181,7 +181,7 @@ HRESULT CImageJPG::ReadHeader() } // ReadHeader /*----------------------------------------------------------------*/ -HRESULT CImageJPG::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageJPG::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { JpegState* state = (JpegState*)m_state; @@ -199,14 +199,14 @@ HRESULT CImageJPG::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, U // read image directly to the data buffer JSAMPLE* buffer[1] = {(JSAMPLE*)pData}; uint8_t*& data = (uint8_t*&)buffer[0]; - for (UINT j=0; jmem->alloc_sarray)((j_common_ptr)cinfo, JPOOL_IMAGE, m_lineWidth, 1); uint8_t* dst = (uint8_t*)pData; uint8_t* src = (uint8_t*)buffer[0]; - for (UINT j=0; j const buffer(new png_byte[m_lineWidth]); - for (UINT j=0; j const buffer(new png_byte[m_lineWidth]); - for (UINT j=0; jread(pData, m_lineWidth)) return _INVALIDFILE; } else { // read image to a buffer and convert it CAutoPtrArr const buffer(new uint8_t[m_lineWidth]); - for (UINT j=0; jread(buffer, m_lineWidth)) return _INVALIDFILE; if (!FilterFormat((BYTE*)pData+(m_height-j-1)*lineWidth, dataFormat, nStride, buffer, m_format, m_stride, m_width)) @@ -130,14 +130,14 @@ HRESULT CImageTGA::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, U /*----------------------------------------------------------------*/ -HRESULT CImageTGA::WriteHeader(PIXELFORMAT imageFormat, UINT width, UINT height, BYTE numLevels) +HRESULT CImageTGA::WriteHeader(PIXELFORMAT imageFormat, Size width, Size height, BYTE numLevels) { return _FAIL; } // WriteHeader /*----------------------------------------------------------------*/ -HRESULT CImageTGA::WriteData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageTGA::WriteData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { return _FAIL; } // WriteData diff --git a/libs/IO/ImageTGA.h b/libs/IO/ImageTGA.h index 769a69708..517814eb4 100644 --- a/libs/IO/ImageTGA.h +++ b/libs/IO/ImageTGA.h @@ -25,9 +25,9 @@ class IO_API CImageTGA : public CImage virtual ~CImageTGA(); HRESULT ReadHeader(); - HRESULT ReadData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); - HRESULT WriteHeader(PIXELFORMAT, UINT width, UINT height, BYTE numLevels); - HRESULT WriteData(void*, PIXELFORMAT, UINT nStride, UINT lineWidth); + HRESULT ReadData(void*, PIXELFORMAT, Size nStride, Size lineWidth); + HRESULT WriteHeader(PIXELFORMAT, Size width, Size height, BYTE numLevels); + HRESULT WriteData(void*, PIXELFORMAT, Size nStride, Size lineWidth); protected: bool m_bRLE; diff --git a/libs/IO/ImageTIFF.cpp b/libs/IO/ImageTIFF.cpp index bd09db413..86252c0db 100644 --- a/libs/IO/ImageTIFF.cpp +++ b/libs/IO/ImageTIFF.cpp @@ -444,7 +444,7 @@ HRESULT CImageTIFF::ReadHeader() } // ReadHeader /*----------------------------------------------------------------*/ -HRESULT CImageTIFF::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, UINT lineWidth) +HRESULT CImageTIFF::ReadData(void* pData, PIXELFORMAT dataFormat, Size nStride, Size lineWidth) { if (m_state && m_width && m_height) { TIFF* tif = (TIFF*)m_state; @@ -483,7 +483,7 @@ HRESULT CImageTIFF::ReadData(void* pData, PIXELFORMAT dataFormat, UINT nStride, uint8_t* data = (uint8_t*)pData; if (!is_tiled && tile_height0 == 1 && dataFormat == m_format && nStride == m_stride) { // read image directly to the data buffer - for (UINT j=0; j> keyword; diff --git a/libs/MVS/Camera.h b/libs/MVS/Camera.h index 2cbacc050..aa9aebb6d 100644 --- a/libs/MVS/Camera.h +++ b/libs/MVS/Camera.h @@ -352,6 +352,27 @@ class MVS_API Camera : public CameraIntern return IsInside(ProjectPointP(X), size); } + // same as above, but for ortho-projection + template + inline TPoint3 TransformPointOrthoI2C(const TPoint3& x) const { + return TPoint3( + TYPE((x.x-K(0,2))/K(0,0)), + TYPE((x.y-K(1,2))/K(1,1)), + x.z ); + } + template + inline TPoint3 TransformPointOrthoI2W(const TPoint3& x) const { + return TransformPointC2W(TransformPointOrthoI2C(x)); + } + template + inline TPoint2 TransformPointOrthoC2I(const TPoint3& X) const { + return TransformPointC2I(TPoint2(X.x, X.y)); + } + template + inline TPoint2 TransformPointOrthoW2I(const TPoint3& X) const { + return TransformPointOrthoC2I(TransformPointW2C(X)); + } + #ifdef _USE_BOOST // implement BOOST serialization template diff --git a/libs/MVS/DepthMap.cpp b/libs/MVS/DepthMap.cpp index de2aac4fb..ed2350524 100644 --- a/libs/MVS/DepthMap.cpp +++ b/libs/MVS/DepthMap.cpp @@ -262,6 +262,7 @@ const float DepthEstimator::scaleRanges[12] = {1.f, 0.5f, 0.25f, 0.125f, 0.0625f DepthEstimator::DepthEstimator(DepthData& _depthData0, volatile Thread::safe_t& _idx, const Image64F& _image0Sum, const MapRefArr& _coords, ENDIRECTION _dir) : + neighborsData(0,4), neighbors(0,2), idxPixel(_idx), scores(_depthData0.images.size()-1), depthMap0(_depthData0.depthMap), normalMap0(_depthData0.normalMap), confMap0(_depthData0.confMap), @@ -271,7 +272,6 @@ DepthEstimator::DepthEstimator(DepthData& _depthData0, volatile Thread::safe_t& idxScore((_depthData0.images.size()-1)/3), #endif dir(_dir), dMin(_depthData0.dMin), dMax(_depthData0.dMax), - neighborsData(0,4), neighbors(0,2), smoothBonusDepth(1.f-OPTDENSE::fRandomSmoothBonus), smoothBonusNormal((1.f-OPTDENSE::fRandomSmoothBonus)*0.96f), smoothSigmaDepth(-1.f/(2.f*SQUARE(OPTDENSE::fRandomSmoothDepth))), // used in exp(-x^2 / (2*(0.006^2))) smoothSigmaNormal(-1.f/(2.f*SQUARE(FD2R(OPTDENSE::fRandomSmoothNormal)))), // used in exp(-x^2 / (2*(0.15^2))) diff --git a/libs/MVS/Image.cpp b/libs/MVS/Image.cpp index 7918390c8..133da424f 100644 --- a/libs/MVS/Image.cpp +++ b/libs/MVS/Image.cpp @@ -79,7 +79,7 @@ bool Image::ReadImage(IMAGEPTR pImage, Image8U3& image) return false; } image.create(pImage->GetHeight(), pImage->GetWidth()); - if (FAILED(pImage->ReadData(image.data, PF_R8G8B8, 3, (UINT)image.step))) { + if (FAILED(pImage->ReadData(image.data, PF_R8G8B8, 3, (CImage::Size)image.step))) { LOG("error: failed loading image data"); return false; } diff --git a/libs/MVS/Interface.h b/libs/MVS/Interface.h index fcd0fc919..18c586897 100644 --- a/libs/MVS/Interface.h +++ b/libs/MVS/Interface.h @@ -10,7 +10,7 @@ // D E F I N E S /////////////////////////////////////////////////// #define MVSI_PROJECT_ID "MVSI" // identifies the project stream -#define MVSI_PROJECT_VER ((uint32_t)2) // identifies the version of a project stream +#define MVSI_PROJECT_VER ((uint32_t)3) // identifies the version of a project stream // set a default namespace name if none given #ifndef _INTERFACE_NAMESPACE @@ -273,7 +273,7 @@ bool Load(ArchiveLoad& a, TYPE& v) { \ // Serialization support for basic types ARCHIVE_DEFINE_TYPE(uint32_t) -ARCHIVE_DEFINE_TYPE(size_t) +ARCHIVE_DEFINE_TYPE(uint64_t) ARCHIVE_DEFINE_TYPE(float) ARCHIVE_DEFINE_TYPE(double) @@ -304,7 +304,7 @@ bool Load(ArchiveLoad& a, cv::Point3_<_Tp>& pt) { // Serialization support for std::string template<> bool Save(ArchiveSave& a, const std::string& s) { - const size_t size(s.size()); + const uint64_t size(s.size()); Save(a, size); if (size > 0) a.stream.write(&s[0], sizeof(char)*size); @@ -312,7 +312,7 @@ bool Save(ArchiveSave& a, const std::string& s) { } template<> bool Load(ArchiveLoad& a, std::string& s) { - size_t size; + uint64_t size; Load(a, size); if (size > 0) { s.resize(size); @@ -324,19 +324,19 @@ bool Load(ArchiveLoad& a, std::string& s) { // Serialization support for std::vector template bool Save(ArchiveSave& a, const std::vector<_Tp>& v) { - const size_t size(v.size()); + const uint64_t size(v.size()); Save(a, size); - for (size_t i=0; i bool Load(ArchiveLoad& a, std::vector<_Tp>& v) { - size_t size; + uint64_t size; Load(a, size); if (size > 0) { v.resize(size); - for (size_t i=0; i - void serialize(Archive& ar, const unsigned int /*version*/) { + void serialize(Archive& ar, const unsigned int version) { ar & name; ar & platformID; ar & cameraID; ar & poseID; + if (version > 2) { + ar & ID; + } } }; typedef std::vector ImageArr; diff --git a/libs/MVS/Mesh.cpp b/libs/MVS/Mesh.cpp index a44a13b46..48ee5a1f9 100644 --- a/libs/MVS/Mesh.cpp +++ b/libs/MVS/Mesh.cpp @@ -3590,7 +3590,7 @@ void Mesh::ProjectOrtho(const Camera& camera, DepthMap& depthMap) const : Base(_vertices, _camera, _depthMap) {} inline bool ProjectVertex(const Mesh::Vertex& pt, int v) { ptc[v] = camera.TransformPointW2C(Cast(pt)); - pti[v] = camera.TransformPointC2I((const Point2&)ptc[v]); + pti[v] = camera.TransformPointC2I(reinterpret_cast(ptc[v])); return depthMap.isInsideWithBorder(pti[v]); } void Raster(const ImageRef& pt) { @@ -3626,7 +3626,7 @@ void Mesh::ProjectOrtho(const Camera& camera, DepthMap& depthMap, Image8U3& imag } inline bool ProjectVertex(const Mesh::Vertex& pt, int v) { ptc[v] = camera.TransformPointW2C(Cast(pt)); - pti[v] = camera.TransformPointC2I((const Point2&)ptc[v]); + pti[v] = camera.TransformPointC2I(reinterpret_cast(ptc[v])); return depthMap.isInsideWithBorder(pti[v]); } inline bool CheckNormal(const Point3& /*faceCenter*/) { diff --git a/libs/MVS/Scene.cpp b/libs/MVS/Scene.cpp index 6f0ee919a..6520b5cc6 100644 --- a/libs/MVS/Scene.cpp +++ b/libs/MVS/Scene.cpp @@ -279,7 +279,46 @@ bool Scene::SaveInterface(const String & fileName) const } // SaveInterface /*----------------------------------------------------------------*/ -bool Scene::Load(const String& fileName) +// try to load known point-cloud or mesh files +bool Scene::Import(const String& fileName) +{ + const String ext(Util::getFileExt(fileName).ToLower()); + if (ext == _T(".obj")) { + // import mesh from obj file + Release(); + return mesh.Load(fileName); + } + if (ext == _T(".ply")) { + // import point-cloud/mesh from ply file + Release(); + int nVertices(0), nFaces(0); + { + PLY ply; + if (!ply.read(fileName)) { + DEBUG_EXTRA("error: invalid PLY file"); + return false; + } + for (int i = 0; i < (int)ply.elems.size(); ++i) { + int elem_count; + LPCSTR elem_name = ply.setup_element_read(i, &elem_count); + if (PLY::equal_strings("vertex", elem_name)) { + nVertices = elem_count; + } else + if (PLY::equal_strings("face", elem_name)) { + nFaces = elem_count; + } + } + } + if (nVertices && nFaces) + return mesh.Load(fileName); + if (nVertices) + return pointcloud.Load(fileName); + } + return false; +} // Import +/*----------------------------------------------------------------*/ + +bool Scene::Load(const String& fileName, bool bImport) { TD_TIMER_STARTD(); Release(); @@ -294,6 +333,8 @@ bool Scene::Load(const String& fileName) fs.read(szHeader, 4); if (!fs || _tcsncmp(szHeader, PROJECT_ID, 4) != 0) { fs.close(); + if (bImport && Import(fileName)) + return true; if (LoadInterface(fileName)) return true; VERBOSE("error: invalid project"); @@ -546,14 +587,16 @@ bool Scene::ExportCamerasMLP(const String& fileName, const String& fileNameScene " \n" " \n" " \n"; - static const char mlp_raster[] = + static const char mlp_raster_pos[] = " \n" - " \n" " \n" " \n"; @@ -572,13 +615,17 @@ bool Scene::ExportCamerasMLP(const String& fileName, const String& fileNameScene if (!imageData.IsValid()) continue; const Camera& camera = imageData.camera; - f.print(mlp_raster, + f.print(mlp_raster_pos, Util::getFileName(imageData.name).c_str(), - -camera.C.x, -camera.C.y, -camera.C.z, + -camera.C.x, -camera.C.y, -camera.C.z + ); + f.print(mlp_raster_cam, 0, 0, imageData.width, imageData.height, camera.K(1,1)/camera.K(0,0), camera.K(0,0), - camera.K(0,2), camera.K(1,2), + camera.K(0,2), camera.K(1,2) + ); + f.print(mlp_raster_rot, camera.R(0,0), camera.R(0,1), camera.R(0,2), -camera.R(1,0), -camera.R(1,1), -camera.R(1,2), -camera.R(2,0), -camera.R(2,1), -camera.R(2,2), diff --git a/libs/MVS/Scene.h b/libs/MVS/Scene.h index 001eac62d..a84b98928 100644 --- a/libs/MVS/Scene.h +++ b/libs/MVS/Scene.h @@ -67,7 +67,9 @@ class MVS_API Scene bool LoadInterface(const String& fileName); bool SaveInterface(const String& fileName) const; - bool Load(const String& fileName); + bool Import(const String& fileName); + + bool Load(const String& fileName, bool bImport=false); bool Save(const String& fileName, ARCHIVE_TYPE type=ARCHIVE_BINARY_ZIP) const; bool SelectNeighborViews(uint32_t ID, IndexArr& points, unsigned nMinViews=3, unsigned nMinPointViews=2, float fOptimAngle=FD2R(10)); diff --git a/libs/MVS/SceneDensify.cpp b/libs/MVS/SceneDensify.cpp index d9dac6ba2..03d5006c8 100644 --- a/libs/MVS/SceneDensify.cpp +++ b/libs/MVS/SceneDensify.cpp @@ -446,7 +446,7 @@ std::pair TriangulatePointsDelaunay(CGAL::Delaunay& delaunay, const continue; // normally this should never happen const CGAL::FaceCirculator done(cfc); Point3d& poszA = (Point3d&)vcorner->point(); - const Point2d& posA = (const Point2d&)poszA; + const Point2d& posA = reinterpret_cast(poszA); const Ray3d rayA(Point3d::ZERO, normalized(image.camera.TransformPointI2C(poszA))); DepthDistArr depths(0, numPoints); do { @@ -470,7 +470,7 @@ std::pair TriangulatePointsDelaunay(CGAL::Delaunay& delaunay, const const Point3d poszB(rayA.Intersects(planeB)); if (poszB.z <= 0) continue; - const Point2d posB(((const Point2d&)poszB0+(const Point2d&)poszB1+(const Point2d&)poszB2)/3.f); + const Point2d posB((reinterpret_cast(poszB0)+reinterpret_cast(poszB1)+reinterpret_cast(poszB2))/3.f); const REAL dist(norm(posB-posA)); depths.StoreTop(DepthDist((float)poszB.z, 1.f/(float)dist)); } @@ -541,7 +541,7 @@ bool DepthMapsData::InitDepthMap(DepthData& depthData) data.normal = normalized(edge2.cross(edge1)); data.normalPlane = data.normal * INVERT(data.normal.dot(c0)); // draw triangle and for each pixel compute depth as the ray intersection with the plane - Image8U::RasterizeTriangle((const Point2f&)i2, (const Point2f&)i1, (const Point2f&)i0, data); + Image8U::RasterizeTriangle(reinterpret_cast(i2), reinterpret_cast(i1), reinterpret_cast(i0), data); } DEBUG_ULTIMATE("Depth-map %3u roughly estimated from %u sparse points: %dx%d (%s)", &depthData-arrDepthData.Begin(), depthData.points.GetSize(), image.image.width(), image.image.height(), TD_TIMER_GET_FMT().c_str()); @@ -1332,7 +1332,7 @@ void DepthMapsData::FuseDepthMaps(PointCloud& pointcloud, bool bEstimateNormal) CLISTDEF0(Depth*) invalidDepths(0, 32); size_t nDepths(0); typedef TImage DepthIndex; - typedef CLISTDEF(DepthIndex) DepthIndexArr; + typedef cList DepthIndexArr; DepthIndexArr arrDepthIdx(scene.images.GetSize()); ProjsArr projs(0, nPointsEstimate); pointcloud.points.Reserve(nPointsEstimate); diff --git a/libs/MVS/SceneReconstruct.cpp b/libs/MVS/SceneReconstruct.cpp index 49e2f4fc4..88b8c73f0 100644 --- a/libs/MVS/SceneReconstruct.cpp +++ b/libs/MVS/SceneReconstruct.cpp @@ -724,7 +724,21 @@ float computePlaneSphereAngle(const delaunay_t& Tr, const facet_t& facet) return 0.5f; // compute the co-tangent to the circumscribed sphere in one of the vertices + #if CGAL_VERSION_NR < 1041101000 const Point3f cc(CGAL2MVS(facet.first->circumcenter(Tr.geom_traits()))); + #else + struct Tools { + static point_t circumcenter(const delaunay_t& Tr, const facet_t& facet) { + return Tr.geom_traits().construct_circumcenter_3_object()( + facet.first->vertex(0)->point(), + facet.first->vertex(1)->point(), + facet.first->vertex(2)->point(), + facet.first->vertex(3)->point() + ); + } + }; + const Point3f cc(CGAL2MVS(Tools::circumcenter(Tr, facet))); + #endif const Point3f ct(cc-v0); const float ctLenSq(normSq(ct)); if (ctLenSq == 0.f)