00001
00002
00003
00004
00005
00006
00007
00008 #include "LadybugVirtualCamera.h"
00009
00010 #include <fstream>
00011 #include <GL/glu.h>
00012 #include <GL/glut.h>
00013 #include <opencv2/highgui/highgui.hpp>
00014
00015 #include "CameraException.h"
00016
00017 namespace nifti {
00018 namespace ladybug {
00019
00020 LadybugVirtualCamera::LadybugVirtualCamera() :
00021 viewportWidth(640), viewportHeight(480), pan(0.0), tilt(0.0), horizontalFov(60.0), verticalFov(45.0), meshCols(0),
00022 meshRows(0), alphamaskAvailable(false), initialized(false), offScreenRendering(false), frameBuffer(0),
00023 colorRenderBuffer(0), depthRenderBuffer(0) {
00024
00025
00026 for (int i = 0; i < NUM_CAMERAS; i++) {
00027 mesh[i] = NULL;
00028
00029 alphaMaskWidths[i] = 0;
00030 alphaMaskHeights[i] = 0;
00031 alphamasks[i] = NULL;
00032
00033 imageWidths[i] = 0;
00034 imageHeights[i] = 0;
00035
00036 glTextureWidths[i] = 0;
00037 glTextureHeights[i] = 0;
00038 glTextures[i] = (GLuint) 0;
00039 }
00040 }
00041
00042 LadybugVirtualCamera::~LadybugVirtualCamera() {
00043 clearMesh();
00044 clearAlphamask();
00045 }
00046
00047 void LadybugVirtualCamera::initializeTextures() {
00048 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00049 glEnable(GL_TEXTURE_2D);
00050 glShadeModel(GL_FLAT);
00051
00052 glGenTextures(6, glTextures);
00053 }
00054
00055 void LadybugVirtualCamera::initializeFramebuffers() {
00056 glGenFramebuffers(1, &frameBuffer);
00057 glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
00058
00059
00060 glGenRenderbuffers(1, &colorRenderBuffer);
00061
00062 glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
00063
00064 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, viewportWidth, viewportHeight);
00065
00066 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderBuffer);
00067
00068 glGenRenderbuffers(1, &depthRenderBuffer);
00069 glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
00070
00071 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, viewportWidth, viewportHeight);
00072
00073 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
00074
00075
00076 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
00077 switch (status) {
00078 case GL_FRAMEBUFFER_COMPLETE:
00079 break;
00080 default:
00081 deleteBuffers();
00082 throw std::runtime_error("Could not setup frame buffer.\n");
00083 }
00084 }
00085
00086 void LadybugVirtualCamera::initialize(bool offScreenRendering) {
00087 this->offScreenRendering = offScreenRendering;
00088
00089 if (this->offScreenRendering) {
00090 int glutWin = glutCreateWindow("temp");
00091 GLenum glew = glewInit();
00092 if (GLEW_OK != glew) {
00093 glutDestroyWindow(glutWin);
00094 throw std::runtime_error((char*) glewGetErrorString(glew));
00095 }
00096
00097 initializeFramebuffers();
00098 }
00099
00100 initializeTextures();
00101 this->initialized = true;
00102 }
00103
00104 void LadybugVirtualCamera::updateBuffers() {
00105 glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
00106 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, viewportWidth, viewportHeight);
00107
00108 glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
00109 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, viewportWidth, viewportHeight);
00110 }
00111
00112 void LadybugVirtualCamera::updateViewport() {
00113
00114 glViewport(0, 0, viewportWidth, viewportHeight);
00115 }
00116
00117 void LadybugVirtualCamera::updateProjection() {
00118
00119 glMatrixMode(GL_PROJECTION);
00120 glLoadIdentity();
00121 gluPerspective((GLdouble) verticalFov, (GLdouble) horizontalFov / (GLdouble) verticalFov, 0.1, 100.0);
00122 }
00123
00124 void LadybugVirtualCamera::updateModelView() {
00125
00126 glMatrixMode(GL_MODELVIEW);
00127 glLoadIdentity();
00128 glRotated(-tilt, 1.0, 0.0, 0.0);
00129 glRotated(-pan, 0.0, 1.0, 0.0);
00130
00131 glRotated(-90.0, 1.0, 0.0, 0.0);
00132 }
00133
00134 void LadybugVirtualCamera::clearBuffers() {
00135
00136
00137 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00138 glClearDepth(1.0);
00139 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00140 }
00141
00142 void LadybugVirtualCamera::render() {
00143 glMatrixMode(GL_TEXTURE);
00144 glLoadIdentity();
00145
00146
00147
00148
00149 for (int iCamera = 0; iCamera < NUM_CAMERAS; iCamera++)
00150 {
00151
00152 double validTextureWidth = (double) imageWidths[iCamera] / glTextureWidths[iCamera];
00153 double validTextureHeight = (double) imageHeights[iCamera] / glTextureHeights[iCamera];
00154
00155 glBindTexture(GL_TEXTURE_2D, glTextures[iCamera]);
00156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00157 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00158
00159 for (int iRow = 0; iRow < meshRows - 1; iRow++)
00160 {
00161 glBegin(GL_TRIANGLE_STRIP);
00162 for (int iCol = 0; iCol < meshCols; iCol++)
00163 {
00164
00165 double p1 = (double) iCol / (meshCols - 1) * validTextureWidth;
00166 double q1 = (double) iRow / (meshRows - 1) * validTextureHeight;
00167 double q2 = (double) (iRow + 1.0) / (meshRows - 1) * validTextureHeight;
00168
00169
00170 int ptr1 = iRow * meshCols + iCol;
00171 double x1 = mesh[iCamera][ptr1 * 3 + 0];
00172 double y1 = mesh[iCamera][ptr1 * 3 + 1];
00173 double z1 = mesh[iCamera][ptr1 * 3 + 2];
00174
00175 int ptr2 = (iRow + 1) * meshCols + iCol;
00176 double x2 = mesh[iCamera][ptr2 * 3 + 0];
00177 double y2 = mesh[iCamera][ptr2 * 3 + 1];
00178 double z2 = mesh[iCamera][ptr2 * 3 + 2];
00179
00180 glTexCoord2d(p1, q1);
00181 glVertex3d(x1, y1, z1);
00182
00183 glTexCoord2d(p1, q2);
00184 glVertex3d(x2, y2, z2);
00185 }
00186 glEnd();
00187 }
00188 }
00189 }
00190
00191 void LadybugVirtualCamera::renderView(cv::Mat& image) {
00192
00193 clearBuffers();
00194 updateViewport();
00195 updateProjection();
00196 updateModelView();
00197 render();
00198
00199
00200 cv::Mat flippedImage(viewportHeight, viewportWidth, CV_8UC4);
00201 glReadPixels(0, 0, viewportWidth, viewportHeight, GL_BGRA, GL_UNSIGNED_BYTE, flippedImage.data);
00202
00203
00204 cv::flip(flippedImage, image, 0);
00205 }
00206
00207 void LadybugVirtualCamera::deleteBuffers() {
00208 if (!this->offScreenRendering) {
00209
00210 return;
00211 }
00212
00213 if (colorRenderBuffer > 0) {
00214 glDeleteRenderbuffers(1, &colorRenderBuffer);
00215 }
00216 if (depthRenderBuffer > 0) {
00217 glDeleteRenderbuffers(1, &depthRenderBuffer);
00218 }
00219
00220
00221 glBindFramebuffer(GL_FRAMEBUFFER, 0);
00222 if (frameBuffer > 0) {
00223 glDeleteFramebuffers(1, &frameBuffer);
00224 }
00225 }
00226
00227 void LadybugVirtualCamera::getViewport(int* viewportWidth, int* viewportHeight) {
00228 *viewportWidth = this->viewportWidth;
00229 *viewportHeight = this->viewportHeight;
00230 }
00231 void LadybugVirtualCamera::setViewport(int viewportWidth, int viewportHeight) {
00232
00233 if (this->viewportWidth != viewportWidth || this->viewportHeight != viewportHeight) {
00234
00235 this->viewportWidth = viewportWidth;
00236 this->viewportHeight = viewportHeight;
00237
00238 if (this->offScreenRendering) {
00239 updateBuffers();
00240 }
00241 }
00242 }
00243
00244 double LadybugVirtualCamera::getPan() {
00245 return this->pan;
00246 }
00247 void LadybugVirtualCamera::setPan(double pan) {
00248 this->pan = pan;
00249 }
00250 double LadybugVirtualCamera::getTilt() {
00251 return this->tilt;
00252 }
00253 void LadybugVirtualCamera::setTilt(double tilt) {
00254 this->tilt = tilt;
00255 }
00256 double LadybugVirtualCamera::getHorizontalFov() {
00257 return this->horizontalFov;
00258 }
00259 void LadybugVirtualCamera::setHorizontalFov(double horizontalFov) {
00260 this->horizontalFov = horizontalFov;
00261 }
00262 double LadybugVirtualCamera::getVerticalFov() {
00263 return this->verticalFov;
00264 }
00265 void LadybugVirtualCamera::setVerticalFov(double verticalFov) {
00266 this->verticalFov = verticalFov;
00267 }
00268
00269 void LadybugVirtualCamera::loadMesh(const std::string& meshFile) {
00270 printf("Loading mesh from %s...\n", meshFile.data());
00271
00272 clearMesh();
00273
00274 FILE *fp = fopen(meshFile.data(), "r");
00275 if (fp == NULL) {
00276 throw std::runtime_error("Opening mesh file failed: " + meshFile);
00277 }
00278
00279 if (fscanf(fp, "cols %d rows %d\n", &meshCols, &meshRows) != 2) {
00280 fclose(fp);
00281 throw std::runtime_error("Reading mesh file header failed.");
00282 }
00283 printf("Header: rows: %d, columns: %d\n", meshRows, meshCols);
00284
00285 for (int iImage = 0; iImage < NUM_CAMERAS; iImage++) {
00286 mesh[iImage] = new double[meshCols * meshRows * 3];
00287
00288 for (int iRow = 0; iRow < meshRows; iRow++) {
00289 for (int iCol = 0; iCol < meshCols; iCol++) {
00290 double x, y, z;
00291 int scanned;
00292 if ((scanned = fscanf(fp, "%lf, %lf, %lf", &x, &y, &z)) != 3) {
00293 fclose(fp);
00294 printf("Image %d, row %d, column %d. Values scanned: %d\n", iImage, iRow, iCol, scanned);
00295 printf("%lf\n", x);
00296 throw std::runtime_error("Reading mesh file failed.");
00297 }
00298 mesh[iImage][(iRow * meshCols + iCol) * 3 + 0] = x;
00299 mesh[iImage][(iRow * meshCols + iCol) * 3 + 1] = y;
00300 mesh[iImage][(iRow * meshCols + iCol) * 3 + 2] = z;
00301 }
00302 }
00303 }
00304
00305 fclose(fp);
00306 }
00307
00308 void LadybugVirtualCamera::clearMesh() {
00309 printf("Clearing mesh...\n");
00310 for (int i = 0; i < NUM_CAMERAS; i++) {
00311 delete[] mesh[i];
00312 mesh[i] = NULL;
00313 }
00314 }
00315
00316 void LadybugVirtualCamera::loadAlphamask(const std::string& alphamaskFilePrefix) {
00317 clearAlphamask();
00318 printf("Loading alphamask using prefix %s...\n", alphamaskFilePrefix.data());
00319 alphamaskAvailable = true;
00320 for (int iCamera = 0; iCamera < NUM_CAMERAS; iCamera++) {
00321 char pgmPath[1024];
00322 sprintf(pgmPath, "%s%d.pgm", alphamaskFilePrefix.data(), iCamera);
00323
00324
00325 cv::Mat alphamaskMat = cv::imread(pgmPath, 0);
00326
00327
00328 if (alphamaskMat.elemSize() > 1) {
00329 alphamaskAvailable = false;
00330 throw std::runtime_error("Invalid alphamask type.");
00331 }
00332 alphaMaskWidths[iCamera] = alphamaskMat.cols;
00333 alphaMaskHeights[iCamera] = alphamaskMat.rows;
00334 int alphamaskSize = alphamaskMat.cols * alphamaskMat.rows * alphamaskMat.elemSize();
00335 alphamasks[iCamera] = new unsigned char[alphamaskSize];
00336 memcpy(alphamasks[iCamera], alphamaskMat.data, alphamaskSize);
00337
00338
00339
00340
00341 }
00342 }
00343
00344 void LadybugVirtualCamera::clearAlphamask() {
00345 printf("Clearing alphamask...\n");
00346 for (int iCamera = 0; iCamera < NUM_CAMERAS; iCamera++) {
00347
00348 delete[] alphamasks[iCamera];
00349 alphamasks[iCamera] = NULL;
00350 }
00351 alphamaskAvailable = false;
00352 glDisable(GL_BLEND);
00353 }
00354
00355 void LadybugVirtualCamera::setImage(const int& imageIndex, const cv::Mat& image) {
00356
00357 imageWidths[imageIndex] = image.cols;
00358 imageHeights[imageIndex] = image.rows;
00359
00360
00361 int channels = image.channels();
00362 if (channels != 3) {
00363 throw std::runtime_error("Image must have 3 channels.");
00364 }
00365
00366 unsigned char* bgraBuffer = new unsigned char[imageWidths[imageIndex] * imageHeights[imageIndex] * 4];
00367
00368 for (int iData = 0; iData < imageWidths[imageIndex] * imageHeights[imageIndex] * channels; iData++) {
00369
00370 bgraBuffer[iData + (iData / channels)] = image.data[iData];
00371 }
00372
00373 if (alphamaskAvailable) {
00374 for (int y = 0; y < imageHeights[imageIndex]; y++) {
00375 for (int x = 0; x < imageWidths[imageIndex]; x++) {
00376 int alphamaskX = x * alphaMaskWidths[imageIndex] / imageWidths[imageIndex];
00377 int alphamaskY = y * alphaMaskHeights[imageIndex] / imageHeights[imageIndex];
00378 bgraBuffer[(y * imageWidths[imageIndex] + x) * 4 + 3] = alphamasks[imageIndex][alphamaskY
00379 * alphaMaskWidths[imageIndex] + alphamaskX];
00380 }
00381 }
00382 }
00383
00384 glBindTexture(GL_TEXTURE_2D, glTextures[imageIndex]);
00385
00386 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00387 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00388 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00389 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00390
00391
00392
00393
00394 glTextureWidths[imageIndex] = getMinimumPowerOfTwo(imageWidths[imageIndex]);
00395 glTextureHeights[imageIndex] = getMinimumPowerOfTwo(imageHeights[imageIndex]);
00396
00397
00398 int textureElems = glTextureWidths[imageIndex] * glTextureHeights[imageIndex] * 4;
00399 unsigned char* textureBuffer = new unsigned char[textureElems];
00400
00401
00402 for (int y = 0; y < imageHeights[imageIndex]; y++) {
00403 for (int x = 0; x < imageWidths[imageIndex]; x++) {
00404 textureBuffer[(y * glTextureWidths[imageIndex] + x) * 4 + 0] = bgraBuffer[(y * imageWidths[imageIndex] + x) * 4
00405 + 0];
00406 textureBuffer[(y * glTextureWidths[imageIndex] + x) * 4 + 1] = bgraBuffer[(y * imageWidths[imageIndex] + x) * 4
00407 + 1];
00408 textureBuffer[(y * glTextureWidths[imageIndex] + x) * 4 + 2] = bgraBuffer[(y * imageWidths[imageIndex] + x) * 4
00409 + 2];
00410 textureBuffer[(y * glTextureWidths[imageIndex] + x) * 4 + 3] = bgraBuffer[(y * imageWidths[imageIndex] + x) * 4
00411 + 3];
00412 }
00413 }
00414
00415
00416
00417 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, glTextureWidths[imageIndex], glTextureHeights[imageIndex], 0, GL_BGRA_EXT,
00418 GL_UNSIGNED_BYTE, textureBuffer);
00419
00420
00421
00422
00423
00424
00425
00426
00427 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00428 glEnable(GL_TEXTURE_2D);
00429 glShadeModel(GL_FLAT);
00430 glEnable(GL_BLEND);
00431 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00432
00433
00434 delete[] bgraBuffer;
00435 delete[] textureBuffer;
00436 }
00437
00438 void LadybugVirtualCamera::setImages(const cv::Mat(&images)[NUM_CAMERAS]) {
00439 for (int iImage = 0; iImage < NUM_CAMERAS; iImage++) {
00440 setImage(iImage, images[iImage]);
00441 }
00442 }
00443
00444 void LadybugVirtualCamera::setImages(const cv::Mat& compositeImage) {
00445 int imageHeight = compositeImage.rows / NUM_CAMERAS;
00446 cv::Mat images[NUM_CAMERAS];
00447 for (int iImage = 0; iImage < NUM_CAMERAS; iImage++) {
00448 images[iImage] = compositeImage.rowRange(iImage * imageHeight, (iImage + 1) * imageHeight);
00449 }
00450 setImages(images);
00451 }
00452
00453 int LadybugVirtualCamera::getMinimumPowerOfTwo(int n) {
00454 int i = 1;
00455 while (i < n) {
00456 i *= 2;
00457 }
00458 return i;
00459 }
00460
00461 }
00462 }