You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
9.4 KiB
303 lines
9.4 KiB
// This file is part of OpenCV project. |
|
// It is subject to the license terms in the LICENSE file found in the top-level directory |
|
// of this distribution and at http://opencv.org/license.html |
|
|
|
// This code is also subject to the license terms in the LICENSE_KinectFusion.md file found in this module's directory |
|
|
|
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE |
|
|
|
#include <iostream> |
|
#include <fstream> |
|
#include <opencv2/imgproc.hpp> |
|
#include <opencv2/calib3d.hpp> |
|
#include <opencv2/highgui.hpp> |
|
#include <opencv2/core/utils/logger.hpp> |
|
#include <opencv2/rgbd.hpp> |
|
#include "io_utils.hpp" |
|
|
|
using namespace cv; |
|
using namespace cv::dynafu; |
|
using namespace cv::io_utils; |
|
|
|
#ifdef HAVE_OPENCV_VIZ |
|
#include <opencv2/viz.hpp> |
|
#endif |
|
|
|
#ifdef HAVE_OPENCV_VIZ |
|
const std::string vizWindowName = "cloud"; |
|
|
|
struct PauseCallbackArgs |
|
{ |
|
PauseCallbackArgs(DynaFu& _df) : df(_df) |
|
{ } |
|
|
|
DynaFu& df; |
|
}; |
|
|
|
void pauseCallback(const viz::MouseEvent& me, void* args); |
|
void pauseCallback(const viz::MouseEvent& me, void* args) |
|
{ |
|
if(me.type == viz::MouseEvent::Type::MouseMove || |
|
me.type == viz::MouseEvent::Type::MouseScrollDown || |
|
me.type == viz::MouseEvent::Type::MouseScrollUp) |
|
{ |
|
PauseCallbackArgs pca = *((PauseCallbackArgs*)(args)); |
|
viz::Viz3d window(vizWindowName); |
|
UMat rendered; |
|
pca.df.render(rendered, window.getViewerPose().matrix); |
|
imshow("render", rendered); |
|
waitKey(1); |
|
} |
|
} |
|
#endif |
|
|
|
static const char* keys = |
|
{ |
|
"{help h usage ? | | print this message }" |
|
"{depth | | Path to depth.txt file listing a set of depth images }" |
|
"{camera |0| Index of depth camera to be used as a depth source }" |
|
"{coarse | | Run on coarse settings (fast but ugly) or on default (slow but looks better)," |
|
" in coarse mode points and normals are displayed }" |
|
"{idle | | Do not run DynaFu, just display depth frames }" |
|
"{record | | Write depth frames to specified file list" |
|
" (the same format as for the 'depth' key) }" |
|
}; |
|
|
|
static const std::string message = |
|
"\nThis demo uses live depth input or RGB-D dataset taken from" |
|
"\nhttps://vision.in.tum.de/data/datasets/rgbd-dataset" |
|
"\nto demonstrate KinectFusion implementation \n"; |
|
|
|
|
|
int main(int argc, char **argv) |
|
{ |
|
bool coarse = false; |
|
bool idle = false; |
|
std::string recordPath; |
|
|
|
CommandLineParser parser(argc, argv, keys); |
|
parser.about(message); |
|
|
|
if(!parser.check()) |
|
{ |
|
parser.printMessage(); |
|
parser.printErrors(); |
|
return -1; |
|
} |
|
|
|
if(parser.has("help")) |
|
{ |
|
parser.printMessage(); |
|
return 0; |
|
} |
|
if(parser.has("coarse")) |
|
{ |
|
coarse = true; |
|
} |
|
if(parser.has("record")) |
|
{ |
|
recordPath = parser.get<String>("record"); |
|
} |
|
if(parser.has("idle")) |
|
{ |
|
idle = true; |
|
} |
|
|
|
Ptr<DepthSource> ds; |
|
if (parser.has("depth")) |
|
ds = makePtr<DepthSource>(parser.get<String>("depth")); |
|
else |
|
ds = makePtr<DepthSource>(parser.get<int>("camera")); |
|
|
|
if (ds->empty()) |
|
{ |
|
std::cerr << "Failed to open depth source" << std::endl; |
|
parser.printMessage(); |
|
return -1; |
|
} |
|
|
|
Ptr<DepthWriter> depthWriter; |
|
if(!recordPath.empty()) |
|
depthWriter = makePtr<DepthWriter>(recordPath); |
|
|
|
Ptr<kinfu::Params> params; |
|
Ptr<DynaFu> df; |
|
|
|
if(coarse) |
|
params = kinfu::Params::coarseParams(); |
|
else |
|
params = kinfu::Params::defaultParams(); |
|
|
|
// These params can be different for each depth sensor |
|
ds->updateParams(*params); |
|
|
|
// Enables OpenCL explicitly (by default can be switched-off) |
|
cv::setUseOptimized(false); |
|
|
|
// Scene-specific params should be tuned for each scene individually |
|
//params->volumePose = params->volumePose.translate(Vec3f(0.f, 0.f, 0.5f)); |
|
//params->tsdf_max_weight = 16; |
|
|
|
namedWindow("OpenGL Window", WINDOW_OPENGL); |
|
resizeWindow("OpenGL Window", 1, 1); |
|
if(!idle) |
|
df = DynaFu::create(params); |
|
|
|
#ifdef HAVE_OPENCV_VIZ |
|
cv::viz::Viz3d window(vizWindowName); |
|
window.setViewerPose(Affine3f::Identity()); |
|
bool pause = false; |
|
#endif |
|
|
|
UMat rendered; |
|
UMat points; |
|
UMat normals; |
|
|
|
int64 prevTime = getTickCount(); |
|
|
|
|
|
for(UMat frame = ds->getDepth(); !frame.empty(); frame = ds->getDepth()) |
|
{ |
|
Mat depthImg, vertImg, normImg; |
|
setOpenGlContext("OpenGL Window"); |
|
df->renderSurface(depthImg, vertImg, normImg); |
|
if(!depthImg.empty()) |
|
{ |
|
UMat depthCvt8, vertCvt8, normCvt8; |
|
convertScaleAbs(depthImg, depthCvt8, 0.33*255); |
|
vertImg.convertTo(vertCvt8, CV_8UC3, 255); |
|
normImg.convertTo(normCvt8, CV_8UC3, 255); |
|
|
|
imshow("Surface prediction", depthCvt8); |
|
imshow("vertex prediction", vertCvt8); |
|
imshow("normal prediction", normCvt8); |
|
} |
|
|
|
if(depthWriter) |
|
depthWriter->append(frame); |
|
|
|
#ifdef HAVE_OPENCV_VIZ |
|
if(pause) |
|
{ |
|
// doesn't happen in idle mode |
|
df->getCloud(points, normals); |
|
|
|
if(!points.empty() && !normals.empty()) |
|
{ |
|
viz::WCloud cloudWidget(points, viz::Color::white()); |
|
viz::WCloudNormals cloudNormals(points, normals, /*level*/1, /*scale*/0.05, viz::Color::gray()); |
|
|
|
Vec3d volSize = df->getParams().voxelSize*Vec3d(df->getParams().volumeDims); |
|
window.showWidget("cube", viz::WCube(Vec3d::all(0), |
|
volSize), |
|
df->getParams().volumePose); |
|
PauseCallbackArgs pca(*df); |
|
window.registerMouseCallback(pauseCallback, (void*)&pca); |
|
window.showWidget("text", viz::WText(cv::String("Move camera in this window. " |
|
"Close the window or press Q to resume"), Point())); |
|
window.spin(); |
|
window.removeWidget("text"); |
|
//window.removeWidget("cloud"); |
|
//window.removeWidget("normals"); |
|
window.registerMouseCallback(0); |
|
} |
|
|
|
pause = false; |
|
} |
|
else |
|
#endif |
|
{ |
|
UMat cvt8; |
|
float depthFactor = params->depthFactor; |
|
convertScaleAbs(frame, cvt8, 0.25*256. / depthFactor); |
|
if(!idle) |
|
{ |
|
imshow("depth", cvt8); |
|
|
|
if(!df->update(frame)) |
|
{ |
|
df->reset(); |
|
std::cout << "reset" << std::endl; |
|
} |
|
#ifdef HAVE_OPENCV_VIZ |
|
else |
|
{ |
|
Mat meshCloud, meshEdges, meshPoly; |
|
df->marchCubes(meshCloud, meshEdges); |
|
for(int i = 0; i < meshEdges.size().height; i += 3) |
|
{ |
|
meshPoly.push_back<int>(3); |
|
meshPoly.push_back<int>(meshEdges.at<int>(i, 0)); |
|
meshPoly.push_back<int>(meshEdges.at<int>(i+1, 0)); |
|
meshPoly.push_back<int>(meshEdges.at<int>(i+2, 0)); |
|
} |
|
|
|
viz::WMesh mesh(meshCloud.t(), meshPoly); |
|
window.showWidget("mesh", mesh); |
|
|
|
if(coarse) |
|
{ |
|
df->getCloud(points, normals); |
|
|
|
if(!points.empty() && !normals.empty()) |
|
{ |
|
viz::WCloud cloudWidget(points, viz::Color::white()); |
|
viz::WCloudNormals cloudNormals(points, normals, /*level*/1, /*scale*/0.05, viz::Color::gray()); |
|
//window.showWidget("cloud", cloudWidget); |
|
//window.showWidget("normals", cloudNormals); |
|
if(!df->getNodesPos().empty()) |
|
{ |
|
viz::WCloud nodeCloud(df->getNodesPos(), viz::Color::red()); |
|
nodeCloud.setRenderingProperty(viz::POINT_SIZE, 4); |
|
window.showWidget("nodes", nodeCloud); |
|
} |
|
} |
|
} |
|
|
|
//window.showWidget("worldAxes", viz::WCoordinateSystem()); |
|
Vec3d volSize = df->getParams().voxelSize*df->getParams().volumeDims; |
|
window.showWidget("cube", viz::WCube(Vec3d::all(0), |
|
volSize), |
|
df->getParams().volumePose); |
|
window.setViewerPose(df->getPose()); |
|
window.spinOnce(1, true); |
|
} |
|
#endif |
|
|
|
df->render(rendered); |
|
} |
|
else |
|
{ |
|
rendered = cvt8; |
|
} |
|
} |
|
|
|
int64 newTime = getTickCount(); |
|
putText(rendered, cv::format("FPS: %2d press R to reset, P to pause, Q to quit", |
|
(int)(getTickFrequency()/(newTime - prevTime))), |
|
Point(0, rendered.rows-1), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 255)); |
|
prevTime = newTime; |
|
|
|
imshow("render", rendered); |
|
|
|
int c = waitKey(1); |
|
switch (c) |
|
{ |
|
case 'r': |
|
if(!idle) |
|
df->reset(); |
|
break; |
|
case 'q': |
|
return 0; |
|
#ifdef HAVE_OPENCV_VIZ |
|
case 'p': |
|
if(!idle) |
|
pause = true; |
|
#endif |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
return 0; |
|
}
|
|
|