From: <ac...@us...> - 2008-10-21 05:23:57
|
Revision: 3511 http://hugin.svn.sourceforge.net/hugin/?rev=3511&view=rev Author: acmihal Date: 2008-10-21 05:23:46 +0000 (Tue, 21 Oct 2008) Log Message: ----------- Support for image remapping using the gpu. Work in progress. Modified Paths: -------------- hugin/branches/nona-gpu/CMakeLists.txt hugin/branches/nona-gpu/src/hugin_base/CMakeLists.txt hugin/branches/nona-gpu/src/hugin_base/nona/RemappedPanoImage.h hugin/branches/nona-gpu/src/hugin_base/panodata/PanoramaOptions.h hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsInterface.h hugin/branches/nona-gpu/src/hugin_base/vigra_ext/CMakeLists.txt hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransforms.h hugin/branches/nona-gpu/src/hugin_base/vigra_ext/Interpolators.h hugin/branches/nona-gpu/src/tools/CMakeLists.txt hugin/branches/nona-gpu/src/tools/nona.cpp Added Paths: ----------- hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsTransformGPU.cpp hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.cpp hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.h Modified: hugin/branches/nona-gpu/CMakeLists.txt =================================================================== --- hugin/branches/nona-gpu/CMakeLists.txt 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/CMakeLists.txt 2008-10-21 05:23:46 UTC (rev 3511) @@ -133,12 +133,14 @@ ## OpenGL and GLEW FIND_PACKAGE(OpenGL) +FIND_PACKAGE(GLUT) FIND_PACKAGE(GLEW) IF(NOT OPENGL_FOUND) MESSAGE("OpenGL was not found, hugin disabled") ENDIF(NOT OPENGL_FOUND) IF(GLEW_FOUND) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) + INCLUDE_DIRECTORIES(${GLUT_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${GLEW_INCLUDE_DIR}) ENDIF(GLEW_FOUND) Modified: hugin/branches/nona-gpu/src/hugin_base/CMakeLists.txt =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/CMakeLists.txt 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/src/hugin_base/CMakeLists.txt 2008-10-21 05:23:46 UTC (rev 3511) @@ -51,8 +51,10 @@ panodata/SrcPanoImage.cpp panotools/PanoToolsInterface.cpp panotools/PanoToolsOptimizerWrapper.cpp +panotools/PanoToolsTransformGPU.cpp vigra_ext/emor.cpp vigra_ext/MultiThreadOperations.cpp +vigra_ext/ImageTransformsGPU.cpp ) IF (${HUGIN_SHARED_LIBS}) Modified: hugin/branches/nona-gpu/src/hugin_base/nona/RemappedPanoImage.h =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/nona/RemappedPanoImage.h 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/src/hugin_base/nona/RemappedPanoImage.h 2008-10-21 05:23:46 UTC (rev 3511) @@ -195,6 +195,7 @@ #include <photometric/ResponseTransform.h> #include <vigra_ext/ImageTransforms.h> +#include <vigra_ext/ImageTransformsGPU.h> #ifdef DEBUG #define DEBUG_REMAP 1 @@ -414,6 +415,8 @@ // msg <<"remapping image " << imgNr; // progress.setMessage(msg.str().c_str()); + const bool useGPU = m_destImg.remapUsingGPU; + if (Base::boundingBox().isEmpty()) return; @@ -478,26 +481,51 @@ } - transformImageAlpha(srcImg, - vigra::srcImage(alpha), - destImageRange(Base::m_image), - destImage(Base::m_mask), - Base::boundingBox().upperLeft(), - m_transf, - invResponse, - m_srcImg.horizontalWarpNeeded(), - interpol, - progress); + if (useGPU) { + transformImageAlphaGPU(srcImg, + vigra::srcImage(alpha), + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interpol, + progress); + } else { + transformImageAlpha(srcImg, + vigra::srcImage(alpha), + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interpol, + progress); + } } else { - transformImage(srcImg, - destImageRange(Base::m_image), - destImage(Base::m_mask), - Base::boundingBox().upperLeft(), - m_transf, - invResponse, - m_srcImg.horizontalWarpNeeded(), - interpol, - progress); + if (useGPU) { + transformImageGPU(srcImg, + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interpol, + progress); + } else { + transformImage(srcImg, + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interpol, + progress); + } } } @@ -512,6 +540,8 @@ vigra_ext::Interpolator interp, AppBase::MultiProgressDisplay & progress) { + const bool useGPU = m_destImg.remapUsingGPU; + if (Base::boundingBox().isEmpty()) return; @@ -573,28 +603,54 @@ default: break; } - vigra_ext::transformImageAlpha(srcImg, - vigra::srcImage(alpha), - destImageRange(Base::m_image), - destImage(Base::m_mask), - Base::boundingBox().upperLeft(), - m_transf, - invResponse, - m_srcImg.horizontalWarpNeeded(), - interp, - progress); + if (useGPU) { + vigra_ext::transformImageAlphaGPU(srcImg, + vigra::srcImage(alpha), + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interp, + progress); + } else { + vigra_ext::transformImageAlpha(srcImg, + vigra::srcImage(alpha), + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interp, + progress); + } } else { - vigra_ext::transformImageAlpha(srcImg, - alphaImg, - destImageRange(Base::m_image), - destImage(Base::m_mask), - Base::boundingBox().upperLeft(), - m_transf, - invResponse, - m_srcImg.horizontalWarpNeeded(), - interp, - progress); + if (useGPU) { + vigra_ext::transformImageAlpha(srcImg, + alphaImg, + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interp, + progress); + } else { + vigra_ext::transformImageAlpha(srcImg, + alphaImg, + destImageRange(Base::m_image), + destImage(Base::m_mask), + Base::boundingBox().upperLeft(), + m_transf, + invResponse, + m_srcImg.horizontalWarpNeeded(), + interp, + progress); + } } } Modified: hugin/branches/nona-gpu/src/hugin_base/panodata/PanoramaOptions.h =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/panodata/PanoramaOptions.h 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/src/hugin_base/panodata/PanoramaOptions.h 2008-10-21 05:23:46 UTC (rev 3511) @@ -209,6 +209,7 @@ blendMode = ENBLEND_BLEND; hdrMergeMode = HDRMERGE_AVERAGE; remapper = NONA; + remapUsingGPU = false; saveCoordImgs = false; huberSigma = 2; photometricHuberSigma = 2/255.0; @@ -358,6 +359,7 @@ BlendingMechanism blendMode; HDRMergeType hdrMergeMode; Remapper remapper; + bool remapUsingGPU; bool saveCoordImgs; Modified: hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsInterface.h =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsInterface.h 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsInterface.h 2008-10-21 05:23:46 UTC (rev 3511) @@ -26,6 +26,7 @@ #include <hugin_config.h> +#include <iostream> #include <string> #include <set> @@ -216,6 +217,8 @@ bool transformImgCoord(hugin_utils::FDiff2D& dest, const hugin_utils::FDiff2D & src) const { return transformImgCoord(dest.x, dest.y, src.x, src.y); } + + bool emitGLSL(std::ostringstream& oss) const; private: // update internal PT data structs. Added: hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsTransformGPU.cpp =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsTransformGPU.cpp (rev 0) +++ hugin/branches/nona-gpu/src/hugin_base/panotools/PanoToolsTransformGPU.cpp 2008-10-21 05:23:46 UTC (rev 3511) @@ -0,0 +1,305 @@ +// -*- c-basic-offset: 4 -*- + +/** @file PanoToolsTransformGPU.cpp + * + * @brief GPU shader program conversion for PTools::Transform + * + * @author Andrew Mihal + * + * $Id: $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <hugin_config.h> + +#include <stdlib.h> + +#include "PanoToolsInterface.h" + +#include <iostream> +#include <iomanip> + +using std::ostringstream; +using std::endl; + +#define distanceparam (*((double*)params)) +#define shift (*((double*)params)) +#define var0 ((double*)params)[0] +#define var1 ((double*)params)[1] +#define var2 ((double*)params)[2] +#define var3 ((double*)params)[3] +#define var4 ((double*)params)[4] +#define var5 ((double*)params)[5] + +/* +TODO + +erect_lambertazimuthal +erect_stereographic +erect_albersequalareaconic +*/ + +static void rotate_erect_glsl(ostringstream& oss, const void* params) { + oss << " // rotate_erect(" << var0 << ", " << var1 << ")" << endl + << " " << ((var1 == 0.0) ? "//" : "") << "src.s += " << var1 << ";" << endl + << " while (src.s < " << -var0 << ") src.s += " << (2.0 * var0) << ";" << endl + << " while (src.s > " << var0 << ") src.s -= " << (2.0 * var0) << ";" << endl + << endl; +} + +static void resize_glsl(ostringstream& oss, const void* params) { + oss << " // resize(" << var0 << ", " << var1 << ")" << endl + << " src *= vec2(" << var0 << ", " << var1 << ");" << endl + << endl; +} + +static void vert_glsl(ostringstream& oss, const void* params) { + oss << " // vert(" << shift << ")" << endl + << " src.t += " << shift << ";" << endl + << endl; +} + +static void horiz_glsl(ostringstream& oss, const void* params) { + oss << " // horiz(" << shift << ")" << endl + << " src.s += " << shift << ";" << endl + << endl; +} + +static void shear_glsl(ostringstream& oss, const void* params) { + oss << " // shear(" << var0 << ", " << var1 << ")" << endl + << " src += (src.ts * vec2(" << var0 << ", " << var1 << "));" << endl + << endl; +} + +static void erect_pano_glsl(ostringstream& oss, const void* params) { + oss << " // erect_pano(" << distanceparam << ")" << endl + << " src.t = " << distanceparam << " * atan(src.t / " << distanceparam << ");" << endl + << endl; +} + +static void erect_rect_glsl(ostringstream& oss, const void* params) { + oss << " // erect_rect(" << distanceparam << ")" << endl + << " src.t = " << distanceparam << " * atan(src.t, length(vec2(" << distanceparam << ", src.s)));" << endl + << " src.s = " << distanceparam << " * atan(src.s, " << distanceparam << ");" << endl + << endl; +} + +static void erect_sphere_tp_glsl(ostringstream& oss, const void* params) { + oss << " // erect_sphere_tp(" << distanceparam << ")" << endl + << " {" << endl + << " float r = length(src);" << endl + << " float theta = r / " << distanceparam << ";" << endl + << " float s = " << (1.0 / distanceparam) << ";" << endl + << " if (theta != 0.0) { s = sin(theta) / r; }" << endl + << " float v1 = s * src.s;" << endl + << " float v0 = cos(theta);" << endl + << " src.s = " << distanceparam << " * atan(v1, v0);" << endl + << " src.t = " << distanceparam << " * atan(s * src.t / length(vec2(v0, v1)));" << endl + << " }" << endl + << endl; +} + +static void sphere_tp_erect_glsl(ostringstream& oss, const void* params) { + oss << " // sphere_tp_erect(" << distanceparam << ")" << endl + << " {" << endl + << " float phi = src.s / " << distanceparam << ";" << endl + << " float theta = -src.t / " << distanceparam << " + " << (M_PI/2) << ";" << endl + << " if (theta < 0.0) {" << endl + << " theta = -theta;" << endl + << " phi += " << M_PI << ";" << endl + << " }" << endl + << " if (theta > " << M_PI << ") {" << endl + << " theta = " << M_PI << " - (theta - " << M_PI << ");" << endl + << " phi += " << M_PI << ";" << endl + << " }" << endl + << " float s = sin(theta);" << endl + << " vec2 v = vec2(s * sin(phi), cos(theta));" << endl + << " float r = length(v);" << endl + << " theta = " << distanceparam << " * atan(r, s * cos(phi));" << endl + << " src = v * (theta / r);" << endl + << " }" << endl + << endl; +} + +static void vertical_glsl(ostringstream& oss, const void* params) { + oss << " // vertical(" << var0 << ", " << var1 << ", " << var2 << ", " << var3 << ", " << var4 << ")" << endl + << " {" << endl + << " float r = abs(src.t / " << var4 << ");" << endl + << " float scale = ((" << var3 << " * r + " << var2 << ") * r + " << var1 << ") * r + " << var0 << ";" << endl + << " src.t *= scale;" << endl + << " }" << endl + << endl; +} + +static void deregister_glsl(ostringstream& oss, const void* params) { + oss << " // deregister(" << var1 << ", " << var2 << ", " << var3 << ", " << var4 << ")" << endl + << " {" << endl + << " float r = abs(src.t / " << var4 << ");" << endl + << " float scale = (" << var3 << " * r + " << var2 << ") * r + " << var1 << ";" << endl + << " src.s += abs(src.t) * scale;" << endl + << " }" << endl + << endl; +} + +static void radial_glsl(ostringstream& oss, const void* params) { + oss << " // radial(" << var0 << ", " << var1 << ", " << var2 << ", " << var3 << ", " << var4 << ", " << var5 << ")" << endl + << " {" << endl + << " float r = length(src) / " << var4 << ";" << endl + << " float scale = 1000.0; " << endl + << " if (r < " << var5 << ") {" << endl + << " scale = ((" << var3 << " * r + " << var2 << ") * r + " << var1 << ") * r + " << var0 << ";" << endl + << " }" << endl + << " src *= scale;" << endl + << " }" << endl + << endl; +} + +static void pano_sphere_tp_glsl(ostringstream& oss, const void* params) { + oss << " // pano_sphere_tp(" << distanceparam << ")" << endl + << " {" << endl + << " float r = length(src);" << endl + << " float theta = r / " << distanceparam << ";" << endl + << " float s = " << (1.0 / distanceparam) << ";" << endl + << " if (theta != 0.0) s = sin(theta) / r;" << endl + << " vec2 v = vec2(cos(theta), s * src.s);" << endl + << " src.s = " << distanceparam << " * atan(v.t, v.s);" << endl + << " src.t = " << distanceparam << " * s * src.t / length(v);" << endl + << " }" << endl + << endl; +} + +static void rect_sphere_tp_glsl(ostringstream& oss, const void* params) { + oss << " // rect_sphere_tp(" << distanceparam << ")" << endl + << " {" << endl + << " float r = length(src);" << endl + << " float theta = r / " << distanceparam << ";" << endl + << " float rho = 0.0;" << endl + << " if (theta >= " << (M_PI / 2.0) << ") rho = 1.6e16;" << endl + << " else if (theta == 0.0) rho = 1.0;" << endl + << " else rho = tan(theta) / theta;" << endl + << " src *= rho;" << endl + << " }" << endl + << endl; +} + +static void persp_sphere_glsl(ostringstream& oss, const void* params) { + double d = *((double*) ((void**)params)[1]); + double (*m)[3] = (double(*)[3]) ((void**)params)[0]; + oss << " // persp_sphere(" << d << ")" << endl + << " {" << endl + << " mat3 m = mat3(" << m[0][0] << ", " << m[1][0] << ", " << m[2][0] << "," << endl + << " " << m[0][1] << ", " << m[1][1] << ", " << m[2][1] << "," << endl + << " " << m[0][2] << ", " << m[1][2] << ", " << m[2][2] << ");" << endl + << " float r = length(src);" << endl + << " float theta = r / " << d << ";" << endl + << " float s = 0.0;" << endl + << " if (r != 0.0) s = sin(theta) / r;" << endl + << " vec3 v = vec3(s * src.s, s * src.t, cos(theta));" << endl + << " vec3 u = v * m;" << endl + << " r = length(u.st);" << endl + << " theta = 0.0;" << endl + << " if (r != 0.0) theta = " << d << " * atan(r, u.p) / r;" << endl + << " src = theta * u.st;" << endl + << " }" << endl + << endl; +} + +static void erect_mercator_glsl(ostringstream& oss, const void* params) { + oss << " // erect_mercator(" << distanceparam << ")" << endl + << " src.t = " << distanceparam << " * atan(sinh(src.t/" << distanceparam << "));" << endl + << endl; +} + +static void erect_millercylindrical_glsl(ostringstream& oss, const void* params) { + oss << " // erect_millercylindrical(" << distanceparam << ")" << endl + << " src.t = " << (1.25 * distanceparam) << " * atan(sinh(src.t * " << (4 / (5.0 * distanceparam)) << "));" << endl + << endl; +} + +static void erect_lambert_glsl(ostringstream& oss, const void* params) { + oss << " // erect_lambert(" << distanceparam << ")" << endl + << " src.t = " << distanceparam << " * asin(src.t / " << distanceparam << ");" << endl + << endl; +} + +static void erect_transmercator_glsl(ostringstream& oss, const void* params) { + oss << " // erect_transmercator(" << distanceparam << ")" << endl + << " {" << endl + << " src /= " << distanceparam << ";" << endl + << " if (abs(src.t) > " << M_PI << ") discard;" << endl + << " float x = src.s;" << endl + << " src.s = " << distanceparam << " * atan(sinh(src.s), cos(src.t));" << endl + << " src.t = " << distanceparam << " * asin(sin(src.t) / cosh(x));" << endl + << " }" << endl + << endl; +} + +static void erect_sinusoidal_glsl(ostringstream& oss, const void* params) { + oss << " // erect_sinusoidal(" << distanceparam << ")" << endl + << " src.s /= cos(src.t / " << distanceparam << ");" << endl + << " if (abs(src.s) > " << (M_PI * distanceparam) << ") discard;" << endl + << endl; +} + +namespace HuginBase { namespace PTools { + +bool Transform::emitGLSL(ostringstream& oss) const { + + oss << " vec2 src = gl_TexCoord[0].st;" << endl + << " src -= vec2(" << m_srcTX << ", " << m_srcTY << ");" << endl + << endl; + + bool foundUnsupportedFunction = false; + int i = 0; + const fDesc* stack = m_stack; + + while ( (stack->func) != NULL ) { + if (stack->func == rotate_erect) rotate_erect_glsl(oss, stack->param); + else if (stack->func == resize) resize_glsl(oss, stack->param); + else if (stack->func == vert) vert_glsl(oss, stack->param); + else if (stack->func == horiz) horiz_glsl(oss, stack->param); + else if (stack->func == shear) shear_glsl(oss, stack->param); + else if (stack->func == erect_pano) erect_pano_glsl(oss, stack->param); + else if (stack->func == erect_rect) erect_rect_glsl(oss, stack->param); + else if (stack->func == erect_sphere_tp) erect_sphere_tp_glsl(oss, stack->param); + else if (stack->func == sphere_tp_erect) sphere_tp_erect_glsl(oss, stack->param); + else if (stack->func == vertical) vertical_glsl(oss, stack->param); + else if (stack->func == deregister) deregister_glsl(oss, stack->param); + else if (stack->func == radial) radial_glsl(oss, stack->param); + else if (stack->func == pano_sphere_tp) pano_sphere_tp_glsl(oss, stack->param); + else if (stack->func == rect_sphere_tp) rect_sphere_tp_glsl(oss, stack->param); + else if (stack->func == persp_sphere) persp_sphere_glsl(oss, stack->param); + else if (stack->func == erect_mercator) erect_mercator_glsl(oss, stack->param); + else if (stack->func == erect_millercylindrical) erect_millercylindrical_glsl(oss, stack->param); + else if (stack->func == erect_lambert) erect_lambert_glsl(oss, stack->param); + else if (stack->func == erect_transmercator) erect_transmercator_glsl(oss, stack->param); + else if (stack->func == erect_sinusoidal) erect_sinusoidal_glsl(oss, stack->param); + else { + oss << " // Unknown function " << (const void*)stack->func << endl << endl; + foundUnsupportedFunction = true; + } + ++stack; + ++i; + } + + oss << " src += vec2(" << (m_destTX-0.5) << ", " << (m_destTY-0.5) << ");" << endl + << endl; + + return !foundUnsupportedFunction; +} + +}} // namespace Modified: hugin/branches/nona-gpu/src/hugin_base/vigra_ext/CMakeLists.txt =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/vigra_ext/CMakeLists.txt 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/src/hugin_base/vigra_ext/CMakeLists.txt 2008-10-21 05:23:46 UTC (rev 3511) @@ -1,3 +1,3 @@ -add_library(huginvigra_ext STATIC MultiThreadOperations.cpp emor.cpp) +add_library(huginvigra_ext STATIC MultiThreadOperations.cpp emor.cpp ImageTransformsGPU.cpp) Modified: hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransforms.h =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransforms.h 2008-10-21 04:40:06 UTC (rev 3510) +++ hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransforms.h 2008-10-21 05:23:46 UTC (rev 3511) @@ -27,6 +27,7 @@ #ifndef _VIGRA_EXT_IMAGETRANSFORMS_H #define _VIGRA_EXT_IMAGETRANSFORMS_H +#include <iostream> #include <fstream> #include <vigra/basicimage.hxx> @@ -43,6 +44,9 @@ #include <boost/thread/thread.hpp> #include <boost/bind.hpp> +#include <sys/time.h> +#include <time.h> + namespace vigra_ext { @@ -86,6 +90,9 @@ bool warparound, AppBase::MultiProgressDisplay & prog) { + timeval t0; + gettimeofday(&t0, NULL); + vigra::Diff2D destSize = dest.second - dest.first; int xstart = destUL.x; @@ -134,6 +141,10 @@ } } prog.popTask(); + + timeval t1; + gettimeofday(&t1, NULL); + std::cout << "deltaT=" << (t1.tv_sec - t0.tv_sec + 1e-6*(t1.tv_usec - t0.tv_usec)) << std::endl; } Added: hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.cpp =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.cpp (rev 0) +++ hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.cpp 2008-10-21 05:23:46 UTC (rev 3511) @@ -0,0 +1,234 @@ +// -*- c-basic-offset: 4 -*- +/** @file ImageTransformsGPU.cpp + * + * Support functions for GPU remapping. + * + * @author Andrew Mihal + * + * $Id:$ + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <iostream> + +#define GLEW_STATIC +#include <GL/glew.h> +#include <GL/glut.h> + +#include <sys/time.h> +#include <time.h> + +using std::cout; +using std::cerr; +using std::endl; + +#define CHECK_GL() checkGLErrors(__LINE__, __FILE__) + +static void checkGLErrors(int line, char *file) { + GLenum errCode; + if ((errCode = glGetError()) != GL_NO_ERROR) { + cerr << "nona: GL error in " << file << ":" << line << ": " << gluErrorString(errCode) << endl; + exit(1); + } +} + +static void printInfoLog(GLhandleARB obj) { + GLint infologLength = 0; + GLint charsWritten = 0; + char *infoLog; + glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength); + if (infologLength > 1) { + infoLog = new char[infologLength]; + glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog); + cout << "nona: GL info log:" << endl << infoLog << endl; + delete[] infoLog; + } +} + +static bool checkFramebufferStatus() { + GLenum status; + status = (GLenum) glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + switch(status) { + case GL_FRAMEBUFFER_COMPLETE_EXT: + return true; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + cerr << "nona: GL error: Framebuffer incomplete, incomplete attachment" << endl; + return false; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + cerr << "nona: Unsupported framebuffer format" << endl; + return false; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + cerr << "nona: Framebuffer incomplete, missing attachment" << endl; + return false; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + cerr << "nona: Framebuffer incomplete, attached images must have same dimensions" << endl; + return false; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + cerr << "nona: Framebuffer incomplete, attached images must have same format" << endl; + return false; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + cerr << "nona: Framebuffer incomplete, missing draw buffer" << endl; + return false; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + cerr << "nona: Framebuffer incomplete, missing read buffer" << endl; + return false; + } + + return false; +} + +namespace vigra_ext +{ + +bool transformImageGPUIntern(const std::string& glsl, + const int srcWidth, const int srcHeight, + float* const srcBuffer, + const int destXStart, const int destXEnd, + const int destYStart, const int destYEnd, + const int destWidth, const int destHeight, + float* const destBuffer, + const bool warparound) { + + timeval t0; + gettimeofday(&t0, NULL); + + const char* glslCString = glsl.c_str(); + cout << glslCString; + + cout << "destStart=[" << destXStart << ", " << destYStart << "]" << endl + << "destEnd=[" << destXEnd << ", " << destYEnd << "]" << endl + << "destSize=[" << destWidth << ", " << destHeight << "]" << endl + << "srcSize=[" << srcWidth << ", " << srcHeight << "]" << endl; + + GLint maxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + cout << "maxTextureSize=" << maxTextureSize << endl; + + GLhandleARB programObject = glCreateProgramObjectARB(); + GLhandleARB shaderObject = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + glShaderSourceARB(shaderObject, 1, &glslCString, NULL); + glCompileShaderARB(shaderObject); + printInfoLog(shaderObject); + glAttachObjectARB(programObject, shaderObject); + glLinkProgramARB(programObject); + GLint success; + glGetObjectParameterivARB(programObject, GL_OBJECT_LINK_STATUS_ARB, &success); + if (!success) { + printInfoLog(programObject); + cerr << "nona: GPU ARB shader program could not be linked." << endl; + exit(1); + } + + GLint srcTextureParam = glGetUniformLocationARB(programObject, "SrcTexture"); + + glUseProgramObjectARB(programObject); + + GLuint srcTexture; + glGenTextures(1, &srcTexture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture); + 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_TEXTURE_WRAP_S, (warparound) ? GL_REPEAT : GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, srcWidth, srcHeight, 0, GL_RGBA, GL_FLOAT, NULL); + CHECK_GL(); + + GLuint outTexture; + glGenTextures(1, &outTexture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, outTexture); + 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_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F_ARB, destWidth, destHeight, 0, GL_RGBA, GL_FLOAT, NULL); + CHECK_GL(); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + GLuint fb; + glGenFramebuffersEXT(1, &fb); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.0, destWidth, 0.0, destHeight); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glViewport(0, 0, destWidth, destHeight); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, outTexture, 0); + + if (!checkFramebufferStatus()) { + exit(1); + } + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture); + glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, srcWidth, srcHeight, GL_RGBA, GL_FLOAT, srcBuffer); + CHECK_GL(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture); + glUniform1iARB(srcTextureParam, 0); + CHECK_GL(); + + timeval t1; + gettimeofday(&t1, NULL); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glPolygonMode(GL_FRONT, GL_FILL); + glBegin(GL_QUADS); + glTexCoord2f(destXStart, destYStart); glVertex2f(0.0, 0.0); + glTexCoord2f(destXEnd, destYStart); glVertex2f(destWidth, 0.0); + glTexCoord2f(destXEnd, destYEnd); glVertex2f(destWidth, destHeight); + glTexCoord2f(destXStart, destYEnd); glVertex2f(0.0, destHeight); + glEnd(); + CHECK_GL(); + + glFinish(); + CHECK_GL(); + + timeval t2; + gettimeofday(&t2, NULL); + + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + CHECK_GL(); + + timeval t3; + gettimeofday(&t3, NULL); + + glReadPixels(0, 0, destWidth, destHeight, GL_RGBA, GL_FLOAT, destBuffer); + CHECK_GL(); + + timeval t4; + gettimeofday(&t4, NULL); + + glDeleteFramebuffersEXT(1, &fb); + glDeleteTextures(1, &outTexture); + glDeleteTextures(1, &srcTexture); + + glUseProgramObjectARB(0); + glDeleteObjectARB(shaderObject); + glDeleteObjectARB(programObject); + + cout << "t1-t0=" << (t1.tv_sec - t0.tv_sec + 1e-6*(t1.tv_usec - t0.tv_usec)) << endl; + cout << "t2-t1=" << (t2.tv_sec - t1.tv_sec + 1e-6*(t2.tv_usec - t1.tv_usec)) << endl; + cout << "t3-t2=" << (t3.tv_sec - t2.tv_sec + 1e-6*(t3.tv_usec - t2.tv_usec)) << endl; + cout << "t4-t3=" << (t4.tv_sec - t3.tv_sec + 1e-6*(t4.tv_usec - t3.tv_usec)) << endl; + + return true; +} + +}; // namespace Added: hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.h =================================================================== --- hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.h (rev 0) +++ hugin/branches/nona-gpu/src/hugin_base/vigra_ext/ImageTransformsGPU.h 2008-10-21 05:23:46 UTC (rev 3511) @@ -0,0 +1,602 @@ +// -*- c-basic-offset: 4 -*- +/** @file ImageTransformsGPU.h + * + * Contains functions to transform whole images. + * Uses PTools::Transform for the calculations + * + * @author Andrew Mihal + * + * $Id:$ + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _VIGRA_EXT_IMAGETRANSFORMSGPU_H +#define _VIGRA_EXT_IMAGETRANSFORMSGPU_H + +#include <fstream> +#include <iostream> +#include <iomanip> + +#include <vigra/basicimage.hxx> +#include <vigra_ext/ROIImage.h> +#include <vigra_ext/Interpolators.h> +#include <vigra/impex.hxx> +#include <vigra_ext/impexalpha.hxx> +#include <vigra_ext/FunctorAccessor.h> + +#include <hugin_math/hugin_math.h> +#include <hugin_utils/utils.h> +#include <appbase/ProgressDisplayOld.h> + +#include "MultiThreadOperations.h" +#include <boost/thread/thread.hpp> +#include <boost/bind.hpp> + +using vigra::NumericTraits; + +namespace vigra_ext +{ + +bool transformImageGPUIntern(const std::string& glsl, + const int srcWidth, const int srcHeight, + float* const srcBuffer, + const int destXStart, const int destXEnd, + const int destYStart, const int destYEnd, + const int destWidth, const int destHeight, + float* const destBuffer, + const bool warparound); + +/* Wrappers to use the RGB GPU transform code for grayscale images. + * The GPU uses vec4 pixel values so there is no point in specializing code + * for single-channel images. + */ + +template <class SrcValueType> +class ConvertToRGBValue { +public: + typedef typename vigra::RGBValue<SrcValueType, 0, 1, 2> result_type; + result_type operator()(const SrcValueType& s) const { + return result_type(s); + } +}; + +template <class ResultValueType> +class ConvertFromRGBValue { +public: + typedef typename vigra::RGBValue<ResultValueType, 0, 1, 2> SrcValueType; + ResultValueType operator()(const SrcValueType& s) const { + return ResultValueType(s.red()); + } +}; + +template <class SrcImageIterator, class SrcAccessor, + class DestImageIterator, class DestAccessor, + class TRANSFORM, + class PixelTransform, + class AlphaImageIterator, class AlphaAccessor, + class Interpolator> +void transformImageGPUIntern(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, + vigra::triple<DestImageIterator, DestImageIterator, DestAccessor> dest, + std::pair<AlphaImageIterator, AlphaAccessor> alpha, + TRANSFORM & transform, + PixelTransform & pixelTransform, + vigra::Diff2D destUL, + Interpolator interp, + bool warparound, + AppBase::MultiProgressDisplay & prog, + vigra::VigraTrueType) +{ + typedef typename SrcAccessor::value_type SrcValueType; + typedef typename vigra_ext::ReadFunctorAccessor<ConvertToRGBValue<SrcValueType>, SrcAccessor> RFAType; + RFAType convert_sa(ConvertToRGBValue<SrcValueType>(), src.third); + vigra::triple<SrcImageIterator, SrcImageIterator, RFAType> convert_src(src.first, src.second, convert_sa); + + typedef typename DestAccessor::value_type DestValueType; + typedef typename vigra_ext::WriteFunctorAccessor<ConvertFromRGBValue<DestValueType>, DestAccessor, vigra::RGBValue<DestValueType, 0, 1, 2> > WFAType; + WFAType convert_da(ConvertFromRGBValue<DestValueType>(), dest.third); + vigra::triple<DestImageIterator, DestImageIterator, WFAType> convert_dest(dest.first, dest.second, convert_da); + + transformImageGPUIntern(convert_src, convert_dest, alpha, transform, pixelTransform, destUL, interp, warparound, prog, vigra::VigraFalseType()); +} + +template <class SrcImageIterator, class SrcAccessor, + class SrcAlphaIterator, class SrcAlphaAccessor, + class DestImageIterator, class DestAccessor, + class TRANSFORM, + class PixelTransform, + class AlphaImageIterator, class AlphaAccessor, + class Interpolator> +void transformImageAlphaGPUIntern(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, + std::pair<SrcAlphaIterator, SrcAlphaAccessor> srcAlpha, + vigra::triple<DestImageIterator, DestImageIterator, DestAccessor> dest, + std::pair<AlphaImageIterator, AlphaAccessor> alpha, + TRANSFORM & transform, + PixelTransform & pixelTransform, + vigra::Diff2D destUL, + Interpolator interp, + bool warparound, + AppBase::MultiProgressDisplay & prog, + vigra::VigraTrueType) +{ + typedef typename SrcAccessor::value_type SrcValueType; + typedef typename vigra_ext::ReadFunctorAccessor<ConvertToRGBValue<SrcValueType>, SrcAccessor> RFAType; + RFAType convert_sa(ConvertToRGBValue<SrcValueType>(), src.third); + vigra::triple<SrcImageIterator, SrcImageIterator, RFAType> convert_src(src.first, src.second, convert_sa); + + typedef typename DestAccessor::value_type DestValueType; + typedef typename vigra_ext::WriteFunctorAccessor<ConvertFromRGBValue<DestValueType>, DestAccessor, vigra::RGBValue<DestValueType, 0, 1, 2> > WFAType; + WFAType convert_da(ConvertFromRGBValue<DestValueType>(), dest.third); + vigra::triple<DestImageIterator, DestImageIterator, WFAType> convert_dest(dest.first, dest.second, convert_da); + + transformImageAlphaGPUIntern(convert_src, srcAlpha, convert_dest, alpha, transform, pixelTransform, destUL, interp, warparound, prog, vigra::VigraFalseType()); +} + +/** Transform an image into the panorama + * + * Uses the GPU for processing. + * + * It can be used for partial transformations as well, if the bounding + * box of a remapped image is known. + * + * Usage: create an output image @dest that should contain the remapped + * @p src image. if @p dest doesn't cover the whole output panorama, + * use @p destUL to specify the offset of @p dest from the output + * panorama. + * + * @param src source image + * @param dest (partial) panorama image. the image size needed to + * hold the complete remapped image can be calculated using + * calcBorderPoints(). + * @param destUL upper left point of @p dest in final panorama. set to (0,0) + * if @p dest has the same size as the complete panorama. + * @param transform function used to remap the picture. + * @param centerDist image, with the same size as dest, that will contain the + * distance of the corrosponding pixel from the center of @p + * src. This is useful to calculate nice seams. Use a null + * image if this information is not needed. + * @param interp Interpolator class (calculates weights for interpolation) + * + */ +template <class SrcImageIterator, class SrcAccessor, + class DestImageIterator, class DestAccessor, + class TRANSFORM, + class PixelTransform, + class AlphaImageIterator, class AlphaAccessor, + class Interpolator> +void transformImageGPUIntern(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, + vigra::triple<DestImageIterator, DestImageIterator, DestAccessor> dest, + std::pair<AlphaImageIterator, AlphaAccessor> alpha, + TRANSFORM & transform, + PixelTransform & pixelTransform, + vigra::Diff2D destUL, + Interpolator interp, + bool warparound, + AppBase::MultiProgressDisplay & prog, + vigra::VigraFalseType) +{ + typedef typename SrcAccessor::value_type SrcValueType; + typedef typename SrcValueType::value_type SrcComponentType; + typedef typename DestAccessor::value_type DestValueType; + typedef typename DestValueType::value_type DestComponentType; + + vigra::Diff2D srcSize = src.second - src.first; + vigra::Diff2D destSize = dest.second - dest.first; + + const int xstart = destUL.x; + const int xend = destUL.x + destSize.x; + const int ystart = destUL.y; + const int yend = destUL.y + destSize.y; + + prog.pushTask(AppBase::ProgressTask("Remapping", "", 1.0/(yend-ystart))); + + vigra_ext::ImageInterpolator<SrcImageIterator, SrcAccessor, Interpolator> + interpol (src, interp, warparound); + + // Set up stream for writing GLSL shader program. + std::ostringstream oss; + oss << std::setprecision(20) << std::showpoint; + + // Emit coordinate transform and interpolator as GLSL shader program. + oss << "#extension GL_ARB_texture_rectangle : enable" << std::endl + << "#version 110" << std::endl + << "uniform sampler2DRect SrcTexture;" << std::endl + << "vec2 sinc(const in vec2 x) {" << std::endl + << " vec2 xpi = x * " << M_PI << ";" << std::endl + << " vec2 result = vec2(1.0, 1.0);" << std::endl + << " if (xpi.s != 0.0) result.s = sin(xpi.s) / xpi.s;" << std::endl + << " if (xpi.t != 0.0) result.t = sin(xpi.t) / xpi.t;" << std::endl + << " return result;" << std::endl + << "}" << std::endl + << "float sinh(const in float x) { return (exp(x) - exp(-x)) / 2.0; }" << std::endl + << "float cosh(const in float x) { return (exp(x) + exp(-x)) / 2.0; }" << std::endl + << "void main(void)" << std::endl + << "{" << std::endl; + transform.emitGLSL(oss); + interpol.emitGLSL(oss); + // FIXME need to do response transform + oss << " gl_FragColor = p;" << std::endl + << "}" << std::endl; + + float* destBuffer = new float[4 * destSize.x * destSize.y]; + float* srcBuffer = new float[4 * srcSize.x * srcSize.y]; + + // Copy source image to srcBuffer + int srcBufferIndex = 0; + for (SrcImageIterator sy = src.first; sy.y != src.second.y; ++sy.y) { + for (SrcImageIterator sx = sy; sx.x != src.second.x; ++sx.x) { + srcBuffer[srcBufferIndex++] = NumericTraits<SrcComponentType>::toRealPromote(src.third(sx).red()); + srcBuffer[srcBufferIndex++] = NumericTraits<SrcComponentType>::toRealPromote(src.third(sx).green()); + srcBuffer[srcBufferIndex++] = NumericTraits<SrcComponentType>::toRealPromote(src.third(sx).blue()); + srcBuffer[srcBufferIndex++] = 1.0f; + } + } + + // Do remapping. + transformImageGPUIntern(oss.str(), + srcSize.x, srcSize.y, + srcBuffer, + xstart, xend, + ystart, yend, + destSize.x, destSize.y, + destBuffer, + warparound); + + // Done with srcBuffer. + delete[] srcBuffer; + + // Copy dest buffer to dest image with pixelTransform. + DestImageIterator yd(dest.first); + AlphaImageIterator ydm(alpha.first); + DestValueType tempval; + + int destBufferIndex = 0; + for(int y=ystart; y < yend; ++y, ++yd.y, ++ydm.y) + { + // create x iterators + DestImageIterator xd(yd); + AlphaImageIterator xdm(ydm); + for(int x=xstart; x < xend; ++x, ++xd.x, ++xdm.x) + { + tempval.red() = NumericTraits<DestComponentType>::fromRealPromote(destBuffer[destBufferIndex++]); + tempval.green() = NumericTraits<DestComponentType>::fromRealPromote(destBuffer[destBufferIndex++]); + tempval.blue() = NumericTraits<DestComponentType>::fromRealPromote(destBuffer[destBufferIndex++]); + float a = destBuffer[destBufferIndex++]; + + if (a != 0.0) { + dest.third.set(tempval, xd); + //dest.third.set( pixelTransform(tempval, hugin_utils::FDiff2D(0.0, 0.0)), xd); + alpha.second.set(pixelTransform.hdrWeight(tempval, vigra::UInt8(255)), xdm); + } else { + alpha.second.set(0, xdm); + } + } + if (destSize.y > 100) { + if ((y-ystart)%(destSize.y/20) == 0) { + prog.setProgress(((double)y-ystart)/destSize.y); + } + } + } + + // Done with destBuffer. + delete[] destBuffer; + + prog.popTask(); + +} + + +/** transform input images with alpha channel */ +template <class SrcImageIterator, class SrcAccessor, + class SrcAlphaIterator, class SrcAlphaAccessor, + class DestImageIterator, class DestAccessor, + class TRANSFORM, + class PixelTransform, + class AlphaImageIterator, class AlphaAccessor, + class Interpolator> +void transformImageAlphaGPUIntern(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, + std::pair<SrcAlphaIterator, SrcAlphaAccessor> srcAlpha, + vigra::triple<DestImageIterator, DestImageIterator, DestAccessor> dest, + std::pair<AlphaImageIterator, AlphaAccessor> alpha, + TRANSFORM & transform, + PixelTransform & pixelTransform, + vigra::Diff2D destUL, + Interpolator interp, + bool warparound, + AppBase::MultiProgressDisplay & prog, + vigra::VigraFalseType) +{ + typedef typename SrcAlphaAccessor::value_type SrcAlphaType; + typedef typename SrcAccessor::value_type SrcValueType; + typedef typename SrcValueType::value_type SrcComponentType; + typedef typename DestAccessor::value_type DestValueType; + typedef typename DestValueType::value_type DestComponentType; + + vigra::Diff2D srcSize = src.second - src.first; + vigra::Diff2D destSize = dest.second - dest.first; + + const int xstart = destUL.x; + const int xend = destUL.x + destSize.x; + const int ystart = destUL.y; + const int yend = destUL.y + destSize.y; + + prog.pushTask(AppBase::ProgressTask("Remapping", "", 1.0/(yend-ystart))); + + // Note that GPU interpolators are the same for source images with and without alpha channels. + vigra_ext::ImageInterpolator<SrcImageIterator, SrcAccessor, Interpolator> + interpol (src, interp, warparound); + + // Set up stream for writing GLSL shader program. + std::ostringstream oss; + oss << std::setprecision(20) << std::showpoint; + + // Emit coordinate transform and interpolator as GLSL shader program. + oss << "#extension GL_ARB_texture_rectangle : enable" << endl + << "#version 110" << std::endl + << "uniform sampler2DRect SrcTexture;" << std::endl + << "vec2 sinc(const in vec2 x) {" << std::endl + << " vec2 xpi = x * " << M_PI << ";" << std::endl + << " vec2 result = vec2(1.0, 1.0);" << std::endl + << " if (xpi.s != 0.0) result.s = sin(xpi.s) / xpi.s;" << std::endl + << " if (xpi.t != 0.0) result.t = sin(xpi.t) / xpi.t;" << std::endl + << " return result;" << std::endl + << "}" << std::endl + << "float sinh(const in float x) { return (exp(x) - exp(-x)) / 2.0; }" << std::endl + << "float cosh(const in float x) { return (exp(x) + exp(-x)) / 2.0; }" << std::endl + << "void main(void)" << std::endl + << "{" << std::endl; + transform.emitGLSL(oss); + interpol.emitGLSL(oss); + // FIXME need to do response transform + oss << " gl_FragColor = p;" << std::endl + << "}" << std::endl; + + float* destBuffer = new float[4 * destSize.x * destSize.y]; + float* srcBuffer = new float[4 * srcSize.x * srcSize.y]; + + // Copy source image to srcBuffer + int srcBufferIndex = 0; + SrcAlphaIterator ay = srcAlpha.first; + for (SrcImageIterator sy = src.first; sy.y != src.second.y; ++sy.y, ++ay.y) { + SrcAlphaIterator ax = ay; + for (SrcImageIterator sx = sy; sx.x != src.second.x; ++sx.x, ++ax.x) { + srcBuffer[srcBufferIndex++] = NumericTraits<SrcComponentType>::toRealPromote(src.third(sx).red()); + srcBuffer[srcBufferIndex++] = NumericTraits<SrcComponentType>::toRealPromote(src.third(sx).green()); + srcBuffer[srcBufferIndex++] = NumericTraits<SrcComponentType>::toRealPromote(src.third(sx).blue()); + srcBuffer[srcBufferIndex++] = NumericTraits<SrcAlphaType>::toRealPromote(srcAlpha.second(ax)); + } + } + + // Do remapping. + transformImageGPUIntern(oss.str(), + srcSize.x, srcSize.y, + srcBuffer, + xstart, xend, + ystart, yend, + destSize.x, destSize.y, + destBuffer, + warparound); + + // Done with srcBuffer. + delete[] srcBuffer; + + // Copy dest buffer to dest image with pixelTransform. + DestImageIterator yd(dest.first); + AlphaImageIterator ydm(alpha.first); + DestValueType tempval; + SrcAlphaType alphaval; + + int destBufferIndex = 0; + for(int y=ystart; y < yend; ++y, ++yd.y, ++ydm.y) + { + // create x iterators + DestImageIterator xd(yd); + AlphaImageIterator xdm(ydm); + for(int x=xstart; x < xend; ++x, ++xd.x, ++xdm.x) + { + tempval.red() = NumericTraits<DestComponentType>::fromRealPromote(destBuffer[destBufferIndex++]); + tempval.green() = NumericTraits<DestComponentType>::fromRealPromote(destBuffer[destBufferIndex++]); + tempval.blue() = NumericTraits<DestComponentType>::fromRealPromote(destBuffer[destBufferIndex++]); + float a = destBuffer[destBufferIndex++]; + alphaval = NumericTraits<SrcAlphaType>::fromRealPromote(a); + + if (a != 0.0) { + dest.third.set(tempval, xd); + //dest.third.set( pixelTransform(tempval, hugin_utils::FDiff2D(0.0, 0.0)), xd); + alpha.second.set(pixelTransform.hdrWeight(tempval, alphaval), xdm); + } else { + alpha.second.set(0, xdm); + } + } + if (destSize.y > 100) { + if ((y-ystart)%(destSize.y/20) == 0) { + prog.setProgress(((double)y-ystart)/destSize.y); + } + } + } + + // Done with destBuffer. + delete[] destBuffer; + + prog.popTask(); +}; + + +/** Transform an image into the panorama + * + * Uses the GPU for processing. + * + * It can be used for partial transformations as well, if the boundig + * box of a remapped image is known. + * + * Usage: create an output image @dest that should contain the remapped + * @p src image. if @p dest doesn't cover the whole output panorama, + * use @p destUL to specify the offset of @p dest from the output + * panorama. + * + * @param src source image + * @param dest (partial) panorama image. the image size needed to + * hold the complete remapped image can be calculated using + * calcBorderPoints(). + * @param destUL upper left point of @p dest in final panorama. set to (0,0) + * if @p dest has the same size as the complete panorama. + * @param transform function used to remap the picture. + * @param centerDist image, with the same size as dest, that will contain the + * distance of the corrosponding pixel from the center of @p + * src. This is useful to calculate nice seams. Use a null + * image if this information is not needed. + * @param interpol Interpolation algorithm that should be used. + * + */ +template <class SrcImageIterator, class SrcAccessor, + class DestImageIterator, class DestAccessor, + class AlphaImageIterator, class AlphaAccessor, + class TRANSFORM, + class PixelTransform> +void transformImageGPU(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src, + vigra::triple<DestImageIterator, DestImageIterator, DestAccessor> dest, + std::pair<AlphaImageIterator, AlphaAccessor> alpha, + vigra::Diff2D destUL, + TRANSFORM & transform, + PixelTransform & pixelTransform, + bool warparound, + Interpolator interpol, + AppBase::MultiProgressDisplay & progress) +{ + typedef typename SrcAccessor::value_type SrcValueType; + typedef typename NumericTraits<SrcValueType>::isScalar srcIsScalar; + + switch (interpol) { + case INTERP_CUBIC: + DEBUG_DEBUG("using cubic interpolator"); + transformImageGPUIntern(src, dest, alpha, transform, pixelTransform, destUL, + vigra_ext::interp_cubic(), warparound, + progress, srcIsScalar()); + break; + case INTERP_SPLINE_16: + DEBUG_DEBUG("interpolator: spline16"); + transformImageGPUIntern(src, dest, alpha, transform, pixelTransform, destUL, + vigra_ext::interp_spline16(), warparound, + progress, srcIsScalar()); + break; + case INTERP_SPLINE_36: + DEBUG_DEBUG("interpolator: spline36"); + transformImageGPUIntern(src, dest, alpha, transform, pixelTransform, destUL, + vigra_ext::interp_spline36(), warparound, + progress, srcIsScalar()); + break; + case INTERP_SPLINE_64: + DEBUG_DEBUG("interpolator: spline64"); + transformImageGPUIntern(src, dest, alpha, transform, pixelTransform, destUL, + ... [truncated message content] |