diff --git a/apps/Tests/Tests.cpp b/apps/Tests/Tests.cpp index b8af6437d..ebc730cbd 100644 --- a/apps/Tests/Tests.cpp +++ b/apps/Tests/Tests.cpp @@ -75,6 +75,10 @@ bool UnitTests() bool PipelineTest(bool verbose=false) { TD_TIMER_START(); + #if 0 && defined(_USE_CUDA) + // force CPU for testing even if CUDA is available + SEACAVE::CUDA::desiredDeviceID = -2; + #endif Scene scene; if (!scene.Load(MAKE_PATH("scene.mvs"))) { VERBOSE("ERROR: TestDataset failed loading the scene!"); @@ -88,7 +92,7 @@ bool PipelineTest(bool verbose=false) } if (verbose) scene.pointcloud.Save(MAKE_PATH("scene_dense.ply")); - if (!scene.ReconstructMesh() || scene.mesh.faces.size() < 40000u) { + if (!scene.ReconstructMesh() || scene.mesh.faces.size() < 25000u) { VERBOSE("ERROR: TestDataset failed reconstructing the mesh!"); return false; } @@ -96,7 +100,7 @@ bool PipelineTest(bool verbose=false) scene.mesh.Save(MAKE_PATH("scene_dense_mesh.ply")); constexpr float decimate = 0.7f; scene.mesh.Clean(decimate); - if (!ISINSIDE(scene.mesh.faces.size(), 25000u, 45000u)) { + if (!ISINSIDE(scene.mesh.faces.size(), 20000u, 30000u)) { VERBOSE("ERROR: TestDataset failed cleaning the mesh!"); return false; } diff --git a/libs/Common/Common.h b/libs/Common/Common.h index eba19aeae..0decd1ace 100644 --- a/libs/Common/Common.h +++ b/libs/Common/Common.h @@ -78,6 +78,12 @@ namespace SEACAVE { extern int g_nVerbosityLevel; } #define LOG_ERR() GET_LOG() //or std::cerr +#ifdef PRINT_ASSERT_MSG +#undef PRINT_ASSERT_MSG +#define PRINT_ASSERT_MSG(exp, ...) {std::cout << SEACAVE::PrintMessageToString("ASSERTION FAILED: (" #exp ") ", __VA_ARGS__) << std::endl;} +#endif + + // macros simplifying the task of composing file paths; // WORKING_FOLDER and WORKING_FOLDER_FULL must be defined as strings // containing the relative/full path to the working folder @@ -86,7 +92,7 @@ namespace SEACAVE { class String; extern String g_strWorkingFolder; // empty by default (current folder) extern String g_strWorkingFolderFull; // full path to current folder -} +} // namespace SEACAVE #define WORKING_FOLDER g_strWorkingFolder // empty by default (current folder) #define WORKING_FOLDER_FULL g_strWorkingFolderFull // full path to current folder #endif diff --git a/libs/Common/Config.h b/libs/Common/Config.h index 1165bfdc2..69363eae9 100644 --- a/libs/Common/Config.h +++ b/libs/Common/Config.h @@ -216,6 +216,8 @@ #define SAFE_RELEASE(p) { if (p!=NULL) { (p)->Release(); (p)=NULL; } } +#define PRINT_ASSERT_MSG(exp, ...) + #ifdef _DEBUG #ifdef _MSC_VER @@ -224,26 +226,32 @@ #include #include #ifdef _INC_CRTDBG -#define ASSERT(exp, ...) {if (!(exp) && 1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, #exp)) _CrtDbgBreak();} +#define SIMPLE_ASSERT(exp) {if (!(exp) && 1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, #exp)) _CrtDbgBreak();} +#define ASSERT(exp, ...) {static bool bIgnore(false); if (!bIgnore && !(exp)) {PRINT_ASSERT_MSG(exp, __VA_ARGS__); if (!(bIgnore = !(1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, #exp)))) _CrtDbgBreak();}} #else -#define ASSERT(exp, ...) {if (!(exp)) __debugbreak();} +#define SIMPLE_ASSERT(exp) {if (!(exp)) __debugbreak();} +#define ASSERT(exp, ...) {if (!(exp)) {PRINT_ASSERT_MSG(exp, __VA_ARGS__); __debugbreak();}} #endif // _INC_CRTDBG #define TRACE(...) {TCHAR buffer[2048]; _sntprintf(buffer, 2048, __VA_ARGS__); OutputDebugString(buffer);} #else // _MSC_VER #include -#define ASSERT(exp, ...) assert(exp) +#define SIMPLE_ASSERT(exp) {if (!(exp)) assert(exp);} +#define ASSERT(exp, ...) {if (!(exp)) {PRINT_ASSERT_MSG(exp, __VA_ARGS__); assert(exp);}} #define TRACE(...) #endif // _MSC_VER #else #ifdef _RELEASE +#define SIMPLE_ASSERT(exp) #define ASSERT(exp, ...) #else #ifdef _MSC_VER -#define ASSERT(exp, ...) {if (!(exp)) __debugbreak();} +#define SIMPLE_ASSERT(exp) {if (!(exp)) __debugbreak();} +#define ASSERT(exp, ...) {if (!(exp)) {PRINT_ASSERT_MSG(exp, __VA_ARGS__); __debugbreak();}} #else // _MSC_VER -#define ASSERT(exp, ...) {if (!(exp)) __builtin_trap();} +#define SIMPLE_ASSERT(exp) {if (!(exp)) __builtin_trap();} +#define ASSERT(exp, ...) {if (!(exp)) {PRINT_ASSERT_MSG(exp, __VA_ARGS__); __builtin_trap();}} #endif // _MSC_VER #endif #define TRACE(...) diff --git a/libs/Common/Rotation.inl b/libs/Common/Rotation.inl index 81b2d0097..ca0a8d11c 100644 --- a/libs/Common/Rotation.inl +++ b/libs/Common/Rotation.inl @@ -1176,8 +1176,8 @@ void TRMatrixBase::SetFromHV(const Vec& xxx, const Vec& yyy) template TRMatrixBase& TRMatrixBase::SetFromDir2Dir(const Vec& dir0, const Vec& dir1) { - ASSERT(ISEQUAL(norm(dir0), TYPE(1))); - ASSERT(ISEQUAL(norm(dir1), TYPE(1))); + ASSERT(ISEQUAL(norm(dir0), TYPE(1)), "Norm = ", norm(dir0)); + ASSERT(ISEQUAL(norm(dir1), TYPE(1)), "Norm = ", norm(dir1)); const TYPE cos01(CLAMP(dir1.dot(dir0), TYPE(-1), TYPE(1))); const TYPE sin01Sq(TYPE(1) - SQUARE(cos01)); if (sin01Sq > EPSILONTOLERANCE()) { @@ -1203,8 +1203,8 @@ TRMatrixBase& TRMatrixBase::SetFromDir2Dir(const Vec& dir0, const Ve template void TRMatrixBase::SetFromDirUpGL(const Vec& viewDir, const Vec& viewUp) { - ASSERT(ISEQUAL(norm(viewDir), TYPE(1))); - ASSERT(ISEQUAL(norm(viewUp), TYPE(1))); + ASSERT(ISEQUAL(norm(viewDir), TYPE(1)), "Norm = ", norm(viewDir)); + ASSERT(ISEQUAL(norm(viewUp), TYPE(1)), "Norm = ", norm(viewUp)); const Vec right(normalized(cross(viewDir, viewUp))); const Vec up(normalized(cross(right, viewDir))); const Vec forward(viewDir * TYPE(-1)); // convert to right handed system @@ -1214,8 +1214,8 @@ void TRMatrixBase::SetFromDirUpGL(const Vec& viewDir, const Vec& viewUp) template void TRMatrixBase::SetFromDirUp(const Vec& viewDir, const Vec& viewUp) { - ASSERT(ISEQUAL(norm(viewDir), TYPE(1))); - ASSERT(ISEQUAL(norm(viewUp), TYPE(1))); + ASSERT(ISEQUAL(norm(viewDir), TYPE(1)), "Norm = ", norm(viewDir)); + ASSERT(ISEQUAL(norm(viewUp), TYPE(1)), "Norm = ", norm(viewUp)); const Vec right(normalized(cross(viewDir, viewUp))); const Vec up(normalized(cross(viewDir, right))); const Vec& forward(viewDir); diff --git a/libs/Common/Types.h b/libs/Common/Types.h index a34499a62..625ae6af1 100644 --- a/libs/Common/Types.h +++ b/libs/Common/Types.h @@ -378,6 +378,25 @@ typedef TAliasCast CastD2I; #endif +// functions simplifying the task of printing messages +namespace SEACAVE { +// print the given message composed of any number of arguments to the given stream +template +std::ostringstream& PrintMessageToStream(std::ostringstream& oss, Args&&... args) { + // fold expression to insert all arguments into the stream + (oss << ... << args); + return oss; +} +// print the given message composed of any number of arguments to a string +template +std::string PrintMessageToString(Args&&... args) { + std::ostringstream oss; + (oss << ... << args); + return oss.str(); +} +} // namespace SEACAVE + + // I N C L U D E S ///////////////////////////////////////////////// #include "Strings.h" @@ -681,13 +700,13 @@ constexpr T factorial(T n) { } template constexpr T combinations(const T& n, const T& k) { - ASSERT(n >= k); + SIMPLE_ASSERT(n >= k); #if 1 T num = n; const T den = factorial(k); for (T i=n-k+1; i PerspectiveCorrectBarycentricCoordinates(const TPoint3 inline void Normal2Dir(const TPoint3& d, TPoint2& p) { - ASSERT(ISEQUAL(norm(d), T(1))); + ASSERT(ISEQUAL(norm(d), T(1)), "Norm = ", norm(d)); p.x = TR(atan2(d.y, d.x)); p.y = TR(acos(d.z)); } @@ -762,7 +762,7 @@ inline void Dir2Normal(const TPoint2& p, TPoint3& d) { d.x = TR(cos(p.x)*siny); d.y = TR(sin(p.x)*siny); d.z = TR(cos(p.y)); - ASSERT(ISEQUAL(norm(d), TR(1))); + ASSERT(ISEQUAL(norm(d), TR(1)), "Norm = ", norm(d)); } // Encodes/decodes a 3D vector in two parameters for the direction and one parameter for the scale template diff --git a/libs/MVS/DepthMap.cpp b/libs/MVS/DepthMap.cpp index 5e4a7eca1..3a64232e9 100644 --- a/libs/MVS/DepthMap.cpp +++ b/libs/MVS/DepthMap.cpp @@ -663,130 +663,57 @@ void DepthEstimator::ProcessPixel(IDX idx) #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA neighborsClose.Empty(); #endif - if (dir == LT2RB) { - // direction from left-top to right-bottom corner - if (x0.x > nSizeHalfWindow) { - const ImageRef nx(x0.x-1, x0.y); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighbors.emplace_back(nx); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - #else - neighbors.emplace_back(NeighborData{nx,ndepth,normalMap0(nx)}); + const auto AddDirectionNeighbor = [this] (const ImageRef& nx) { + const Depth ndepth(depthMap0(nx)); + if (ndepth > 0) { + #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA + ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f), "Norm = ", norm(normalMap0(nx))); + neighbors.emplace_back(nx); + neighborsClose.emplace_back(NeighborEstimate{ndepth, normalMap0(nx) + #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE + , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) #endif - } + }); + #else + neighbors.emplace_back(NeighborData{nx,ndepth,normalMap0(nx)}); + #endif } - if (x0.y > nSizeHalfWindow) { - const ImageRef nx(x0.x, x0.y-1); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighbors.emplace_back(nx); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - #else - neighbors.emplace_back(NeighborData{nx,ndepth,normalMap0(nx)}); + }; + const auto AddDirection = [this] (const ImageRef& nx) { + const Depth ndepth(depthMap0(nx)); + if (ndepth > 0) { + ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f), "Norm = ", norm(normalMap0(nx))); + neighborsClose.emplace_back(NeighborEstimate{ndepth, normalMap0(nx) + #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE + , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) #endif - } - } - #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA - if (x0.x < size.width-nSizeHalfWindow) { - const ImageRef nx(x0.x+1, x0.y); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - } - } - if (x0.y < size.height-nSizeHalfWindow) { - const ImageRef nx(x0.x, x0.y+1); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif }); - } } + }; + if (dir == LT2RB) { + // direction from left-top to right-bottom corner + if (x0.x > nSizeHalfWindow) + AddDirectionNeighbor(ImageRef(x0.x-1, x0.y)); + if (x0.y > nSizeHalfWindow) + AddDirectionNeighbor(ImageRef(x0.x, x0.y-1)); + #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA + if (x0.x < size.width-nSizeHalfWindow) + AddDirection(ImageRef(x0.x+1, x0.y)); + if (x0.y < size.height-nSizeHalfWindow) + AddDirection(ImageRef(x0.x, x0.y+1)); #endif } else { ASSERT(dir == RB2LT); // direction from right-bottom to left-top corner - if (x0.x < size.width-nSizeHalfWindow) { - const ImageRef nx(x0.x+1, x0.y); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighbors.emplace_back(nx); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - #else - neighbors.emplace_back(NeighborData{nx,ndepth,normalMap0(nx)}); - #endif - } - } - if (x0.y < size.height-nSizeHalfWindow) { - const ImageRef nx(x0.x, x0.y+1); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighbors.emplace_back(nx); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - #else - neighbors.emplace_back(NeighborData{nx,ndepth,normalMap0(nx)}); - #endif - } - } + if (x0.x < size.width-nSizeHalfWindow) + AddDirectionNeighbor(ImageRef(x0.x+1, x0.y)); + if (x0.y < size.height-nSizeHalfWindow) + AddDirectionNeighbor(ImageRef(x0.x, x0.y+1)); #if DENSE_SMOOTHNESS != DENSE_SMOOTHNESS_NA - if (x0.x > nSizeHalfWindow) { - const ImageRef nx(x0.x-1, x0.y); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - } - } - if (x0.y > nSizeHalfWindow) { - const ImageRef nx(x0.x, x0.y-1); - const Depth ndepth(depthMap0(nx)); - if (ndepth > 0) { - ASSERT(ISEQUAL(norm(normalMap0(nx)), 1.f)); - neighborsClose.emplace_back(NeighborEstimate{ndepth,normalMap0(nx) - #if DENSE_SMOOTHNESS == DENSE_SMOOTHNESS_PLANE - , Cast(image0.camera.TransformPointI2C(Point3(nx, ndepth))) - #endif - }); - } - } + if (x0.x > nSizeHalfWindow) + AddDirection(ImageRef(x0.x-1, x0.y)); + if (x0.y > nSizeHalfWindow) + AddDirection(ImageRef(x0.x, x0.y-1)); #endif } float& conf = confMap0(x0); @@ -1027,7 +954,7 @@ DepthEstimator::PixelEstimate DepthEstimator::PerturbEstimate(const PixelEstimat } perturbation *= 0.5f; } - ASSERT(ISEQUAL(norm(ptbEst.normal), 1.f)); + ASSERT(ISEQUAL(norm(ptbEst.normal), 1.f), "Norm = ", norm(ptbEst.normal)); return ptbEst; } diff --git a/libs/MVS/DepthMap.h b/libs/MVS/DepthMap.h index 52ed84cd5..7246d2a5c 100644 --- a/libs/MVS/DepthMap.h +++ b/libs/MVS/DepthMap.h @@ -453,7 +453,7 @@ struct MVS_API DepthEstimator { inline Normal RandomNormal(const Point3f& viewRay) { Normal normal; Dir2Normal(Point2f(rnd.randomRange(FD2R(0.f),FD2R(180.f)), rnd.randomRange(FD2R(90.f),FD2R(180.f))), normal); - ASSERT(ISEQUAL(norm(normal), 1.f)); + ASSERT(ISEQUAL(norm(normal), 1.f), "Norm = ", norm(normal)); return normal.dot(viewRay) > 0 ? -normal : normal; } @@ -463,7 +463,7 @@ struct MVS_API DepthEstimator { const float cosAngLen(normal.dot(viewDir)); if (cosAngLen >= 0) normal = RMatrixBaseF(normal.cross(viewDir), MINF((ACOS(cosAngLen/norm(viewDir))-FD2R(90.f))*1.01f, -0.001f)) * normal; - ASSERT(ISEQUAL(norm(normal), 1.f)); + ASSERT(ISEQUAL(norm(normal), 1.f), "Norm = ", norm(normal)); } static bool ImportIgnoreMask(const Image&, const Image8U::Size&, uint16_t nIgnoreMaskLabel, BitMatrix&, Image8U* =NULL); diff --git a/libs/MVS/Scene.cpp b/libs/MVS/Scene.cpp index 5df98349f..a81bd46d3 100644 --- a/libs/MVS/Scene.cpp +++ b/libs/MVS/Scene.cpp @@ -1847,7 +1847,7 @@ size_t Scene::DrawCircle(PointCloud& pc, PointCloud::PointArr& outCircle, const const float fAngle(fStartAngle + fAngleBetweenPoints * pIdx); ASSERT(fAngle <= FTWO_PI); const Normal n(cos(fAngle), sin(fAngle), 0); - ASSERT(ISEQUAL(norm(n), 1.f)); + ASSERT(ISEQUAL(norm(n), 1.f), "Norm = ", norm(n)); const Point3f newPoint(circleCenter + circleRadius * n); // select cameras seeing this point PointCloud::ViewArr views; diff --git a/libs/MVS/SceneDensify.cpp b/libs/MVS/SceneDensify.cpp index 8a6a84622..96f321d30 100644 --- a/libs/MVS/SceneDensify.cpp +++ b/libs/MVS/SceneDensify.cpp @@ -381,7 +381,7 @@ void* STCALL DepthMapsData::ScoreDepthMapTmp(void* arg) // replace invalid normal with random values normal = estimator.RandomNormal(viewDir); } - ASSERT(ISEQUAL(norm(normal), 1.f)); + ASSERT(ISEQUAL(norm(normal), 1.f), "Norm = ", norm(normal)); estimator.confMap0(x) = estimator.ScorePixel(depth, normal); } return NULL; @@ -1481,7 +1481,7 @@ void DepthMapsData::FuseDepthMaps(PointCloud& pointcloud, bool bEstimateColor, b ProjArr& pointProjs = projs.emplace_back(); pointProjs.emplace_back(Proj(x)); const PointCloud::Normal normal(!depthData.normalMap.empty() ? Cast(imageData.camera.R.t() * Cast(depthData.normalMap(x))) : Normal(0, 0, -1)); - ASSERT(ISEQUAL(norm(normal), 1.f)); + ASSERT(ISEQUAL(norm(normal), 1.f), "Norm = ", norm(normal)); // check the projection in the neighbor depth-maps Point3 X(point*confidence); Pixel32F C(Cast(imageData.image(x))*confidence); @@ -1509,7 +1509,7 @@ void DepthMapsData::FuseDepthMaps(PointCloud& pointcloud, bool bEstimateColor, b if (IsDepthSimilar(pt.z, depthB, OPTDENSE::fDepthDiffThreshold)) { // check if normals agree const PointCloud::Normal normalB(!depthData.normalMap.empty() ? Cast(imageDataB.camera.R.t() * Cast(depthDataB.normalMap(xB))) : Normal(0, 0, -1)); - ASSERT(ISEQUAL(norm(normalB), 1.f)); + ASSERT(ISEQUAL(norm(normalB), 1.f), "Norm = ", norm(normalB)); if (normal.dot(normalB) > normalError) { // add view to the 3D point ASSERT(views.FindFirst(idxImageB) == PointCloud::ViewArr::NO_INDEX); @@ -1688,12 +1688,12 @@ void DepthMapsData::DenseFuseDepthMaps(PointCloud& pointcloud, bool bEstimateCol return; // check if normals agree normal = image.camera.R.t() * Cast(depthData.normalMap(x)); - ASSERT(ISEQUAL(norm(normal), 1.f)); + ASSERT(ISEQUAL(norm(normal), 1.f), "Norm = ", norm(normal)); if (refNormal.dot(normal) < normalError) return; } else { normal = image.camera.R.t() * Cast(depthData.normalMap(x)); - ASSERT(ISEQUAL(norm(normal), 1.f)); + ASSERT(ISEQUAL(norm(normal), 1.f), "Norm = ", norm(normal)); } // set the current pixel as visited useMask.set(x);