-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Gernot Riegler
authored and
Gernot Riegler
committed
Oct 11, 2017
0 parents
commit 8e5cbcd
Showing
6 changed files
with
353 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
build/ | ||
pyrender.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# PyRender | ||
|
||
This project contains a Cython version of [librender by Andreas Geiger and Chaohui Wang 2014](http://www.cvlibs.net/software/librender/). | ||
The code enables the efficient rendering of depth maps from 3D triangle meshes. | ||
|
||
To use the code, first compile the Cython code via | ||
|
||
```bash | ||
python setup.py build-ext --inplace | ||
``` | ||
|
||
You can then use the rendering function | ||
|
||
```python | ||
import pyrender | ||
... | ||
# vertices: a 3xN double numpy array | ||
# faces: a 3xN double array (indices of vertices array) | ||
# cam_intr: (fx, fy, px, py) double vector | ||
# img_size: (width, height) int vector | ||
depth, mask, img = pyrender.render(vertices, faces, cam_intr, img_size) | ||
``` | ||
|
||
Make sure `pyrender` is in your `$PYTHONPATH`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
#include "offscreen.h" | ||
|
||
int OffscreenGL::glutWin = -1; | ||
bool OffscreenGL::glutInitialized = false; | ||
|
||
OffscreenGL::OffscreenGL(int maxHeight, int maxWidth) { | ||
|
||
if (!glutInitialized) { | ||
int argc = 1; | ||
char *argv = "test"; | ||
glutInit(&argc, &argv); | ||
glutInitialized = true; | ||
} | ||
|
||
glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); | ||
glutInitWindowPosition(100, 100); | ||
glutInitWindowSize(maxWidth, maxHeight); | ||
|
||
// create or set window & off-screen framebuffer | ||
if (glutWin < 0) { | ||
|
||
glutWin = glutCreateWindow("OpenGL"); | ||
glutHideWindow(); | ||
glewInit(); | ||
glGenFramebuffersEXT(1, &fb); | ||
|
||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); | ||
glGenTextures(1, &renderTex); | ||
glActiveTexture(GL_TEXTURE0); | ||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, renderTex); | ||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, maxWidth, maxHeight, | ||
0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | ||
|
||
glGenTextures(1, &depthTex); | ||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, depthTex); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); | ||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); | ||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH24_STENCIL8, maxWidth, maxHeight, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); | ||
|
||
glGenFramebuffersEXT(1, &fb); | ||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); | ||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, renderTex, 0); | ||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_RECTANGLE_ARB, depthTex, 0); | ||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT|GL_DEPTH_ATTACHMENT_EXT); | ||
} else { | ||
glutSetWindow(glutWin); | ||
} | ||
} | ||
|
||
OffscreenGL::~OffscreenGL() { | ||
} | ||
|
||
|
||
GLuint createDisplayList(double *fM, int fNum, double *vM, int vNum, double *cM, unsigned int colorModFactor, double linewidth, bool coloring, bool one_offset) { | ||
|
||
GLuint theShape; | ||
int i; | ||
unsigned int channelCapacity, channelCapacity2; | ||
double *fp; | ||
int vIndex, fNum2; | ||
fNum2 = fNum*2; | ||
|
||
channelCapacity = 256 / colorModFactor; | ||
channelCapacity2 = channelCapacity * channelCapacity; | ||
|
||
theShape = glGenLists(1); | ||
|
||
glNewList(theShape, GL_COMPILE); | ||
|
||
if (linewidth>0.1) { | ||
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); | ||
glLineWidth(linewidth); | ||
} | ||
|
||
glBegin(GL_TRIANGLES); | ||
for (i = 1; i <= fNum; i++) { | ||
fp = fM + i-1; | ||
|
||
vIndex = (int)fp[0] - one_offset; | ||
if (coloring) glColor3ub(cM[vIndex], cM[vIndex + vNum], cM[vIndex + 2*vNum]); | ||
glVertex3d(vM[vIndex], vM[vIndex + vNum], vM[vIndex + 2*vNum]); | ||
|
||
vIndex = (int)fp[fNum] - one_offset; | ||
if (coloring) glColor3ub(cM[vIndex], cM[vIndex + vNum], cM[vIndex + 2*vNum]); | ||
glVertex3d(vM[vIndex], vM[vIndex + vNum], vM[vIndex + 2*vNum]); | ||
|
||
vIndex = (int)fp[fNum2] - one_offset; | ||
if (coloring) glColor3ub(cM[vIndex], cM[vIndex + vNum], cM[vIndex + 2*vNum]); | ||
glVertex3d(vM[vIndex], vM[vIndex + vNum], vM[vIndex + 2*vNum]); | ||
} | ||
glEnd(); | ||
if (linewidth>0.1) | ||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); | ||
glEndList(); | ||
|
||
return theShape; | ||
} | ||
|
||
void cameraSetup(double zNear, double zFar, double *intrinsics, unsigned int imgHeight, unsigned int imgWidth) { | ||
|
||
double viewMat[] = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}; | ||
double fcv[] = {intrinsics[0], intrinsics[1]}; | ||
double ccv[] = {intrinsics[2], intrinsics[3]}; | ||
|
||
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); | ||
glEnable(GL_DEPTH_TEST); | ||
glDisable(GL_TEXTURE_2D); | ||
|
||
glMatrixMode(GL_MODELVIEW); | ||
glLoadMatrixd(viewMat); | ||
|
||
double left = - ccv[0] / fcv[0] * zNear; | ||
double bottom = (ccv[1] - (double)(imgHeight-1)) / fcv[1] * zNear; | ||
double right = ((double)imgWidth - 1.0 - ccv[0]) / fcv[0] * zNear; | ||
double top = ccv[1] / fcv[1] * zNear; | ||
|
||
glMatrixMode(GL_PROJECTION); | ||
glLoadIdentity(); | ||
glFrustum(left, right, bottom, top, zNear, zFar); | ||
glViewport(0, 0, imgWidth, imgHeight); | ||
} | ||
|
||
void drawPatchToDepthBuffer(GLuint listName, unsigned char *imageBuffer, float *depthBuffer, bool *maskBuffer, | ||
unsigned int imgHeight, unsigned int imgWidth, double *zNearFarV, bool coloring = true) { | ||
|
||
glCallList(listName); | ||
glFlush(); | ||
|
||
// bug fix for Nvidia | ||
unsigned int paddedWidth = imgWidth % 4; | ||
if (paddedWidth != 0) paddedWidth = 4 - paddedWidth + imgWidth; | ||
else paddedWidth = imgWidth; | ||
|
||
// Read off of the depth buffer | ||
float *dataBuffer_depth = (float *)malloc(paddedWidth * imgHeight * sizeof(GL_FLOAT)); | ||
glReadPixels(0, 0, paddedWidth, imgHeight, GL_DEPTH_COMPONENT, GL_FLOAT, dataBuffer_depth); | ||
|
||
// Read off of the color buffer | ||
GLubyte *dataBuffer_rgb = (GLubyte *)malloc(3* paddedWidth * imgHeight * sizeof(GLubyte)); | ||
if (coloring) | ||
glReadPixels(0, 0, paddedWidth, imgHeight, GL_RGB, GL_UNSIGNED_BYTE, dataBuffer_rgb); | ||
|
||
// reorder the pixel data for the opengl to matlab conversion | ||
unsigned int matlabImgIndex = 0; | ||
unsigned int oglImageIndex = 0; | ||
|
||
float n = zNearFarV[0]; | ||
float f = zNearFarV[1]; | ||
for (int j = 0; j < imgWidth; j++) { | ||
for (int i = 0; i < imgHeight; i++, matlabImgIndex++) { | ||
oglImageIndex = (j + (imgHeight-1-i) * paddedWidth); | ||
float depth = dataBuffer_depth[oglImageIndex]; | ||
|
||
// render mask: indicating points inside the clipped plane | ||
maskBuffer[matlabImgIndex] = depth<1; | ||
|
||
// render depth | ||
depthBuffer[matlabImgIndex] = -f*n/(depth*(f-n)-f); | ||
|
||
// render color | ||
if (coloring) { | ||
imageBuffer[matlabImgIndex] = (unsigned char) dataBuffer_rgb[oglImageIndex*3]; | ||
imageBuffer[matlabImgIndex+imgWidth*imgHeight] = (unsigned char) dataBuffer_rgb[oglImageIndex*3+1]; | ||
imageBuffer[matlabImgIndex+imgWidth*imgHeight*2] = (unsigned char) dataBuffer_rgb[oglImageIndex*3+2]; | ||
} | ||
} | ||
} | ||
|
||
free(dataBuffer_depth); | ||
free(dataBuffer_rgb); | ||
} | ||
|
||
void renderDepthMesh(double *FM, int fNum, double *VM, int vNum, double *CM, double *intrinsics, int *imgSizeV, double *zNearFarV, unsigned char * imgBuffer, float *depthBuffer, bool *maskBuffer, double linewidth, bool coloring, bool one_offset) { | ||
OffscreenGL offscreenGL(imgSizeV[0], imgSizeV[1]); | ||
cameraSetup(zNearFarV[0], zNearFarV[1], intrinsics, imgSizeV[0], imgSizeV[1]); | ||
GLuint list = createDisplayList(FM, fNum, VM, vNum, CM, 1, linewidth, coloring, one_offset); | ||
drawPatchToDepthBuffer(list, imgBuffer, depthBuffer, maskBuffer, imgSizeV[0], imgSizeV[1], zNearFarV, coloring); | ||
if (list) { | ||
glDeleteLists(list, 1); | ||
list = 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#ifndef LIBRENDER_OFFSCREEN_H | ||
#define LIBRENDER_OFFSCREEN_H | ||
|
||
#include <GL/glew.h> | ||
#if defined(__APPLE__) | ||
#include <OpenGL/gl.h> | ||
#include <OpenGL/glu.h> | ||
#else | ||
#include <GL/gl.h> | ||
#include <GL/glu.h> | ||
#endif | ||
#include <GL/glut.h> | ||
|
||
class OffscreenGL { | ||
|
||
public: | ||
OffscreenGL(int maxHeight, int maxWidth); | ||
~OffscreenGL(); | ||
|
||
private: | ||
static int glutWin; | ||
static bool glutInitialized; | ||
GLuint fb; | ||
GLuint renderTex; | ||
GLuint depthTex; | ||
}; | ||
|
||
|
||
void renderDepthMesh(double *FM, int fNum, double *VM, int vNum, double *CM, double *intrinsics, int *imgSizeV, double *zNearFarV, unsigned char * imgBuffer, float *depthBuffer, bool *maskBuffer, double linewidth, bool coloring, bool one_offset); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
cimport cython | ||
import numpy as np | ||
cimport numpy as np | ||
|
||
from libc.stdlib cimport free, malloc | ||
from libcpp cimport bool | ||
from cpython cimport PyObject, Py_INCREF | ||
|
||
CREATE_INIT = True # workaround, so cython builds a init function | ||
|
||
np.import_array() | ||
|
||
|
||
cdef extern from "offscreen.h": | ||
void renderDepthMesh(double *FM, int fNum, double *VM, int vNum, double *CM, double *intrinsics, int *imgSizeV, double *zNearFarV, unsigned char * imgBuffer, float *depthBuffer, bool *maskBuffer, double linewidth, bool coloring, bool one_offset); | ||
|
||
|
||
def render(double[:,::1] vertices, double[:,::1] faces, double[::1] cam_intr, int[::1] img_size, double linewidth=0, double[:,::1] colors=None): | ||
if vertices.shape[0] != 3: | ||
raise Exception('vertices must be a 3xM double array') | ||
if faces.shape[0] != 3: | ||
raise Exception('faces must be a 3xM double array') | ||
if cam_intr.shape[0] != 4: | ||
raise Exception('cam_intr must be a 4x1 double vector') | ||
if img_size.shape[0] != 2: | ||
raise Exception('img_size must be a 2x1 int vector') | ||
|
||
cdef double* VM = &(vertices[0,0]) | ||
cdef int vNum = vertices.shape[1] | ||
cdef double* FM = &(faces[0,0]) | ||
cdef int fNum = faces.shape[1] | ||
cdef double* intrinsics = &(cam_intr[0]) | ||
cdef int* imgSize = &(img_size[0]) | ||
|
||
cdef bool coloring = True | ||
cdef double* CM = NULL | ||
if colors is not None: | ||
CM = &(colors[0,0]) | ||
else: | ||
coloring = False | ||
|
||
cdef double znf[2] | ||
znf[0] = 1e10 | ||
znf[1] = -1e10 | ||
cdef double z | ||
for i in range(vNum): | ||
z = VM[2*vNum+i] | ||
if (z<znf[0]): | ||
znf[0] = z | ||
if (z>znf[1]): | ||
znf[1] = z | ||
|
||
znf[0] -= 0.1; | ||
znf[1] += 0.1; | ||
znf[0] = max(znf[0],0.1); | ||
znf[1] = max(znf[1],znf[0]+0.1); | ||
|
||
depth = np.empty((img_size[1], img_size[0]), dtype=np.float32) | ||
mask = np.empty((img_size[1], img_size[0]), dtype=np.uint8) | ||
img = np.empty((3, img_size[1], img_size[0]), dtype=np.uint8) | ||
cdef float[:,::1] depth_view = depth | ||
cdef unsigned char[:,::1] mask_view = mask | ||
cdef unsigned char[:,:,::1] img_view = img | ||
cdef float* depthBuffer = &(depth_view[0,0]) | ||
cdef bool* maskBuffer = <bool*> &(mask_view[0,0]) | ||
cdef unsigned char* imgBuffer = &(img_view[0,0,0]) | ||
|
||
renderDepthMesh(FM, fNum, VM, vNum, CM, intrinsics, imgSize, znf, imgBuffer, depthBuffer, maskBuffer, linewidth, coloring, False); | ||
|
||
return depth.T, mask.T, img.transpose((2,1,0)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from distutils.core import setup | ||
from Cython.Build import cythonize | ||
from distutils.extension import Extension | ||
from Cython.Distutils import build_ext | ||
import numpy as np | ||
import platform | ||
|
||
extra_compile_args = [] | ||
extra_link_args = ['-lGLEW', '-lglut'] | ||
|
||
if platform.system() == 'Darwin': | ||
extra_link_args.append('-framework OpenGL') | ||
extra_link_args.append('-framework GLU') | ||
else: | ||
extra_link_args.append('-lGL') | ||
extra_link_args.append('-lGLU') | ||
|
||
setup( | ||
name="pyrender", | ||
cmdclass= {'build_ext': build_ext}, | ||
ext_modules=[ | ||
Extension('pyrender', | ||
['pyrender.pyx', | ||
'offscreen.cpp', | ||
], | ||
language='c++', | ||
include_dirs=[np.get_include(),], | ||
extra_compile_args=extra_compile_args, | ||
extra_link_args=extra_link_args | ||
) | ||
] | ||
) | ||
|
||
|