/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2012 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLGeom/src/PointcloudSceneObject.cpp ** ** Module : ICLGeom ** ** Authors: Andre Ueckermann ** ** ** ** ** ** Commercial License ** ** ICL can be used commercially, please refer to our website ** ** www.iclcv.org for more details. ** ** ** ** GNU General Public License Usage ** ** Alternatively, this file may be used under the terms of the ** ** GNU General Public License version 3.0 as published by the ** ** Free Software Foundation and appearing in the file LICENSE.GPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the GNU General Public License ** ** version 3.0 requirements will be met: ** ** http://www.gnu.org/copyleft/gpl.html. ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** *********************************************************************/ #define __CL_ENABLE_EXCEPTIONS //enables openCL error catching #include <ICLGeom/PointcloudSceneObject.h> #ifdef HAVE_OPENCL #include <CL/cl.hpp> #endif #include <ICLQuick/Quick.h> #include <ICLGeom/GeomDefs.h> namespace icl{ //OpenCL kernel code static char pointcloudViewerKernel[] = "__kernel void \n" "calculateUniColor(__global float const * depth, __global float4 const * vrOffset, __global float4 const * vrDirection, __global float const * norms, __global float4 * outV, __global float4 * outC, float4 const color, float const scale) \n" "{ \n" " size_t id = get_global_id(0); \n" " float d = 1.046 * (depth[id]==2047 ? 0 : 1000. / (depth[id] * -0.0030711016 + 3.3309495161)); \n" " float lambda = d*norms[id]*scale; \n" " float4 out = vrOffset[id]+vrDirection[id]*lambda; \n" " out.w=1; \n" " outV[id]=out; \n" " if(depth[id]==2047) \n" " { \n" " outC[id]=((float4)(0,0,0,0)); \n" " } \n" " else \n" " { \n" " outC[id]=color; \n" " } \n" "} \n" "__kernel void \n" "calculateRGBColor(__global float const * depth, __global float4 const * vrOffset, __global float4 const * vrDirection, __global float const * norms, __global float4 * outV, __global float4 * outC, __global uchar const * colorR, __global uchar const * colorG, __global uchar const * colorB, float const scale, __global float const * H, int const w, int const h) \n" "{ \n" " size_t id = get_global_id(0); \n" " float d = 1.046 * (depth[id]==2047 ? 0 : 1000. / (depth[id] * -0.0030711016 + 3.3309495161)); \n" " float lambda = d*norms[id]*scale; \n" " float4 out = vrOffset[id]+vrDirection[id]*lambda; \n" " out.w=1; \n" " outV[id]=out; \n" " if(depth[id]==2047) \n" " { \n" " outC[id]=((float4)(0,0,0,0)); \n" " } \n" " else \n" " { \n" " int y = (int)floor((float)id/(float)w); \n" " int x = id-y*w; \n" " float az = H[6]*x + H[7] * y + H[8]; \n" " int ax = (int)round(( H[0]*(float)x + H[1] * (float)y + H[2] ) / az); \n" " int ay = (int)round(( H[3]*(float)x + H[4] * (float)y + H[5] ) / az); \n" " if(ax>=0 && ax<w && ay>=0 && ay<h) \n" " { \n" " outC[id] = ((float4)(colorR[ax+ay*w]/255., colorG[ax+ay*w]/255., colorB[ax+ay*w]/255.,1.)); \n" " } \n" " } \n" "} \n" "__kernel void \n" "calculatePseudoColor(__global float const * depth, __global float4 const * vrOffset, __global float4 const * vrDirection, __global float const * norms, __global float4 * outV, __global float4 * outC, __global uchar const * colorR, __global uchar const * colorG, __global uchar const * colorB, float const scale, int const w, int const h)\n" "{ \n" " size_t id = get_global_id(0); \n" " float d = 1.046 * (depth[id]==2047 ? 0 : 1000. / (depth[id] * -0.0030711016 + 3.3309495161)); \n" " float lambda = d*norms[id]*scale; \n" " float4 out = vrOffset[id]+vrDirection[id]*lambda; \n" " out.w=1; \n" " outV[id]=out; \n" " if(depth[id]==2047) \n" " { \n" " outC[id]=((float4)(0,0,0,0)); \n" " } \n" " else \n" " { \n" " int y = (int)floor((float)id/(float)w); \n" " int x = id-y*w; \n" " outC[id] = ((float4)(colorR[x+y*w]/255., colorG[x+y*w]/255., colorB[x+y*w]/255.,1.)); \n" " } \n" "} \n" "__kernel void \n" "calculateNormalDirectionColorCam(__global float const * depth, __global float4 const * vrOffset, __global float4 const * vrDirection, __global float const * norms, __global float4 * outV, __global float4 * outC, __global float4 * normals, float const scale) \n" "{ \n" " size_t id = get_global_id(0); \n" " float d = 1.046 * (depth[id]==2047 ? 0 : 1000. / (depth[id] * -0.0030711016 + 3.3309495161)); \n" " float lambda = d*norms[id]*scale; \n" " float4 out = vrOffset[id]+vrDirection[id]*lambda; \n" " out.w=1; \n" " outV[id]=out; \n" " if(depth[id]==2047) \n" " { \n" " outC[id]=((float4)(0,0,0,0)); \n" " } \n" " else \n" " { \n" " float4 n = normals[id]; \n" " float cx=fabs(n.x); \n" " float cy=fabs(n.y); \n" " float cz=fabs(n.z); \n" " outC[id] = ((float4)(cx, cy, cz,1.)); \n" " } \n" "} \n" "__kernel void \n" "calculateNormalDirectionColorWorld(__global float const * depth, __global float4 const * vrOffset, __global float4 const * vrDirection, __global float const * norms, __global float4 * outV, __global float4 * outC, __global float4 * normals, float const scale, __global float const * cam, __global float4 * outNormals) \n" "{ \n" " size_t id = get_global_id(0); \n" " float d = 1.046 * (depth[id]==2047 ? 0 : 1000. / (depth[id] * -0.0030711016 + 3.3309495161)); \n" " float lambda = d*norms[id]*scale; \n" " float4 out = vrOffset[id]+vrDirection[id]*lambda; \n" " out.w=1; \n" " outV[id]=out; \n" " if(depth[id]==2047) \n" " { \n" " outC[id]=((float4)(0,0,0,0)); \n" " } \n" " else \n" " { \n" " float4 pWN; \n" " float4 n= normals[id]; \n" " pWN.x=-(n.x*cam[0]+n.y*cam[1]+n.z*cam[2]); \n" " pWN.y=-(n.x*cam[4]+n.y*cam[5]+n.z*cam[6]); \n" " pWN.z=-(n.x*cam[8]+n.y*cam[9]+n.z*cam[10]); \n" " pWN.w=1; \n" " float cx=fabs(pWN.x); \n" " float cy=fabs(pWN.y); \n" " float cz=fabs(pWN.z); \n" " outC[id] = ((float4)(cx, cy, cz,1.)); \n" " outNormals[id]=pWN; \n" " } \n" "} \n" "__kernel void \n" "calculatePseudoColorDepthImage(__global float const * depth, __global uchar * R, __global uchar * G, __global uchar * B) \n" "{ \n" " size_t id = get_global_id(0); \n" " float v = depth[id]/2048.0; \n" " v = pown(v,3)*6; \n" " int pv = v*6*256; \n" " int lb = pv & 0xff; \n" " switch (pv>>8) { \n" " case 0: \n" " R[id] = 255; \n" " G[id] = 255-lb; \n" " B[id] = 255-lb; \n" " break; \n" " case 1: \n" " R[id] = 255; \n" " G[id] = lb; \n" " B[id] = 0; \n" " break; \n" " case 2: \n" " R[id] = 255-lb; \n" " G[id] = 255; \n" " B[id] = 0; \n" " break; \n" " case 3: \n" " R[id] = 0; \n" " G[id] = 255; \n" " B[id] = lb; \n" " break; \n" " case 4: \n" " R[id] = 0; \n" " G[id] = 255-lb; \n" " B[id] = 255; \n" " break; \n" " case 5: \n" " R[id] = 0; \n" " G[id] = 0; \n" " B[id] = 255-lb; \n" " break; \n" " default: \n" " R[id] = 0; \n" " G[id] = 0; \n" " B[id] = 0; \n" " break; \n" " } \n" "} \n" ; PointcloudSceneObject::PointcloudSceneObject(Size size, const Camera &cam){ H.id(); w=size.width; h=size.height; dim=w*h; s=size; setLockingEnabled(true); viewrayOffsets = new PointNormalEstimation::Vec4[w*h]; viewrayDirections = new PointNormalEstimation::Vec4[w*h]; highlightedIdx = -1; create_view_rays(w,h,cam); ViewRay v00 = cam.getViewRay(Point32f(w/2,h/2)); int i=0; norms.resize(w*h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x,++i){ addVertex(Vec(0,0,0,1),geom_blue()); norms[i] = 1.0/getNormFactor(rays[i],v00); viewrayOffsets[i].x=rays[i].offset[0]; viewrayOffsets[i].y=rays[i].offset[1]; viewrayOffsets[i].z=rays[i].offset[2]; viewrayOffsets[i].w=rays[i].offset[3]; viewrayDirections[i].x=rays[i].direction[0]; viewrayDirections[i].y=rays[i].direction[1]; viewrayDirections[i].z=rays[i].direction[2]; viewrayDirections[i].w=rays[i].direction[3]; } } inverseCamCSMatrix = cam.getCSTransformationMatrix().inv(); setVisible(Primitive::vertex,true); setPointSize(3); setLineWidth(4); depthScaling=1; useCL=true; normalLinesSet=false; useNormalLines=false; normalLinesLength=20.0; normalLinesGranularity=4; pWNormals=new PointNormalEstimation::Vec4[w*h]; for(int i=0; i<w*h; i++){ pWNormals[i].x=0; pWNormals[i].y=0; pWNormals[i].z=0; pWNormals[i].w=0; } #ifdef HAVE_OPENCL //create openCL context rawImageArray = new float[w*h]; outputVertices=new cl_float4[w*h]; outputColors=new cl_float4[w*h]; colorImageRArray=new cl_uchar[w*h]; colorImageGArray=new cl_uchar[w*h]; colorImageBArray=new cl_uchar[w*h]; pseudoImageRArray=new cl_uchar[w*h]; pseudoImageGArray=new cl_uchar[w*h]; pseudoImageBArray=new cl_uchar[w*h]; //init for(int i=0; i<w*h; i++){ rawImageArray[i]=0; outputVertices[i].x=0; outputVertices[i].y=0; outputVertices[i].z=0; outputVertices[i].w=0; outputColors[i].x=0; outputColors[i].y=0; outputColors[i].z=0; outputColors[i].w=0; colorImageRArray[i]=0; colorImageGArray[i]=0; colorImageBArray[i]=0; pseudoImageRArray[i]=0; pseudoImageGArray[i]=0; pseudoImageBArray[i]=0; } std::vector<cl::Platform> platformList;//get number of available openCL platforms int selectedDevice=0;//initially select platform 0 try{ if(cl::Platform::get(&platformList)==CL_SUCCESS){ std::cout<<"openCL platform found"<<std::endl; }else{ std::cout<<"no openCL platform available"<<std::endl; } std::cout<<"number of openCL platforms: "<<platformList.size()<<std::endl; //check devices on platforms for(unsigned int i=0; i<platformList.size(); i++){//check all platforms std::cout<<"platform "<<i+1<<":"<<std::endl; std::vector<cl::Device> deviceList; if(platformList.at(i).getDevices(CL_DEVICE_TYPE_GPU, &deviceList)==CL_SUCCESS){ std::cout<<"GPU-DEVICE(S) FOUND"<<std::endl; selectedDevice=i; //if GPU found on platform, select this platform clReady=true; //and mark CL context as available }else if(platformList.at(i).getDevices(CL_DEVICE_TYPE_CPU, &deviceList)==CL_SUCCESS){ std::cout<<"CPU-DEVICE(S) FOUND"<<std::endl; }else{ std::cout<<"UNKNOWN DEVICE(S) FOUND"<<std::endl; } std::cout<<"number of devices: "<<deviceList.size()<<std::endl; } }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<< std::endl; std::cout<<"OpenCL not ready"<<std::endl; clReady=false;//disable openCL on error } if(clReady==true){//only if CL context is available try{ cl_context_properties cprops[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)(platformList[selectedDevice])(), 0};//get context properties of selected platform context = cl::Context(CL_DEVICE_TYPE_GPU, cprops);//select GPU device devices = context.getInfo<CL_CONTEXT_DEVICES>(); std::cout<<"selected devices: "<<devices.size()<<std::endl; cl::Program::Sources sources(1, std::make_pair(pointcloudViewerKernel, 0)); //kernel source program=cl::Program(context, sources); //program (bind context and source) program.build(devices);//build program //create buffer for memory access and allocation vrOffsetBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &viewrayOffsets[0]); vrDirectionBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &viewrayDirections[0]); normsBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &norms[0]); pseudoRBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &pseudoImageRArray[0]); pseudoGBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &pseudoImageGArray[0]); pseudoBBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &pseudoImageBArray[0]); verticesBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &m_vertices[0]); vertColorsBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &m_vertexColors[0]); outNormalsBuffer = cl::Buffer( context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &pWNormals[0]); //create kernels kernelUnicolor=cl::Kernel(program, "calculateUniColor"); kernelRGBcolor=cl::Kernel(program, "calculateRGBColor"); kernelPseudocolor=cl::Kernel(program, "calculatePseudoColor"); kernelPseudodepth=cl::Kernel(program, "calculatePseudoColorDepthImage"); kernelNormalcolorCam=cl::Kernel(program, "calculateNormalDirectionColorCam"); kernelNormalcolorWorld=cl::Kernel(program, "calculateNormalDirectionColorWorld"); queue=cl::CommandQueue(context, devices[0], 0);//create command queue }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<< std::endl; clReady=false;//disable openCL on error } } #else std::cout<<"no openCL parallelization available"<<std::endl; clReady=false; #endif } PointcloudSceneObject::~PointcloudSceneObject(){ #ifdef HAVE_OPENCL delete[] rawImageArray; delete[] outputVertices; delete[] outputColors; delete[] colorImageRArray; delete[] colorImageGArray; delete[] colorImageBArray; delete[] pseudoImageRArray; delete[] pseudoImageGArray; delete[] pseudoImageBArray; #endif delete[] pWNormals; } Img8u PointcloudSceneObject::calculatePseudocolorDepthImage(const Img32f &depthImg, bool vSync){ Img8u hsvImage(s,formatRGB); if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); kernelPseudodepth.setArg(0, rawImageBuffer);//set parameter for kernel kernelPseudodepth.setArg(1, pseudoRBuffer); kernelPseudodepth.setArg(2, pseudoGBuffer); kernelPseudodepth.setArg(3, pseudoBBuffer); queue.enqueueNDRangeKernel(//run kernel kernelPseudodepth, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } queue.enqueueReadBuffer(//read output from kernel pseudoRBuffer, vS, // block 0, w*h * sizeof(cl_uchar), (cl_uchar*) pseudoImageRArray); queue.enqueueReadBuffer(//read output from kernel pseudoGBuffer, vS, // block 0, w*h * sizeof(cl_uchar), (cl_uchar*) pseudoImageGArray); queue.enqueueReadBuffer(//read output from kernel pseudoBBuffer, vS, // block 0, w*h * sizeof(cl_uchar), (cl_uchar*) pseudoImageBArray); std::vector<icl8u*> data(3); data[0] = pseudoImageRArray; data[1] = pseudoImageGArray; data[2] = pseudoImageBArray; hsvImage = Img8u(Size(w,h),3,data,false); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ for(int x=0;x<hsvImage.getWidth();++x){ for(int y=0;y<hsvImage.getHeight();++y){ float v = depthImg(x,y,0)/2048.0; v = powf(v,3)*6; int pv = v*6*256; int lb = pv & 0xff; switch (pv>>8) { case 0: hsvImage(x,y,0) = 255; hsvImage(x,y,1) = 255-lb; hsvImage(x,y,2) = 255-lb; break; case 1: hsvImage(x,y,0) = 255; hsvImage(x,y,1) = lb; hsvImage(x,y,2) = 0; break; case 2: hsvImage(x,y,0) = 255-lb; hsvImage(x,y,1) = 255; hsvImage(x,y,2) = 0; break; case 3: hsvImage(x,y,0) = 0; hsvImage(x,y,1) = 255; hsvImage(x,y,2) = lb; break; case 4: hsvImage(x,y,0) = 0; hsvImage(x,y,1) = 255-lb; hsvImage(x,y,2) = 255; break; case 5: hsvImage(x,y,0) = 0; hsvImage(x,y,1) = 0; hsvImage(x,y,2) = 255-lb; break; default: hsvImage(x,y,0) = 0; hsvImage(x,y,1) = 0; hsvImage(x,y,2) = 0; break; } } } } return hsvImage; } void PointcloudSceneObject::calculateUniColor(const Img32f &depthImg, GeomColor color, bool vSync){ if(normalLinesSet==true){ clearNormalLines(); } if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); cl_float4 vcolor; vcolor.x=color[0]/255.; vcolor.y=color[1]/255.; vcolor.z=color[2]/255.; vcolor.w=1.; kernelUnicolor.setArg(0, rawImageBuffer);//set parameter for kernel kernelUnicolor.setArg(1, vrOffsetBuffer); kernelUnicolor.setArg(2, vrDirectionBuffer); kernelUnicolor.setArg(3, normsBuffer); kernelUnicolor.setArg(4, verticesBuffer); kernelUnicolor.setArg(5, vertColorsBuffer); kernelUnicolor.setArg(6, vcolor); kernelUnicolor.setArg(7, depthScaling); queue.enqueueNDRangeKernel(//run kernel kernelUnicolor, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } queue.enqueueReadBuffer(//read output from kernel verticesBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertices.data())); queue.enqueueReadBuffer(//read output from kernel vertColorsBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertexColors.data())); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ Mutex::Locker l(mutex); const Channel32f d = depthImg[0]; const Rect r(0,0,w,h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x){ int i = x+w*y; float ds = depth_to_distance_mm(d[i]) * norms[i] * depthScaling; m_vertices[i] = rays[i](ds); if(d[i] == 2047){ m_vertexColors[i] = GeomColor(0,0,0,0); }else{ m_vertexColors[i] = color/255.; } } } } } void PointcloudSceneObject::calculateRGBColor(const Img32f &depthImg, const Img8u &colorImg, FixedMatrix<float,3,3> homogeneity, bool vSync){ if(normalLinesSet==true){ clearNormalLines(); } if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array colorImageRArray=(cl_uchar*)colorImg.begin(0);//image to char array colorImageGArray=(cl_uchar*)colorImg.begin(1);//image to char array colorImageBArray=(cl_uchar*)colorImg.begin(2);//image to char array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); colorRBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &colorImageRArray[0]); colorGBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &colorImageGArray[0]); colorBBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &colorImageBArray[0]); homogeneityBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, 9 * sizeof(float), (void *) &homogeneity[0]); kernelRGBcolor.setArg(0, rawImageBuffer);//set parameter for kernel kernelRGBcolor.setArg(1, vrOffsetBuffer); kernelRGBcolor.setArg(2, vrDirectionBuffer); kernelRGBcolor.setArg(3, normsBuffer); kernelRGBcolor.setArg(4, verticesBuffer); kernelRGBcolor.setArg(5, vertColorsBuffer); kernelRGBcolor.setArg(6, colorRBuffer); kernelRGBcolor.setArg(7, colorGBuffer); kernelRGBcolor.setArg(8, colorBBuffer); kernelRGBcolor.setArg(9, depthScaling); kernelRGBcolor.setArg(10, homogeneityBuffer); kernelRGBcolor.setArg(11, w); kernelRGBcolor.setArg(12, h); queue.enqueueNDRangeKernel(//run kernel kernelRGBcolor, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } queue.enqueueReadBuffer(//read output from kernel verticesBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertices.data())); queue.enqueueReadBuffer(//read output from kernel vertColorsBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertexColors.data())); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ H=homogeneity; Mutex::Locker l(mutex); const Channel32f d = depthImg[0]; const Channel8u c[3] = { colorImg[0], colorImg[1], colorImg[2] }; const Rect r(0,0,w,h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x){ int i = x+w*y; float ds = depth_to_distance_mm(d[i]) * norms[i] * depthScaling; m_vertices[i] = rays[i](ds); if(d[i] == 2047){ m_vertexColors[i] = GeomColor(0,0,0,0); }else{ float az = H(0,2)*x + H(1,2) * y + H(2,2); int ax = round(( H(0,0)*x + H(1,0) * y + H(2,0) ) / az); int ay = round(( H(0,1)*x + H(1,1) * y + H(2,1) ) / az); if(r.contains(ax,ay)){ m_vertexColors[i] = GeomColor(c[0](ax,ay)/255., c[1](ax,ay)/255., c[2](ax,ay)/255.,1); } } } } } } void PointcloudSceneObject::calculatePseudoColor(const Img32f &depthImg, Img8u &pseudoImg, bool vSync){ if(normalLinesSet==true){ clearNormalLines(); } if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array colorImageRArray=(cl_uchar*)pseudoImg.begin(0);//image to char array colorImageGArray=(cl_uchar*)pseudoImg.begin(1);//image to char array colorImageBArray=(cl_uchar*)pseudoImg.begin(2);//image to char array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); colorRBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &colorImageRArray[0]); colorGBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &colorImageGArray[0]); colorBBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &colorImageBArray[0]); kernelPseudocolor.setArg(0, rawImageBuffer);//set parameter for kernel kernelPseudocolor.setArg(1, vrOffsetBuffer); kernelPseudocolor.setArg(2, vrDirectionBuffer); kernelPseudocolor.setArg(3, normsBuffer); kernelPseudocolor.setArg(4, verticesBuffer); kernelPseudocolor.setArg(5, vertColorsBuffer); kernelPseudocolor.setArg(6, colorRBuffer); kernelPseudocolor.setArg(7, colorGBuffer); kernelPseudocolor.setArg(8, colorBBuffer); kernelPseudocolor.setArg(9, depthScaling); kernelPseudocolor.setArg(10, w); kernelPseudocolor.setArg(11, h); queue.enqueueNDRangeKernel(//run kernel kernelPseudocolor, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } queue.enqueueReadBuffer(//read output from kernel verticesBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertices.data())); queue.enqueueReadBuffer(//read output from kernel vertColorsBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertexColors.data())); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ Mutex::Locker l(mutex); const Channel32f d = depthImg[0]; const Channel8u c[3] = { pseudoImg[0], pseudoImg[1], pseudoImg[2] }; const Rect r(0,0,w,h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x){ int i = x+w*y; float ds = depth_to_distance_mm(d[i]) * norms[i] * depthScaling; m_vertices[i] = rays[i](ds); if(d[i] == 2047){ m_vertexColors[i] = GeomColor(0,0,0,0); }else{ m_vertexColors[i] = GeomColor(c[0](x,y)/255., c[1](x,y)/255., c[2](x,y)/255.,1); } } } } } void PointcloudSceneObject::calculatePseudoColor(const Img32f &depthImg, bool vSync){ if(normalLinesSet==true){ clearNormalLines(); } if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); pseudoRBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &pseudoImageRArray[0]); pseudoGBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &pseudoImageGArray[0]); pseudoBBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_uchar), (void *) &pseudoImageBArray[0]); kernelPseudodepth.setArg(0, rawImageBuffer);//set parameter for kernel kernelPseudodepth.setArg(1, pseudoRBuffer); kernelPseudodepth.setArg(2, pseudoGBuffer); kernelPseudodepth.setArg(3, pseudoBBuffer); queue.enqueueNDRangeKernel(//run kernel 1 kernelPseudodepth, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } kernelPseudocolor.setArg(0, rawImageBuffer);//set parameter for kernel kernelPseudocolor.setArg(1, vrOffsetBuffer); kernelPseudocolor.setArg(2, vrDirectionBuffer); kernelPseudocolor.setArg(3, normsBuffer); kernelPseudocolor.setArg(4, verticesBuffer); kernelPseudocolor.setArg(5, vertColorsBuffer); kernelPseudocolor.setArg(6, pseudoRBuffer); kernelPseudocolor.setArg(7, pseudoGBuffer); kernelPseudocolor.setArg(8, pseudoBBuffer); kernelPseudocolor.setArg(9, depthScaling); kernelPseudocolor.setArg(10, w); kernelPseudocolor.setArg(11, h); queue.enqueueNDRangeKernel(//run kernel 2 kernelPseudocolor, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); queue.enqueueReadBuffer(//read output from kernel verticesBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertices.data())); queue.enqueueReadBuffer(//read output from kernel vertColorsBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertexColors.data())); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ Mutex::Locker l(mutex); Img8u pseudoImg=calculatePseudocolorDepthImage(depthImg,vSync); const Channel32f d = depthImg[0]; const Channel8u c[3] = { pseudoImg[0], pseudoImg[1], pseudoImg[2] }; const Rect r(0,0,w,h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x){ int i = x+w*y; float ds = depth_to_distance_mm(d[i]) * norms[i] * depthScaling; m_vertices[i] = rays[i](ds); if(d[i] == 2047){ m_vertexColors[i] = GeomColor(0,0,0,0); }else{ m_vertexColors[i] = GeomColor(c[0](x,y)/255., c[1](x,y)/255., c[2](x,y)/255.,1); } } } } } void PointcloudSceneObject::calculateNormalDirectionColor(const Img32f &depthImg, PointNormalEstimation::Vec4* pNormals, bool vSync){ if(normalLinesSet==true){ clearNormalLines(); } if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); normalsBuffer = cl::Buffer( context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &pNormals[0]); kernelNormalcolorCam.setArg(0, rawImageBuffer);//set parameter for kernel kernelNormalcolorCam.setArg(1, vrOffsetBuffer); kernelNormalcolorCam.setArg(2, vrDirectionBuffer); kernelNormalcolorCam.setArg(3, normsBuffer); kernelNormalcolorCam.setArg(4, verticesBuffer); kernelNormalcolorCam.setArg(5, vertColorsBuffer); kernelNormalcolorCam.setArg(6, normalsBuffer); kernelNormalcolorCam.setArg(7, depthScaling); queue.enqueueNDRangeKernel(//run kernel kernelNormalcolorCam, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } if(useNormalLines==true){//No vSync if normal lines are shown vS=CL_TRUE; } queue.enqueueReadBuffer(//read output from kernel verticesBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertices.data())); queue.enqueueReadBuffer(//read output from kernel vertColorsBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertexColors.data())); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ Mutex::Locker l(mutex); const Channel32f d = depthImg[0]; const Rect r(0,0,w,h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x){ int i = x+w*y; float ds = depth_to_distance_mm(d[i]) * norms[i] * depthScaling; m_vertices[i] = rays[i](ds); if(d[i] == 2047){ m_vertexColors[i] = GeomColor(0,0,0,0); }else{ float cx=fabs(pNormals[i].x); float cy=fabs(pNormals[i].y); float cz=fabs(pNormals[i].z); m_vertexColors[i] = GeomColor(cx, cy, cz,1.); } } } } if(useNormalLines==true){ drawNormalLines(pNormals); } } void PointcloudSceneObject::calculateNormalDirectionColor(const Img32f &depthImg, PointNormalEstimation::Vec4* pNormals, Camera cam, bool vSync){ if(normalLinesSet==true){ clearNormalLines(); } Mat T = cam.getCSTransformationMatrix(); FixedMatrix<float,3,3> R = T.part<0,0,3,3>(); Mat T2 = R.transp().resize<4,4>(0); T2(3,3) =1; if(useCL==true && clReady==true){ #ifdef HAVE_OPENCL try{ rawImageArray=(float*)depthImg.begin(0);//image to float array rawImageBuffer = cl::Buffer(//write new image to buffer context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(float), (void *) &rawImageArray[0]); normalsBuffer = cl::Buffer( context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, w*h * sizeof(cl_float4), (void *) &pNormals[0]); camBuffer = cl::Buffer( context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, 16 * sizeof(float), (void *) &T2[0]); kernelNormalcolorWorld.setArg(0, rawImageBuffer);//set parameter for kernel kernelNormalcolorWorld.setArg(1, vrOffsetBuffer); kernelNormalcolorWorld.setArg(2, vrDirectionBuffer); kernelNormalcolorWorld.setArg(3, normsBuffer); kernelNormalcolorWorld.setArg(4, verticesBuffer); kernelNormalcolorWorld.setArg(5, vertColorsBuffer); kernelNormalcolorWorld.setArg(6, normalsBuffer); kernelNormalcolorWorld.setArg(7, depthScaling); kernelNormalcolorWorld.setArg(8, camBuffer); kernelNormalcolorWorld.setArg(9, outNormalsBuffer); queue.enqueueNDRangeKernel(//run kernel kernelNormalcolorWorld, cl::NullRange, cl::NDRange(w*h), //input size for get global id cl::NullRange); cl_bool vS=CL_TRUE; //default: blocking (use after complete read) if(vSync==true){ vS=CL_FALSE; //if vSync is activated: no block (read if needed, faster but incomplete update) } if(useNormalLines==true){//No vSync if normal lines are shown vS=CL_TRUE; } queue.enqueueReadBuffer(//read output from kernel verticesBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertices.data())); queue.enqueueReadBuffer(//read output from kernel vertColorsBuffer, vS, 0, w*h * sizeof(cl_float4), reinterpret_cast<cl_float4*>(m_vertexColors.data())); queue.enqueueReadBuffer(//read output from kernel outNormalsBuffer, CL_TRUE, // block 0, w*h * sizeof(cl_float4), (cl_float4*) pWNormals); }catch (cl::Error err) {//catch openCL errors std::cout<< "ERROR: "<< err.what()<< "("<< err.err()<< ")"<<std::endl; } #endif } else{ Mutex::Locker l(mutex); const Channel32f d = depthImg[0]; const Rect r(0,0,w,h); for(int y=0;y<h;++y){ for(int x=0;x<w;++x){ int i = x+w*y; float ds = depth_to_distance_mm(d[i]) * norms[i] * depthScaling; m_vertices[i] = rays[i](ds); if(d[i] == 2047){ m_vertexColors[i] = GeomColor(0,0,0,0); }else{ Vec pWN = T2*(Vec&)pNormals[i]; pWNormals[i].x=-pWN[0]; pWNormals[i].y=-pWN[1]; pWNormals[i].z=-pWN[2]; pWNormals[i].w=1.; float cx=fabs(pWN[0]); float cy=fabs(pWN[1]); float cz=fabs(pWN[2]); m_vertexColors[i] = GeomColor(cx, cy, cz,1.); } } } } if(useNormalLines==true){ drawNormalLines(pWNormals); } } void PointcloudSceneObject::setDepthScaling(float scaling){ depthScaling=scaling; } float PointcloudSceneObject::depth_to_distance_mm(int d){ return 1.046 * (d==2047 ? 0 : 1000. / (d * -0.0030711016 + 3.3309495161)); /* what is this? const float k1 = 1.1863; const float k2 = 2842.5; const float k3 = 0.1236; return k3 * tanf(d/k2 + k1); */ } float PointcloudSceneObject::sprod(const Vec &a,const Vec &b){ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } float PointcloudSceneObject::getNormFactor(const ViewRay &a, const ViewRay &b){ return sprod(a.direction,b.direction)/(norm3(a.direction)*norm3(b.direction)); } void PointcloudSceneObject::create_view_rays(int w, int h, const Camera &cam){ rays.resize(w*h); Mat T = cam.getCSTransformationMatrix(); Mat P = cam.getProjectionMatrix(); Mat M = P*T; FixedMatrix<icl32f,4,3> Q; Q.row(0) = M.row(0); Q.row(1) = M.row(1); Q.row(2) = M.row(3); FixedMatrix<icl32f,3,4> Qpinv = Q.pinv(); const Vec pos = cam.getPosition(); int i=0; if((pos[0]*pos[0] + pos[1]*pos[1] + pos[2]*pos[2]) < 1e-20){ for(int y=0;y<h;++y){ for(int x=0;x<w;++x,++i){ ViewRay &v = rays[i]; v.offset = pos; v.direction = Qpinv*FixedColVector<icl32f,3>(x, y, 1); v.direction[3] = 0; v.direction.normalize(); v.direction *= -1; v.direction[3] = 1; } } }else{ for(int y=0;y<h;++y){ for(int x=0;x<w;++x,++i){ ViewRay &v = rays[i]; v.offset = pos; v.direction = Qpinv*FixedColVector<icl32f,3>(x, y, 1); v.direction = pos - homogenize(v.direction); v.direction[3] = 0; v.direction.normalize(); v.direction *= -1; v.direction[3] = 1; } } } } void PointcloudSceneObject::setUseCL(bool use){ useCL=use; } bool PointcloudSceneObject::isCLReady(){ return clReady; } bool PointcloudSceneObject::isCLActive(){ return useCL; } void PointcloudSceneObject::setUseDrawNormalLines(bool use){ useNormalLines=use; } void PointcloudSceneObject::drawNormalLines(PointNormalEstimation::Vec4* pNormals){ for(int y=0; y<h; y+=normalLinesGranularity){ for(int x=0; x<w; x+=normalLinesGranularity){ int i=x+w*y; if(m_vertexColors.at(i)[3]!=0){ Vec point(m_vertices.at(i)[0]+normalLinesLength*pNormals[i].x, m_vertices.at(i)[1]+normalLinesLength*pNormals[i].y, m_vertices.at(i)[2]+normalLinesLength*pNormals[i].z, 1); addVertex(point, geom_white()); addLine(m_vertices.size()-1, i, geom_white()); } } } normalLinesSet=true; } void PointcloudSceneObject::clearNormalLines(){ m_vertices.resize(w*h); m_vertexColors.resize(w*h); clearAllPrimitives(); normalLinesSet=false; } void PointcloudSceneObject::setNormalLinesLength(float length){ normalLinesLength=length; } void PointcloudSceneObject::setNormalLinesGranularity(int granularity){ normalLinesGranularity=granularity; } PointNormalEstimation::Vec4* PointcloudSceneObject::getWorldNormals(){ return pWNormals; } }