Last active
July 29, 2016 07:56
-
-
Save porst17/15318057662359c9a383b44d1235c439 to your computer and use it in GitHub Desktop.
Combine 4 orthographic renderings of a sphere into a equirectangular map of the sphere
This file contains hidden or 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
/* | |
* Copyright 2016 Christian Stussak | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
/*********************************************************************** | |
* Combine 4 orthographic renderings of a sphere into a equirectangular | |
* map of the sphere. | |
* | |
* Compile with | |
* $ g++ op2erp.cpp -l freeimage -o op2erp | |
***********************************************************************/ | |
#include <FreeImage.h> | |
#include <iostream> | |
#include <cstdlib> | |
#include <cmath> | |
#include <functional> | |
#define WIDTH 1024 | |
#define HEIGHT 512 | |
#define NUM_SAMPLES_SQRT 3 | |
#define NUM_SAMPLES ( NUM_SAMPLES_SQRT * NUM_SAMPLES_SQRT ) | |
#define THRESHOLD 0.25 | |
#define EPSILON 0.000001 // to avoid sampling problems along the boundaries | |
FIBITMAP *front, *left, *back, *right, *top, *bottom; | |
FIBITMAP* FreeImage_Load32Bits( char *filename ) | |
{ | |
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(filename,0); | |
FIBITMAP* image = FreeImage_Load(format, filename); | |
if( !image ) | |
std::cout << "unable to load " << filename << std::endl; | |
FIBITMAP* result = FreeImage_ConvertTo32Bits(image); | |
if( !image ) | |
std::cout << "unable to convert " << filename << " to 32bit RGBA" << std::endl; | |
FreeImage_Unload(image); | |
return result; | |
} | |
template<typename T> | |
T clamp(const T &val, const T &min, const T &max) | |
{ | |
return std::max(min, std::min(max, val)); | |
} | |
RGBQUAD sampler( double phi, double theta ) | |
{ | |
RGBQUAD result; | |
if( theta > ( 1.0 - THRESHOLD ) * M_PI ) | |
{ | |
// sample bottom image | |
int w = FreeImage_GetWidth(bottom); | |
int h = FreeImage_GetHeight(bottom); | |
phi += 0; | |
int px = clamp( (int) ( ( ( ( std::sin( theta ) * std::sin( phi ) ) * w / 2.0 ) + w / 2 ) ), 0, w ); | |
int py = clamp( (int) ( ( ( std::sin( theta ) * std::cos( phi ) ) * h / 2.0 ) + h / 2.0 ), 0, h ); | |
FreeImage_GetPixelColor( bottom, px, py, &result ); | |
} | |
else if ( theta < THRESHOLD * M_PI ) | |
{ | |
// sample top image | |
int w = FreeImage_GetWidth(top); | |
int h = FreeImage_GetHeight(top); | |
phi = M_PI - phi; | |
int px = clamp( (int) ( ( ( ( std::sin( theta ) * std::sin( phi ) ) * w / 2.0 ) + w / 2 ) ), 0, w ); | |
int py = clamp( (int) ( ( ( std::sin( theta ) * std::cos( phi ) ) * h / 2.0 ) + h / 2.0 ), 0, h ); | |
FreeImage_GetPixelColor( top, px, py, &result ); | |
} | |
else | |
{ | |
FIBITMAP *image; | |
if( phi < 0.125 * 2.0 * M_PI || phi >= 0.875 * 2.0 * M_PI ) | |
{ | |
// sample front image | |
image = front; | |
phi += 1.5 * M_PI; | |
} | |
else if( phi < 0.375 * 2.0 * M_PI ) | |
{ | |
// sample right image | |
image = right; | |
phi += 1.0 * M_PI; | |
} | |
else if( phi < 0.625 * 2.0 * M_PI ) | |
{ | |
// sample back image | |
image = back; | |
phi += 0.5 * M_PI; | |
} | |
else | |
{ | |
// sample left image | |
image = left; | |
} | |
theta += M_PI; | |
int w = FreeImage_GetWidth(image); | |
int h = FreeImage_GetHeight(image); | |
int px = ( w - 1 ) - clamp( (int) ( ( ( ( std::sin( theta ) * std::cos( phi ) ) * w / 2.0 ) + w / 2 ) ), 0, w ); | |
int py = ( h - 1 ) - clamp( (int) ( ( std::cos( theta ) * h / 2.0 ) + h / 2.0 ), 0, h ); | |
FreeImage_GetPixelColor( image, px, py, &result ); | |
} | |
return result; | |
} | |
RGBQUAD sample( double phi_min, double phi_max, double theta_min, double theta_max ) | |
{ | |
int R = 0, G = 0, B = 0; | |
RGBQUAD temp; | |
for( int i = 0; i < NUM_SAMPLES_SQRT; ++i ) | |
{ | |
for( int j = 0; j < NUM_SAMPLES_SQRT; ++j ) | |
{ | |
double phi = phi_min + ( phi_max - phi_min ) * ( i / NUM_SAMPLES_SQRT ); | |
double theta = theta_min + ( theta_max - theta_min ) * ( j / NUM_SAMPLES_SQRT ); | |
temp = sampler( phi, theta ); | |
R += temp.rgbRed; | |
G += temp.rgbGreen; | |
B += temp.rgbBlue; | |
} | |
} | |
temp.rgbRed = R / NUM_SAMPLES; | |
temp.rgbGreen = G / NUM_SAMPLES; | |
temp.rgbBlue = B / NUM_SAMPLES; | |
return temp; | |
} | |
int main( int argc, char* argv[] ) | |
{ | |
if(argc != 8) | |
{ | |
std::cout << "Usage: op2erp front.png left.png back.png right.png top.png bottom.png merged_result.png" << std::endl; | |
std::exit(-1); | |
} | |
FreeImage_Initialise(false); | |
front = FreeImage_Load32Bits( argv[ 1 ] ); | |
left = FreeImage_Load32Bits( argv[ 2 ] ); | |
back = FreeImage_Load32Bits( argv[ 3 ] ); | |
right = FreeImage_Load32Bits( argv[ 4 ] ); | |
top = FreeImage_Load32Bits( argv[ 5 ] ); | |
bottom = FreeImage_Load32Bits( argv[ 6 ] ); | |
FIBITMAP *output = FreeImage_Allocate( WIDTH, HEIGHT, 32); | |
for( int x = 0; x < WIDTH; ++x ) | |
{ | |
for( int y = 0; y < HEIGHT; ++y ) | |
{ | |
double theta_min = clamp( M_PI * ( 1.0 - y / ( double ) HEIGHT ), EPSILON, M_PI - EPSILON ); | |
double theta_max = clamp( M_PI * ( 1.0 - ( y + 1 ) / ( double ) HEIGHT ), EPSILON, M_PI - EPSILON ); | |
double phi_min = 2.0 * M_PI * ( x / ( double ) WIDTH ); | |
double phi_max = 2.0 * M_PI * ( ( x + 1 ) / ( double ) WIDTH ); | |
RGBQUAD color = sample( phi_min, phi_max, theta_min, theta_max ); | |
FreeImage_SetPixelColor( output, x, y, &color ); | |
} | |
} | |
std::cout << "done filling pixel data" << std::endl; | |
if (FreeImage_Save(FIF_PNG, output, argv[ 7 ], 0)) | |
{ | |
std::cout << "bitmap successfully saved!" << std::endl; | |
} | |
FreeImage_DeInitialise(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment