Spaces:
Sleeping
Sleeping
typedef unsigned char uchar; | |
std::mutex mtx; | |
class Viewer { | |
public: | |
Viewer( | |
const torch::Tensor image, | |
const torch::Tensor poses, | |
const torch::Tensor points, | |
const torch::Tensor colors, | |
const torch::Tensor intrinsics); | |
void close() { | |
running = false; | |
}; | |
void join() { | |
tViewer.join(); | |
}; | |
void update_image(torch::Tensor img) { | |
mtx.lock(); | |
redraw = true; | |
image = img.permute({1,2,0}).to(torch::kCPU); | |
mtx.unlock(); | |
} | |
// main visualization | |
void run(); | |
private: | |
bool running; | |
std::thread tViewer; | |
int w; | |
int h; | |
int ux; | |
int nPoints, nFrames; | |
const torch::Tensor counter; | |
const torch::Tensor dirty; | |
torch::Tensor image; | |
torch::Tensor poses; | |
torch::Tensor points; | |
torch::Tensor colors; | |
torch::Tensor intrinsics; | |
bool redraw; | |
bool showForeground; | |
bool showBackground; | |
torch::Tensor transformMatrix; | |
double filterThresh; | |
void drawPoints(); | |
void drawPoses(); | |
void initVBO(); | |
void destroyVBO(); | |
// OpenGL buffers (vertex buffer, color buffer) | |
GLuint vbo, cbo; | |
struct cudaGraphicsResource *xyz_res; | |
struct cudaGraphicsResource *rgb_res; | |
}; | |
Viewer::Viewer( | |
const torch::Tensor image, | |
const torch::Tensor poses, | |
const torch::Tensor points, | |
const torch::Tensor colors, | |
const torch::Tensor intrinsics) | |
: image(image), poses(poses), points(points), colors(colors), intrinsics(intrinsics) | |
{ | |
running = true; | |
redraw = true; | |
nFrames = poses.size(0); | |
nPoints = points.size(0); | |
ux = 0; | |
h = image.size(0); | |
w = image.size(1); | |
tViewer = std::thread(&Viewer::run, this); | |
}; | |
void Viewer::drawPoints() { | |
float *xyz_ptr; | |
uchar *rgb_ptr; | |
size_t xyz_bytes; | |
size_t rgb_bytes; | |
unsigned int size_xyz = 3 * points.size(0) * sizeof(float); | |
unsigned int size_rgb = 3 * points.size(0) * sizeof(uchar); | |
cudaGraphicsResourceGetMappedPointer((void **) &xyz_ptr, &xyz_bytes, xyz_res); | |
cudaGraphicsResourceGetMappedPointer((void **) &rgb_ptr, &rgb_bytes, rgb_res); | |
float *xyz_data = points.data_ptr<float>(); | |
cudaMemcpy(xyz_ptr, xyz_data, xyz_bytes, cudaMemcpyDeviceToDevice); | |
uchar *rgb_data = colors.data_ptr<uchar>(); | |
cudaMemcpy(rgb_ptr, rgb_data, rgb_bytes, cudaMemcpyDeviceToDevice); | |
// bind color buffer | |
glBindBuffer(GL_ARRAY_BUFFER, cbo); | |
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); | |
glEnableClientState(GL_COLOR_ARRAY); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
glVertexPointer(3, GL_FLOAT, 0, 0); | |
// bind vertex buffer | |
glEnableClientState(GL_VERTEX_ARRAY); | |
glDrawArrays(GL_POINTS, 0, points.size(0)); | |
glDisableClientState(GL_VERTEX_ARRAY); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
glDisableClientState(GL_COLOR_ARRAY); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
} | |
void Viewer::drawPoses() { | |
float *tptr = transformMatrix.data_ptr<float>(); | |
const int NUM_POINTS = 8; | |
const int NUM_LINES = 10; | |
const float CAM_POINTS[NUM_POINTS][3] = { | |
{ 0, 0, 0}, | |
{-1, -1, 1.5}, | |
{ 1, -1, 1.5}, | |
{ 1, 1, 1.5}, | |
{-1, 1, 1.5}, | |
{-0.5, 1, 1.5}, | |
{ 0.5, 1, 1.5}, | |
{ 0, 1.2, 1.5}}; | |
const int CAM_LINES[NUM_LINES][2] = { | |
{1,2}, {2,3}, {3,4}, {4,1}, {1,0}, {0,2}, {3,0}, {0,4}, {5,7}, {7,6}}; | |
const float SZ = 0.05; | |
glColor3f(0,0.5,1); | |
glLineWidth(1.5); | |
for (int i=0; i<nFrames; i++) { | |
if (i + 1 == nFrames) | |
glColor3f(1,0,0); | |
glPushMatrix(); | |
glMultMatrixf((GLfloat*) (tptr + 4*4*i)); | |
glBegin(GL_LINES); | |
for (int j=0; j<NUM_LINES; j++) { | |
const int u = CAM_LINES[j][0], v = CAM_LINES[j][1]; | |
glVertex3f(SZ*CAM_POINTS[u][0], SZ*CAM_POINTS[u][1], SZ*CAM_POINTS[u][2]); | |
glVertex3f(SZ*CAM_POINTS[v][0], SZ*CAM_POINTS[v][1], SZ*CAM_POINTS[v][2]); | |
} | |
glEnd(); | |
glPopMatrix(); | |
} | |
} | |
void Viewer::initVBO() { | |
glGenBuffers(1, &vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
// initialize buffer object | |
unsigned int size_xyz = 3 * points.size(0) * sizeof(float); | |
glBufferData(GL_ARRAY_BUFFER, size_xyz, 0, GL_DYNAMIC_DRAW); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
// register this buffer object with CUDA | |
cudaGraphicsGLRegisterBuffer(&xyz_res, vbo, cudaGraphicsMapFlagsWriteDiscard); | |
cudaGraphicsMapResources(1, &xyz_res, 0); | |
glGenBuffers(1, &cbo); | |
glBindBuffer(GL_ARRAY_BUFFER, cbo); | |
// initialize buffer object | |
unsigned int size_rgb = 3 * points.size(0) * sizeof(uchar); | |
glBufferData(GL_ARRAY_BUFFER, size_rgb, 0, GL_DYNAMIC_DRAW); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
// register this buffer object with CUDA | |
cudaGraphicsGLRegisterBuffer(&rgb_res, cbo, cudaGraphicsMapFlagsWriteDiscard); | |
cudaGraphicsMapResources(1, &rgb_res, 0); | |
} | |
void Viewer::destroyVBO() { | |
cudaGraphicsUnmapResources(1, &xyz_res, 0); | |
cudaGraphicsUnregisterResource(xyz_res); | |
glBindBuffer(1, vbo); | |
glDeleteBuffers(1, &vbo); | |
cudaGraphicsUnmapResources(1, &rgb_res, 0); | |
cudaGraphicsUnregisterResource(rgb_res); | |
glBindBuffer(1, cbo); | |
glDeleteBuffers(1, &cbo); | |
} | |
void Viewer::run() { | |
// initialize OpenGL buffers | |
pangolin::CreateWindowAndBind("DPVO", 2*640, 2*480); | |
const int UI_WIDTH = 180; | |
glEnable(GL_DEPTH_TEST); | |
pangolin::OpenGlRenderState Visualization3D_camera( | |
pangolin::ProjectionMatrix(w, h,400,400,w/2,h/2,0.1,500), | |
pangolin::ModelViewLookAt(-0,-1,-1, 0,0,0, pangolin::AxisNegY)); | |
pangolin::View& Visualization3D_display = pangolin::CreateDisplay() | |
.SetBounds(0.0, 1.0, pangolin::Attach::Pix(UI_WIDTH), 1.0, -w/(float)h) | |
.SetHandler(new pangolin::Handler3D(Visualization3D_camera)); | |
initVBO(); | |
// UI Knobs | |
// pangolin::CreatePanel("ui").SetBounds(0.8, 1.0, 0.0, pangolin::Attach::Pix(UI_WIDTH)); | |
// pangolin::Var<double> settings_filterThresh("ui.filter",0.5,1e-2,1e2,true); | |
// pangolin::Var<int> settings_frameIndex("ui.index", 0, 0, nFrames-1); | |
// pangolin::Var<bool> settings_showSparse("ui.sparse",true,true); | |
// pangolin::Var<bool> settings_showDense("ui.dense",true,true); | |
// pangolin::Var<bool> settings_showForeground("ui.foreground",true,true); | |
// pangolin::Var<bool> settings_showBackground("ui.background",true,true); | |
pangolin::View& d_video = pangolin::Display("imgVideo").SetAspect(w/(float)h); | |
pangolin::GlTexture texVideo(w,h,GL_RGB,false,0,GL_RGB,GL_UNSIGNED_BYTE); | |
pangolin::CreateDisplay() | |
.SetBounds(0.0, 0.3, 0.0, 1.0) | |
.SetLayout(pangolin::LayoutEqual) | |
.AddDisplay(d_video); | |
while( !pangolin::ShouldQuit() && running ) { | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glClearColor(1.0f,1.0f,1.0f,1.0f); | |
Visualization3D_display.Activate(Visualization3D_camera); | |
// maybe possible to draw cameras without copying to CPU? | |
transformMatrix = poseToMatrix(poses); | |
transformMatrix = transformMatrix.transpose(1,2); | |
transformMatrix = transformMatrix.contiguous().to(torch::kCPU); | |
// draw poses using OpenGL | |
drawPoints(); | |
drawPoses(); | |
mtx.lock(); | |
if (redraw) { | |
redraw = false; | |
texVideo.Upload(image.data_ptr(), GL_BGR, GL_UNSIGNED_BYTE); | |
} | |
mtx.unlock(); | |
d_video.Activate(); | |
glColor4f(1.0f,1.0f,1.0f,1.0f); | |
texVideo.RenderToViewportFlipY(); | |
pangolin::FinishFrame(); | |
} | |
// destroy OpenGL buffers | |
// destroyVBO(); | |
running = false; | |
exit(1); | |
} | |
namespace py = pybind11; | |
PYBIND11_MODULE(dpviewerx, m) { | |
py::class_<Viewer>(m, "Viewer") | |
.def(py::init<const torch::Tensor, | |
const torch::Tensor, | |
const torch::Tensor, | |
const torch::Tensor, | |
const torch::Tensor>()) | |
.def("update_image", &Viewer::update_image) | |
.def("join", &Viewer::join); | |
} | |