From 0b98dceb5a1c03edf1bb640b97fc864bd970f263 Mon Sep 17 00:00:00 2001 From: Marco Callieri mcallieri Date: Fri, 24 Jun 2011 12:13:42 +0000 Subject: [PATCH] first working version of the project-to-texture filter --- .../filter_color_projection.cpp | 351 +++++++++++++++++- .../filter_color_projection.h | 2 +- .../filter_color_projection.pro | 5 +- .../filter_color_projection/floatbuffer.h | 132 +++---- .../filter_color_projection/pushpull.h | 149 ++++++++ .../filter_color_projection/rastering.h | 212 +++++++++++ 6 files changed, 780 insertions(+), 71 deletions(-) create mode 100644 src/meshlabplugins/filter_color_projection/pushpull.h create mode 100644 src/meshlabplugins/filter_color_projection/rastering.h diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp index 16125cbc6..16ddbfbcf 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp @@ -34,15 +34,31 @@ #include "render_helper.cpp" +#include "pushpull.h" +#include "rastering.h" +#include + using namespace std; using namespace vcg; +// utility--------------------------------- + +#define CheckError(x,y); if ((x)) {this->errorMessage = (y); return false;} + +static QString extractFilenameWOExt(MeshModel* mm) +{ + QFileInfo fi(mm->fullName()); + return fi.baseName(); +} +//----------------------------------------- + // Constructor FilterColorProjectionPlugin::FilterColorProjectionPlugin() { typeList << FP_SINGLEIMAGEPROJ - << FP_MULTIIMAGETRIVIALPROJ; + << FP_MULTIIMAGETRIVIALPROJ + << FP_MULTIIMAGETRIVIALPROJTEXTURE; foreach(FilterIDType tt , types()) actionList << new QAction(filterName(tt), this); @@ -54,6 +70,7 @@ QString FilterColorProjectionPlugin::filterName(FilterIDType filterId) const switch(filterId) { case FP_SINGLEIMAGEPROJ : return QString("Project current raster color to current mesh"); case FP_MULTIIMAGETRIVIALPROJ : return QString("Project active rasters color to current mesh"); + case FP_MULTIIMAGETRIVIALPROJTEXTURE : return QString("Project active rasters color to current mesh, filling the texture"); default : assert(0); } } @@ -64,6 +81,7 @@ QString FilterColorProjectionPlugin::filterName(FilterIDType filterId) const switch(filterId) { case FP_SINGLEIMAGEPROJ : return QString("Color information from the current raster is perspective-projected on the current mesh"); case FP_MULTIIMAGETRIVIALPROJ : return QString("Color information from all the active rasters is perspective-projected on the current mesh using basic weighting"); + case FP_MULTIIMAGETRIVIALPROJTEXTURE : return QString("Color information from all the active rasters is perspective-projected on the current mesh, filling the texture, using basic weighting"); default : assert(0); } } @@ -73,6 +91,7 @@ int FilterColorProjectionPlugin::getRequirements(QAction *action){ switch(ID(action)){ case FP_SINGLEIMAGEPROJ: return MeshModel::MM_VERTCOLOR; case FP_MULTIIMAGETRIVIALPROJ: return MeshModel::MM_VERTCOLOR; + case FP_MULTIIMAGETRIVIALPROJTEXTURE : return 0; default: assert(0); return 0; } return 0; @@ -132,6 +151,45 @@ void FilterColorProjectionPlugin::initParameterSet(QAction *action, MeshDocument } break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE : + { + QString fileName = extractFilenameWOExt(md.mm()); + fileName = fileName.append("_color.png"); + parlst.addParam(new RichString("textName", + fileName, + "Texture file", + "The texture file to be created")); + parlst.addParam(new RichInt ("texsize", + 1024, + "pixel size of texture image", + "pixel size of texture image, the image will be a square tsize X tsize, most applications do require that tsize is a power of 2")); + parlst.addParam(new RichFloat ("deptheta", + 0.5, + "depth threshold", + "threshold value for depth buffer projection (shadow buffer)")); + parlst.addParam(new RichBool ("onselection", + false, + "Only on selecton", + "If true, projection is only done for selected vertices")); + parlst.addParam(new RichBool ("useangle", + true, + "use angle weight", + "If true, color contribution is weighted by pixel view angle")); + parlst.addParam(new RichBool ("usedistance", + true, + "use distance weight", + "If true, color contribution is weighted by pixel view distance")); + parlst.addParam(new RichBool ("useborders", + true, + "use image borders weight", + "If true, color contribution is weighted by pixel distance from image boundaries")); + parlst.addParam(new RichBool ("usesilhouettes", + true, + "use depth discontinuities weight", + "If true, color contribution is weighted by pixel distance from depth discontinuities (external and internal silhouettes)")); + } + break; + default: break; // do not add any parameter for the other filters } } @@ -300,7 +358,7 @@ bool FilterColorProjectionPlugin::applyFilter(QAction *filter, MeshDocument &md, allcammaximagesize = imgdiag; } - //-- cycle all cmaeras + //-- cycle all cameras cam_ind = 0; foreach(RasterModel *raster, md.rasterList) { @@ -470,6 +528,289 @@ bool FilterColorProjectionPlugin::applyFilter(QAction *filter, MeshDocument &md, } break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE : + { + bool onselection = par.getBool("onselection"); + int texsize = par.getInt("texsize"); + float eta = par.getFloat("deptheta"); + bool useangle = par.getBool("useangle"); + bool usedistance = par.getBool("usedistance"); + bool useborders = par.getBool("useborders"); + bool usesilhouettes = par.getBool("usesilhouettes"); + QString textName = par.getString("textName"); + + int textW = texsize; + int textH = texsize; + + Point2f pp; // projected point + float depth=0; // depth of point (distance from camera) + float pdepth=0; // depth value of projected point (from depth map) + double pweight; // pixel weight + MeshModel *model; + bool do_project; + int cam_ind; + int texcount = 0; // current texel index + + // min max depth for depth weight normalization + float allcammaxdepth; + float allcammindepth; + + // max image size for border weight normalization + float allcammaximagesize; + + // get the working model + model = md.mm(); + + // the mesh has to be correctly transformed before mapping + tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); + tri::UpdateBounding::Box(model->cm); + + // texture file name + QString filePath(model->fullName()); + filePath = filePath.left(std::max(filePath.lastIndexOf('\\'),filePath.lastIndexOf('/'))+1); + // Check textName and eventually add .png ext + CheckError(textName.length() == 0, "Texture file not specified"); + CheckError(std::max(textName.lastIndexOf("\\"),textName.lastIndexOf("/")) != -1, "Path in Texture file not allowed"); + if (!textName.endsWith(".png", Qt::CaseInsensitive)) + textName.append(".png"); + filePath.append(textName); + + // Image creation + CheckError(textW <= 0, "Texture Width has an incorrect value"); + CheckError(textH <= 0, "Texture Height has an incorrect value"); + QImage img(QSize(textW,textH), QImage::Format_ARGB32); + img.fill(qRgba(0,0,0,0)); // transparent black + + // Compute (texture-space) border edges + model->updateDataMask(MeshModel::MM_FACEFACETOPO); + //tri::UpdateTopology::FaceFace(model->cm); + tri::UpdateTopology::FaceFaceFromTexCoord(model->cm); + tri::UpdateFlags::FaceBorderFromFF(model->cm); + + // create a list of to-be-filled texels and accumulators + // storing texel 2d coords, texel mesh-space point, texel mesh normal + + vector texels; + texels.clear(); + texels.reserve(textW*textH); // just to avoid the 2x reallocate rule... + + vector accums; + accums.clear(); + accums.reserve(textW*textH); // just to avoid the 2x reallocate rule... + + // Rasterizing triangles in the list of voxels + TexFillerSampler tfs(img); + tfs.texelspointer = &texels; + tfs.accumpointer = &accums; + tfs.InitCallback(cb, model->cm.fn, 0, 80); + tri::SurfaceSampling::Texture(model->cm,tfs,textW,textH,true); + + // Revert alpha values for border edge pixels to 255 + cb(81, "Cleaning up texture ..."); + for (int y=0; y 0) + img.setPixel(x,y, px | 0xff000000); + } + + // calculate accuratenear/far for all cameras + std::vector my_near; + std::vector my_far; + calculateNearFarAccurate(md, &my_near, &my_far); + + allcammaxdepth = -1000000; + allcammindepth = 1000000; + allcammaximagesize = -1000000; + for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) + { + if(my_far[cam_ind] > allcammaxdepth) + allcammaxdepth = my_far[cam_ind]; + if(my_near[cam_ind] < allcammindepth) + allcammindepth = my_near[cam_ind]; + + float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); + if (imgdiag > allcammaximagesize) + allcammaximagesize = imgdiag; + } + + //-- cycle all cameras + cam_ind = 0; + foreach(RasterModel *raster, md.rasterList) + { + do_project = true; + + // no drawing if camera not valid + if(!raster->shot.IsValid()) + do_project = false; + + // no drawing if raster is not active + //if(!raster->shot.IsValid()) + // do_project = false; + + if(do_project) + { + // delete & reinit rendermanager + if(rendermanager != NULL) + delete rendermanager; + rendermanager = new RenderHelper(); + if( rendermanager->initializeGL(cb) != 0 ) + return false; + Log("init GL"); + if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + return false; + Log("init Buffers"); + + // render normal & depth + rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, my_near[cam_ind]*0.99, my_far[cam_ind]*1.01); + + // If should be used silhouette weighting, it is needed to compute depth discontinuities + // and per-pixel distance from detected borders on the entire image here + // the weight is then applied later, per-vertex, when needed + floatbuffer *silhouette_buff=NULL; + float maxsildist = rendermanager->depth->sx + rendermanager->depth->sy; + if(usesilhouettes) + { + silhouette_buff = new floatbuffer(); + silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); + + silhouette_buff->applysobel(rendermanager->depth); + //sprintf(dumpFileName,"Abord%i.bmp",cam_ind); + //silhouette_buff->dumpbmp(dumpFileName); + + silhouette_buff->initborder(rendermanager->depth); + //sprintf(dumpFileName,"Bbord%i.bmp",cam_ind); + //silhouette_buff->dumpbmp(dumpFileName); + + maxsildist = silhouette_buff->distancefield(); + //sprintf(dumpFileName,"Cbord%i.bmp",cam_ind); + //silhouette_buff->dumpbmp(dumpFileName); + } + + for(texcount=0; texcount < texels.size(); texcount++) + { + pp = raster->shot.Project(texels[texcount].meshpoint); + + //if inside image + if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) + { + + depth = raster->shot.Depth(texels[texcount].meshpoint); + pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; + + if(depth <= (pdepth + eta)) + { + // determine color + QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); + // determine weight + pweight = 1.0; + + if(useangle) + { + Point3f pixnorm; + Point3f viewaxis; + + pixnorm = texels[texcount].meshnormal; + pixnorm.Normalize(); + + viewaxis = raster->shot.GetViewPoint() - texels[texcount].meshpoint; + viewaxis.Normalize(); + + float ang = abs(pixnorm * viewaxis); + ang = min(1.0f, ang); + + pweight *= ang; + } + + if(usedistance) + { + float distw = depth; + distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); + + pweight *= distw; + pweight *= distw; + } + + if(useborders) + { + double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); + double ydist = 1.0 - (abs(pp[1] - (raster->shot.Intrinsics.ViewportPx[1] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[1] / 2.0)); + double borderw = min (xdist , ydist); + + pweight *= borderw; + } + + if(usesilhouettes) + { + // here the silhouette weight is applied, but it is calculated before, on a per-image basis + float silw = 1.0; + silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; + pweight *= silw; + } + + accums[texcount].weights += pweight; + accums[texcount].acc_red += (qRed(pcolor) * pweight / 255.0); + accums[texcount].acc_grn += (qGreen(pcolor) * pweight / 255.0); + accums[texcount].acc_blu += (qBlue(pcolor) * pweight / 255.0); + } + } + + } // end foreach texel + cam_ind ++; + + if(usesilhouettes) + { + delete silhouette_buff; + } + + } // end if(do_project) + + } // end foreach camera + + // for each texel.... divide accumulated values by weight and write to texture + for(texcount=0; texcount < texels.size(); texcount++) + { + float texel_red = 1.0; + float texel_green = 1.0; + float texel_blue = 1.0; + + if(accums[texcount].weights > 0.0) + { + texel_red = accums[texcount].acc_red / accums[texcount].weights; + texel_green = accums[texcount].acc_grn / accums[texcount].weights; + texel_blue = accums[texcount].acc_blu / accums[texcount].weights; + } + + img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(texel_red*255.0, texel_green*255.0, texel_blue*255.0, 255)); + } + + // PullPush + cb(85, "Filling texture holes..."); + PullPush(img, qRgba(0,0,0,0)); + + + // Undo topology changes + tri::UpdateTopology::FaceFace(model->cm); + tri::UpdateFlags::FaceBorderFromFF(model->cm); + + // Save texture + cb(90, "Saving texture ..."); + CheckError(!img.save(filePath), "Texture file cannot be saved"); + Log( "Texture \"%s\" Created", filePath.toStdString().c_str()); + assert(QFile(filePath).exists()); + + // Assign texture + model->cm.textures.clear(); + model->cm.textures.push_back(textName.toStdString()); + + // the mesh has to return to its original position + tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); + tri::UpdateBounding::Box(model->cm); + + + } break; + } @@ -485,6 +826,9 @@ FilterColorProjectionPlugin::FilterClass FilterColorProjectionPlugin::getClass(Q case FP_MULTIIMAGETRIVIALPROJ: return FilterClass(Camera + VertexColoring); break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE: + return FilterClass(Camera + Texture); + break; default : assert(0); return MeshFilterInterface::Generic; } @@ -498,6 +842,9 @@ int FilterColorProjectionPlugin::postCondition( QAction* a ) const{ case FP_MULTIIMAGETRIVIALPROJ: return MeshModel::MM_VERTCOLOR; break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE: + return MeshModel::MM_UNKNOWN; + break; default: assert(0); return MeshModel::MM_NONE; } diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.h b/src/meshlabplugins/filter_color_projection/filter_color_projection.h index d6c06353d..f535ec58d 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.h +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.h @@ -33,7 +33,7 @@ class FilterColorProjectionPlugin : public QObject, public MeshFilterInterface Q_INTERFACES(MeshFilterInterface) public: - enum { FP_SINGLEIMAGEPROJ, FP_MULTIIMAGETRIVIALPROJ }; + enum { FP_SINGLEIMAGEPROJ, FP_MULTIIMAGETRIVIALPROJ, FP_MULTIIMAGETRIVIALPROJTEXTURE }; FilterColorProjectionPlugin(); diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.pro b/src/meshlabplugins/filter_color_projection/filter_color_projection.pro index 388cfe10f..f830f1876 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.pro +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.pro @@ -1,11 +1,12 @@ include (../../shared.pri) SOURCES = filter_color_projection.cpp\ - render_helper.cpp\ - floatbuffer.cpp\ + HEADERS = filter_color_projection.h\ render_helper.h\ floatbuffer.h\ + pushpull.h \ + rastering.h \ TARGET = filter_color_projection diff --git a/src/meshlabplugins/filter_color_projection/floatbuffer.h b/src/meshlabplugins/filter_color_projection/floatbuffer.h index 53f9bd596..6b575ca5a 100644 --- a/src/meshlabplugins/filter_color_projection/floatbuffer.h +++ b/src/meshlabplugins/filter_color_projection/floatbuffer.h @@ -19,21 +19,21 @@ * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * -****************************************************************************/ -#ifndef FLOATBUFFER_H -#define FLOATBUFFER_H - -#include -#include - -#include -#include +****************************************************************************/ +#ifndef FLOATBUFFER_H +#define FLOATBUFFER_H + +#include +#include + +#include +#include #include - -using namespace std; -using namespace vcg; - -//---------------------------------- BMP headers for cross platform compilation + +using namespace std; +using namespace vcg; + +//---------------------------------- BMP headers for cross platform compilation /* Note: the magic number has been removed from the bmpfile_header structure since it causes alignment problems @@ -71,56 +71,56 @@ typedef struct { uint32_t ncolors; uint32_t nimpcolors; } BITMAPINFOHEADER_X; - -//------------------------------------------------------------------------------ - -class colorp -{ - public: - - float r; - float g; - float b; - - float w; - int im; -}; - -class floatbuffer -{ - public: - - float* data; - - int sx,sy; - - int loaded; // -1 not created - // 1 loaded - // 0 unloaded - - QString filename; // when unloaded, offcore filename - - floatbuffer(void); - floatbuffer(floatbuffer *from); - ~floatbuffer(void); - - int init(int sizex, int sizey); - int destroy(); - - float getval(int xx, int yy); - int setval(int xx, int yy, float val); - - int fillwith(float val); - - int applysobel(floatbuffer *from); - int initborder(floatbuffer* zerofrom); - int distancefield(); - - int dump(QString filename); - int dumpbmp(QString filename, bool asitis = false); - int dumpbmp2(QString filename); - int dumppfm(QString filename); -}; - - + +//------------------------------------------------------------------------------ + +class colorp +{ + public: + + float r; + float g; + float b; + + float w; + int im; +}; + +class floatbuffer +{ + public: + + float* data; + + int sx,sy; + + int loaded; // -1 not created + // 1 loaded + // 0 unloaded + + QString filename; // when unloaded, offcore filename + + floatbuffer(void); + floatbuffer(floatbuffer *from); + ~floatbuffer(void); + + int init(int sizex, int sizey); + int destroy(); + + float getval(int xx, int yy); + int setval(int xx, int yy, float val); + + int fillwith(float val); + + int applysobel(floatbuffer *from); + int initborder(floatbuffer* zerofrom); + int distancefield(); + + int dump(QString filename); + int dumpbmp(QString filename, bool asitis = false); + int dumpbmp2(QString filename); + int dumppfm(QString filename); +}; + + #endif // FLOATBUFFER_H \ No newline at end of file diff --git a/src/meshlabplugins/filter_color_projection/pushpull.h b/src/meshlabplugins/filter_color_projection/pushpull.h new file mode 100644 index 000000000..0fa81a84f --- /dev/null +++ b/src/meshlabplugins/filter_color_projection/pushpull.h @@ -0,0 +1,149 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* 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 program 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 (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef _PUSHPULL_H +#define _PUSHPULL_H + +typedef unsigned char byte; + +#include + +namespace vcg +{ + /* pull push filling algorithm */ + + int mean4w(int p1,byte w1,int p2,byte w2,int p3,byte w3,int p4,byte w4) + { + int result =(p1*int(w1) + p2*int(w2) +p3*int(w3) + p4*int(w4) ) + / ( int(w1)+int(w2)+int(w3)+int(w4) ) ; + return result; + } + + QRgb mean4Pixelw(QRgb p1,byte w1,QRgb p2,byte w2,QRgb p3,byte w3,QRgb p4,byte w4) + { + int r= mean4w(qRed(p1),w1,qRed(p2),w2,qRed(p3),w3,qRed(p4),w4); + int g= mean4w(qGreen(p1),w1,qGreen(p2),w2,qGreen(p3),w3,qGreen(p4),w4); + int b= mean4w(qBlue(p1),w1,qBlue(p2),w2,qBlue(p3),w3,qBlue(p4),w4); + int a= mean4w(qAlpha(p1),w1,qAlpha(p2),w2,qAlpha(p3),w3,qAlpha(p4),w4); + + return qRgba(r,g,b,a); + + } + + // Genera una mipmap pesata + void PullPushMip( QImage & p, QImage & mip, QRgb bkcolor ) + { + assert(p.width()/2==mip.width()); + assert(p.height()/2==mip.height()); + byte w1,w2,w3,w4; + int x,y; + for(y=0;y0 ) + mip.setPixel(x, y, mean4Pixelw( + p.pixel(x*2 ,y*2 ),w1, + p.pixel(x*2+1,y*2 ),w2, + p.pixel(x*2 ,y*2+1),w3, + p.pixel(x*2+1,y*2+1),w4 )); + } + } + + // interpola a partire da una mipmap + void PullPushFill( QImage & p, QImage & mip, QRgb bkg ) + { + assert(p.width()/2==mip.width()); + assert(p.height()/2==mip.height()); + // byte w1,w2,w3,w4; + int x,y; + for(y=0;y0 ? mip.pixel(x-1,y ) : bkg), (x>0 ? byte( 48) : 0), + (y>0 ? mip.pixel(x ,y-1) : bkg), (y>0 ? byte( 48) : 0), + ((x>0 && y>0 )? mip.pixel(x-1,y-1) : bkg), ((x>0 && y>0 )? byte( 16) : 0))); + if(p.pixel(x*2+1,y*2 )==bkg) + p.setPixel(x*2+1,y*2 ,mean4Pixelw(mip.pixel(x ,y ) ,byte(144), + (x0 ? mip.pixel(x ,y-1) : bkg), (y>0 ? byte( 48) : 0), + ((x0) ? mip.pixel(x+1,y-1) : bkg), ((x0) ? byte( 16) : 0))); + if(p.pixel(x*2 ,y*2+1)==bkg) + p.setPixel(x*2 ,y*2+1, mean4Pixelw( mip.pixel(x ,y ), byte(144), + (x>0 ? mip.pixel(x-1,y ) : bkg), (x>0 ? byte( 48) : 0), + (y0 && y0 && y mip(16); + int div=2; + int miplev=0; + + // pull phase create the mipmap + while(1){ + mip[miplev]= QImage(p.width()/div,p.height()/div,p.format()); + mip[miplev].fill(bkcolor); + div*=2; + if(miplev>0) PullPushMip(mip[miplev-1],mip[miplev],bkcolor); + else PullPushMip(p,mip[miplev],bkcolor); + if(mip[miplev].width()<=4 || mip[miplev].height()<=4) break; + ++miplev; + } + miplev++; +#ifdef _PUSHPULL_DEBUG + for(int k=0;k=0;--i){ + if(i>0) PullPushFill(mip[i-1],mip[i],bkcolor); + else PullPushFill(p,mip[i],bkcolor); + } + +#ifdef _PUSHPULL_DEBUG + for(k=0;k +#include +#include +#include + + +// texel descriptor--------------------------------- + +typedef struct{ + + Point2i texcoord; + + Point3f meshpoint; + Point3f meshnormal; + +} TexelDesc; + +typedef struct{ + + float weights; + float acc_red; + float acc_grn; + float acc_blu; + +} TexelAccum; + + +//-------------------------------------------------- + +//----------- TEXTURE FILLING SAMPLER ------------------------------ +/* +class TexFillSampler +{ + public: + TexFillSampler(CMeshO* _m){m=_m; uvSpaceFlag = false; qualitySampling=false; tex=0;}; + CMeshO *m; + QImage* tex; + int texSamplingWidth; + int texSamplingHeight; + bool uvSpaceFlag; + bool qualitySampling; + texwork *thiswork; + + void AddVert(const MyMesh::VertexType &p) + { + } + + void AddFace(const MyMesh::FaceType &f, MyMesh::CoordType p) + { + } + + void AddTextureSample(const MyMesh::FaceType &f, const MyMesh::CoordType &p, const Point2i &tp, float edgeDist=0) + { + double rr,gg,bb; + double count; + QColor col; + float weight; + Point2f ppoint; + Point3f pray; + float dpt,ref; + + Point3f meshpoint = f.P(0)*p[0] + f.P(1)*p[1] +f.P(2)*p[2]; + Point3f meshnorm = f.V(0)->N()*p[0] + f.V(1)->N()*p[1] +f.V(2)->N()*p[2]; + + rr = gg = bb = 0; + count = 0; + for(int camit=0; camitcamnum; camit++) + { + ppoint = thiswork->immagini[camit].imshot->Project(meshpoint); + // pray is the vector from the point-to-be-colored to the camera center + pray = (thiswork->immagini[camit].imshot->Extrinsics.Tra() - meshpoint).Normalize(); + + + if((ppoint[0] > 0) && (ppoint[0] < thiswork->immagini[camit].imshot->Intrinsics.ViewportPx.X()) && + (ppoint[1] > 0) && (ppoint[1] < thiswork->immagini[camit].imshot->Intrinsics.ViewportPx.Y())) + if((meshnorm.dot(-thiswork->immagini[camit].imshot->Axis(2))) <= 0.0) + if((pray.dot(-thiswork->immagini[camit].imshot->Axis(2))) <= 0.0) + { + + dpt = (thiswork->immagini[camit].imshot->Depth(meshpoint) - thiswork->depth_eta); + ref = thiswork->immagini[camit].camdepth.getval(ppoint[0],ppoint[1]); + + if(dpt < ref) + { + weight = thiswork->immagini[camit].camweight.getval(ppoint[0],ppoint[1]); + ppoint[1] = thiswork->immagini[camit].imshot->Intrinsics.ViewportPx.Y() - ppoint[1]; + col = thiswork->immagini[camit].impicture->pixel(ppoint[0],ppoint[1]); + + if((col.red() + col.green() + col.blue()) > 0) + { + rr += col.red()*weight; gg += col.green()*weight; bb += col.blue()*weight; + count += weight; + } + } + } + } + + if(count > 0) + { + rr = (double)rr/count; + gg = (double)gg/count; + bb = (double)bb/count; + + // updating color mean + if(thiswork->usemean) + { + thiswork->meanrr = (thiswork->meanrr * 10.0 + rr) / 11.0; + thiswork->meangg = (thiswork->meangg * 10.0 + gg) / 11.0; + thiswork->meanbb = (thiswork->meanbb * 10.0 + bb) / 11.0; + } + } + else // default color + { + rr = thiswork->meanrr; + gg = thiswork->meangg; + bb = thiswork->meanbb; + } + +//-------------------------- + + tex->setPixel(tp[0], texSamplingHeight - tp[1], qRgb(rr,gg,bb)); + + + + } +}; // end class TexFillSampler +//------------------------------------------------------------------ + +*/ + + +class TexFillerSampler +{ +public: + + QImage &trgImg; + + vector *texelspointer; // list of active texels to be filled + vector *accumpointer; // list of color + weight accumulators + + // Callback stuff + vcg::CallBackPos *cb; + const CMeshO::FaceType *currFace; + int faceNo, faceCnt, start, offset; + + + TexFillerSampler(QImage &_img) : trgImg(_img) {} + + void InitCallback(vcg::CallBackPos *_cb, int _faceNo, int _start=0, int _offset=100) + { + assert(_faceNo > 0); + assert(_start>=0); + assert(_offset>=0 && _offset <= 100-_start); + cb = _cb; + faceNo = _faceNo; + faceCnt = 0; + start = _start; + offset = _offset; + currFace = NULL; + } + + // expects points outside face (affecting face color) with edge distance > 0 + void AddTextureSample(const CMeshO::FaceType &f, const CMeshO::CoordType &p, const vcg::Point2i &tp, float edgeDist= 0.0) + { + Point3f meshpoint = f.P(0)*p[0] + f.P(1)*p[1] +f.P(2)*p[2]; + Point3f meshnorm = (f.V(0)->N()*p[0] + f.V(1)->N()*p[1] + f.V(2)->N()*p[2]).Normalize(); + + TexelDesc newtexel; + newtexel.texcoord = tp; + newtexel.meshpoint = meshpoint; + newtexel.meshnormal = meshnorm; + + TexelAccum newaccum; + newaccum.weights = 0.0; + newaccum.acc_red = 0.0; + newaccum.acc_grn = 0.0; + newaccum.acc_blu = 0.0; + + texelspointer->push_back(newtexel); + accumpointer->push_back(newaccum); + } +}; // end class TexFillerSampler + + + +#endif