From b2277c74d4cbbbdecdf08458e96a90cc21dd1f8a Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Tue, 9 Nov 2021 17:37:37 +0100 Subject: [PATCH] filter mutualinfo, mutualglobal and colorproj python rename --- .../filter_color_projection.cpp | 1674 +++++++++-------- .../filter_color_projection.h | 2 +- .../filter_mutualglobal.cpp | 21 +- .../filter_mutualglobal/filter_mutualglobal.h | 3 +- .../filter_mutualinfo/filter_mutualinfo.cpp | 17 +- .../filter_mutualinfo/filter_mutualinfo.h | 2 +- 6 files changed, 919 insertions(+), 800 deletions(-) diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp index f7863a295..35323b5b2 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp @@ -1,25 +1,25 @@ /**************************************************************************** -* 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. * -* * -****************************************************************************/ + * 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. * + * * + ****************************************************************************/ #include @@ -39,870 +39,984 @@ #include "rastering.h" #include - using namespace std; using namespace vcg; // utility--------------------------------- -#define CheckError(x,y); if ((x)) {throw MLException((y));} +#define CheckError(x, y) \ + ; \ + if ((x)) { \ + throw MLException((y)); \ + } static QString extractFilenameWOExt(const MeshModel* mm) { - QFileInfo fi(mm->fullName()); - return fi.baseName(); + QFileInfo fi(mm->fullName()); + return fi.baseName(); } //----------------------------------------- // Constructor FilterColorProjectionPlugin::FilterColorProjectionPlugin() { - typeList = { - FP_SINGLEIMAGEPROJ, - FP_MULTIIMAGETRIVIALPROJ, - FP_MULTIIMAGETRIVIALPROJTEXTURE - }; + typeList = {FP_SINGLEIMAGEPROJ, FP_MULTIIMAGETRIVIALPROJ, FP_MULTIIMAGETRIVIALPROJTEXTURE}; - for(ActionIDType tt : types()) + for (ActionIDType tt : types()) actionList.push_back(new QAction(filterName(tt), this)); } QString FilterColorProjectionPlugin::pluginName() const { - return "FilterColorProjection"; + return "FilterColorProjection"; } // ST() return the very short string describing each filtering action QString FilterColorProjectionPlugin::filterName(ActionIDType 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); - } - return NULL; + 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); return QString(); + } +} + +QString FilterColorProjectionPlugin::pythonFilterName(ActionIDType f) const +{ + switch (f) { + case FP_SINGLEIMAGEPROJ: return QString("compute_color_from_current_raster_projection"); + case FP_MULTIIMAGETRIVIALPROJ: return QString("compute_color_from_active_rasters_projection"); + case FP_MULTIIMAGETRIVIALPROJTEXTURE: + return QString("compute_color_and_texture_from_active_rasters_projection"); + default: assert(0); return QString(); + } } // Info() return the longer string describing each filtering action QString FilterColorProjectionPlugin::filterInfo(ActionIDType 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); - } + 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); + } return NULL; } // What "new" properties the plugin requires -int FilterColorProjectionPlugin::getRequirements(const 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; - } +int FilterColorProjectionPlugin::getRequirements(const 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; } bool FilterColorProjectionPlugin::requiresGLContext(const QAction* action) const { - switch(ID(action)){ + switch (ID(action)) { case FP_SINGLEIMAGEPROJ: case FP_MULTIIMAGETRIVIALPROJ: - case FP_MULTIIMAGETRIVIALPROJTEXTURE : - return true; - default: - assert(0); + case FP_MULTIIMAGETRIVIALPROJTEXTURE: return true; + default: assert(0); } return false; } - // This function define the needed parameters for each filter. -RichParameterList FilterColorProjectionPlugin::initParameterList(const QAction *action, const MeshDocument &md) +RichParameterList +FilterColorProjectionPlugin::initParameterList(const QAction* action, const MeshDocument& md) { - RichParameterList parlst; - switch(ID(action)) - { - case FP_SINGLEIMAGEPROJ : - { - parlst.addParam(RichBool ("usedepth", - true, - "Use depth for projection", - "If true, depth is used to restrict projection on visible faces")); - parlst.addParam(RichFloat ("deptheta", - 0.5, - "depth threshold", - "threshold value for depth buffer projection (shadow buffer)")); - parlst.addParam(RichBool ("onselection", - false, - "Only on selection", - "If true, projection is only done for selected vertices")); - QColor color1 = QColor(0, 0, 0, 255); - parlst.addParam(RichColor("blankColor", color1, "Color for unprojected areas", "Areas that cannot be projected willb e filled using this color. If R=0 G=0 B=0 A=0 old color is preserved")); - } - break; + RichParameterList parlst; + switch (ID(action)) { + case FP_SINGLEIMAGEPROJ: { + parlst.addParam(RichBool( + "usedepth", + true, + "Use depth for projection", + "If true, depth is used to restrict projection on visible faces")); + parlst.addParam(RichFloat( + "deptheta", + 0.5, + "depth threshold", + "threshold value for depth buffer projection (shadow buffer)")); + parlst.addParam(RichBool( + "onselection", + false, + "Only on selection", + "If true, projection is only done for selected vertices")); + QColor color1 = QColor(0, 0, 0, 255); + parlst.addParam(RichColor( + "blankColor", + color1, + "Color for unprojected areas", + "Areas that cannot be projected willb e filled using this color. If R=0 G=0 B=0 A=0 " + "old color is preserved")); + } break; - case FP_MULTIIMAGETRIVIALPROJ : - { - parlst.addParam(RichFloat ("deptheta", - 0.5, - "depth threshold", - "threshold value for depth buffer projection (shadow buffer)")); - parlst.addParam(RichBool ("onselection", - false, - "Only on selection", - "If true, projection is only done for selected vertices")); - parlst.addParam(RichBool ("useangle", - true, - "use angle weight", - "If true, color contribution is weighted by pixel view angle")); - parlst.addParam(RichBool ("usedistance", - true, - "use distance weight", - "If true, color contribution is weighted by pixel view distance")); - parlst.addParam(RichBool ("useborders", - true, - "use image borders weight", - "If true, color contribution is weighted by pixel distance from image boundaries")); - parlst.addParam(RichBool ("usesilhouettes", - true, - "use depth discontinuities weight", - "If true, color contribution is weighted by pixel distance from depth discontinuities (external and internal silhouettes)")); - parlst.addParam(RichBool ("usealpha", - false, - "use image alpha weight", - "If true, alpha channel of the image is used as additional weight. In this way it is possible to mask-out parts of the images that should not be projected on the mesh. Please note this is not a transparency effect, but just influences the weigthing between different images")); - QColor color1 = QColor(0, 0, 0, 255); - parlst.addParam(RichColor("blankColor", color1, "Color for unprojected areas", "Areas that cannot be projected willb e filled using this color. If R=0 G=0 B=0 A=0 old color is preserved")); - } - break; + case FP_MULTIIMAGETRIVIALPROJ: { + parlst.addParam(RichFloat( + "deptheta", + 0.5, + "depth threshold", + "threshold value for depth buffer projection (shadow buffer)")); + parlst.addParam(RichBool( + "onselection", + false, + "Only on selection", + "If true, projection is only done for selected vertices")); + parlst.addParam(RichBool( + "useangle", + true, + "use angle weight", + "If true, color contribution is weighted by pixel view angle")); + parlst.addParam(RichBool( + "usedistance", + true, + "use distance weight", + "If true, color contribution is weighted by pixel view distance")); + parlst.addParam(RichBool( + "useborders", + true, + "use image borders weight", + "If true, color contribution is weighted by pixel distance from image boundaries")); + parlst.addParam(RichBool( + "usesilhouettes", + true, + "use depth discontinuities weight", + "If true, color contribution is weighted by pixel distance from depth discontinuities " + "(external and internal silhouettes)")); + parlst.addParam(RichBool( + "usealpha", + false, + "use image alpha weight", + "If true, alpha channel of the image is used as additional weight. In this way it is " + "possible to mask-out parts of the images that should not be projected on the mesh. " + "Please note this is not a transparency effect, but just influences the weigthing " + "between different images")); + QColor color1 = QColor(0, 0, 0, 255); + parlst.addParam(RichColor( + "blankColor", + color1, + "Color for unprojected areas", + "Areas that cannot be projected willb e filled using this color. If R=0 G=0 B=0 A=0 " + "old color is preserved")); + } break; - case FP_MULTIIMAGETRIVIALPROJTEXTURE : - { - QString fileName = extractFilenameWOExt(md.mm()); - fileName = fileName.append("_color.png"); - parlst.addParam(RichString("textName", - fileName, - "Texture file", - "The texture file to be created")); - parlst.addParam(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(RichBool ("dorefill", - true, - "fill atlas gaps", - "If true, unfilled areas of the mesh are interpolated, to avoid visible seams while mipmapping")); - parlst.addParam(RichFloat ("deptheta", - 0.5, - "depth threshold", - "threshold value for depth buffer projection (shadow buffer)")); - parlst.addParam(RichBool ("onselection", - false, - "Only on selection", - "If true, projection is only done for selected vertices")); - parlst.addParam(RichBool ("useangle", - true, - "use angle weight", - "If true, color contribution is weighted by pixel view angle")); - parlst.addParam(RichBool ("usedistance", - true, - "use distance weight", - "If true, color contribution is weighted by pixel view distance")); - parlst.addParam(RichBool ("useborders", - true, - "use image borders weight", - "If true, color contribution is weighted by pixel distance from image boundaries")); - parlst.addParam(RichBool ("usesilhouettes", - true, - "use depth discontinuities weight", - "If true, color contribution is weighted by pixel distance from depth discontinuities (external and internal silhouettes)")); - parlst.addParam(RichBool ("usealpha", - false, - "use image alpha weight", - "If true, alpha channel of the image is used as additional weight. In this way it is possible to mask-out parts of the images that should not be projected on the mesh. Please note this is not a transparency effect, but just influences the weigthing between different images")); - } - break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE: { + QString fileName = extractFilenameWOExt(md.mm()); + fileName = fileName.append("_color.png"); + parlst.addParam( + RichString("textName", fileName, "Texture file", "The texture file to be created")); + parlst.addParam(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(RichBool( + "dorefill", + true, + "fill atlas gaps", + "If true, unfilled areas of the mesh are interpolated, to avoid visible seams while " + "mipmapping")); + parlst.addParam(RichFloat( + "deptheta", + 0.5, + "depth threshold", + "threshold value for depth buffer projection (shadow buffer)")); + parlst.addParam(RichBool( + "onselection", + false, + "Only on selection", + "If true, projection is only done for selected vertices")); + parlst.addParam(RichBool( + "useangle", + true, + "use angle weight", + "If true, color contribution is weighted by pixel view angle")); + parlst.addParam(RichBool( + "usedistance", + true, + "use distance weight", + "If true, color contribution is weighted by pixel view distance")); + parlst.addParam(RichBool( + "useborders", + true, + "use image borders weight", + "If true, color contribution is weighted by pixel distance from image boundaries")); + parlst.addParam(RichBool( + "usesilhouettes", + true, + "use depth discontinuities weight", + "If true, color contribution is weighted by pixel distance from depth discontinuities " + "(external and internal silhouettes)")); + parlst.addParam(RichBool( + "usealpha", + false, + "use image alpha weight", + "If true, alpha channel of the image is used as additional weight. In this way it is " + "possible to mask-out parts of the images that should not be projected on the mesh. " + "Please note this is not a transparency effect, but just influences the weigthing " + "between different images")); + } break; - default: break; // do not add any parameter for the other filters - } - return parlst; + default: break; // do not add any parameter for the other filters + } + return parlst; } // Core Function doing the actual mesh processing. -std::map FilterColorProjectionPlugin::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb) +std::map FilterColorProjectionPlugin::applyFilter( + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos* cb) { - if (glContext != nullptr){ - //CMeshO::FaceIterator fi; + if (glContext != nullptr) { + // CMeshO::FaceIterator fi; CMeshO::VertexIterator vi; - RenderHelper *rendermanager=NULL; - - switch(ID(filter)) - { + RenderHelper* rendermanager = NULL; - ////--------------------------- project single trivial ---------------------------------- + switch (ID(filter)) { + ////--------------------------- project single trivial + ///---------------------------------- - case FP_SINGLEIMAGEPROJ : - { - bool use_depth = par.getBool("usedepth"); - bool onselection = par.getBool("onselection"); - Scalarm eta = par.getFloat("deptheta"); - QColor blank = par.getColor("blankColor"); + case FP_SINGLEIMAGEPROJ: { + bool use_depth = par.getBool("usedepth"); + bool onselection = par.getBool("onselection"); + Scalarm eta = par.getFloat("deptheta"); + QColor blank = par.getColor("blankColor"); - Scalarm depth=0; // depth of point (distance from camera) - Scalarm pdepth=0; // depth value of projected point (from depth map) + Scalarm depth = 0; // depth of point (distance from camera) + Scalarm pdepth = 0; // depth value of projected point (from depth map) - // get current raster and model - RasterModel *raster = md.rm(); - MeshModel *model = md.mm(); + // get current raster and model + RasterModel* raster = md.rm(); + MeshModel* model = md.mm(); - // no projection if camera not valid - if(!raster || !raster->shot.IsValid()) { - throw MLException("Raster or camera not valid."); + // no projection if camera not valid + if (!raster || !raster->shot.IsValid()) { + throw MLException("Raster or camera not valid."); + } + + // the mesh has to be correctly transformed before mapping + tri::UpdatePosition::Matrix(model->cm, model->cm.Tr, true); + tri::UpdateBounding::Box(model->cm); + + // making context current + glContext->makeCurrent(); + + if (use_depth) { + // init rendermanager + rendermanager = new RenderHelper(); + if (rendermanager->initializeGL(cb) != 0) { + delete rendermanager; + throw MLException("Failed on initializing GL rendermanager."); } + log("init GL"); + // if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + // return false; + // Log("init Buffers"); - // the mesh has to be correctly transformed before mapping - tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); - tri::UpdateBounding::Box(model->cm); - - // making context current - glContext->makeCurrent(); + // render depth + rendermanager->renderScene(raster->shot, model, RenderHelper::FLAT, glContext); + } - if(use_depth) - { - // init rendermanager - rendermanager = new RenderHelper(); - if( rendermanager->initializeGL(cb) != 0 ) - { - delete rendermanager; - throw MLException("Failed on initializing GL rendermanager."); - } - log("init GL"); - //if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) - // return false; - //Log("init Buffers"); + // unmaking context current + glContext->doneCurrent(); - // render depth - rendermanager->renderScene(raster->shot, model, RenderHelper::FLAT, glContext); - } + qDebug( + "Viewport %i %i", + raster->shot.Intrinsics.ViewportPx[0], + raster->shot.Intrinsics.ViewportPx[1]); + for (vi = model->cm.vert.begin(); vi != model->cm.vert.end(); ++vi) { + if (!(*vi).IsD() && (!onselection || (*vi).IsS())) { + Point2m pp = raster->shot.Project((*vi).P()); + // pray is the vector from the point-to-be-colored to the camera center + Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); - // unmaking context current - glContext->doneCurrent(); + if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || + (blank.alpha() != 0)) + (*vi).C() = + vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); - qDebug("Viewport %i %i",raster->shot.Intrinsics.ViewportPx[0],raster->shot.Intrinsics.ViewportPx[1]); - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) - { - if(!(*vi).IsD() && (!onselection || (*vi).IsS())) - { - Point2m pp = raster->shot.Project((*vi).P()); - // pray is the vector from the point-to-be-colored to the camera center - Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); + // if inside image + if (pp[0] > 0 && pp[1] > 0 && pp[0] < raster->shot.Intrinsics.ViewportPx[0] && + pp[1] < raster->shot.Intrinsics.ViewportPx[1]) { + if ((pray.dot(-raster->shot.Axis(2))) <= 0.0) { + if (use_depth) { + depth = raster->shot.Depth((*vi).P()); + pdepth = rendermanager->depth->getval( + int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * + // raster->shot.Intrinsics.ViewportPx[0]) + // + int(pp[0])]; + } - if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) - (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); - - //if inside image - if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) - { - if((pray.dot(-raster->shot.Axis(2))) <= 0.0) - { - if(use_depth) - { - depth = raster->shot.Depth((*vi).P()); - pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1]));//rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; - } - - if(!use_depth || (depth <= (pdepth + eta))) - { - QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); - (*vi).C() = vcg::Color4b(qRed(pcolor), qGreen(pcolor), qBlue(pcolor), 255); - } + if (!use_depth || (depth <= (pdepth + eta))) { + QRgb pcolor = raster->currentPlane->image.pixel( + pp[0], raster->shot.Intrinsics.ViewportPx[1] - pp[1]); + (*vi).C() = + vcg::Color4b(qRed(pcolor), qGreen(pcolor), qBlue(pcolor), 255); } } } } - - // the mesh has to return to its original position - tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); - tri::UpdateBounding::Box(model->cm); - - // delete rendermanager - if(rendermanager != NULL) - delete rendermanager; } - - break; + + // the mesh has to return to its original position + tri::UpdatePosition::Matrix(model->cm, Inverse(model->cm.Tr), true); + tri::UpdateBounding::Box(model->cm); + + // delete rendermanager + if (rendermanager != NULL) + delete rendermanager; + } + + break; ////--------------------------- project multi trivial ---------------------------------- - case FP_MULTIIMAGETRIVIALPROJ : - { - bool onselection = par.getBool("onselection"); - Scalarm eta = par.getFloat("deptheta"); - bool useangle = par.getBool("useangle"); - bool usedistance = par.getBool("usedistance"); - bool useborders = par.getBool("useborders"); - bool usesilhouettes = par.getBool("usesilhouettes"); - bool usealphamask = par.getBool("usealpha"); - QColor blank = par.getColor("blankColor"); + case FP_MULTIIMAGETRIVIALPROJ: { + bool onselection = par.getBool("onselection"); + Scalarm eta = par.getFloat("deptheta"); + bool useangle = par.getBool("useangle"); + bool usedistance = par.getBool("usedistance"); + bool useborders = par.getBool("useborders"); + bool usesilhouettes = par.getBool("usesilhouettes"); + bool usealphamask = par.getBool("usealpha"); + QColor blank = par.getColor("blankColor"); - Scalarm depth=0; // depth of point (distance from camera) - Scalarm pdepth=0; // depth value of projected point (from depth map) - double pweight; // pixel weight - MeshModel *model; - bool do_project; - int cam_ind; + Scalarm depth = 0; // depth of point (distance from camera) + Scalarm pdepth = 0; // depth value of projected point (from depth map) + double pweight; // pixel weight + MeshModel* model; + bool do_project; + int cam_ind; - // min max depth for depth weight normalization - float allcammaxdepth; - float allcammindepth; + // min max depth for depth weight normalization + float allcammaxdepth; + float allcammindepth; - // max image size for border weight normalization - float allcammaximagesize; + // max image size for border weight normalization + float allcammaximagesize; - // accumulation buffers for colors and weights - int buff_ind; - double *weights; - double *acc_red; - double *acc_grn; - double *acc_blu; + // accumulation buffers for colors and weights + int buff_ind; + double* weights; + double* acc_red; + double* acc_grn; + double* acc_blu; - // get current model - model = md.mm(); + // get current 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); - - // init accumulation buffers for colors and weights - log("init color accumulation buffers"); - weights = new double[model->cm.vn]; - acc_red = new double[model->cm.vn]; - acc_grn = new double[model->cm.vn]; - acc_blu = new double[model->cm.vn]; - for(int buff_ind=0; buff_indcm.vn; buff_ind++) - { - weights[buff_ind] = 0.0; - acc_red[buff_ind] = 0.0; - acc_grn[buff_ind] = 0.0; - acc_blu[buff_ind] = 0.0; - } - - // 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; - cam_ind = 0; - for(const RasterModel& rm : md.rasterIterator()) { - 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(rm.shot.Intrinsics.ViewportPx[0] * rm.shot.Intrinsics.ViewportPx[1])); - if (imgdiag > allcammaximagesize) - allcammaximagesize = imgdiag; - cam_ind++; - } - - //-- cycle all cameras - cam_ind = 0; - for(const RasterModel& raster : md.rasterIterator()){ - if(raster.isVisible()) { - 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) { - // making context current - glContext->makeCurrent(); - - // delete & reinit rendermanager - if(rendermanager != NULL) - delete rendermanager; - rendermanager = new RenderHelper(); - if( rendermanager->initializeGL(cb) != 0 ){ - delete rendermanager; - throw MLException("Failed on initializing GL rendermanager."); - } - log("init GL"); - /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) - return false; - Log("init Buffers");*/ - - // render normal & depth - rendermanager->renderScene(raster.shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); - - // unmaking context current - glContext->doneCurrent(); - - buff_ind=0; - - // 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.pfm",cam_ind); - //silhouette_buff->dumppfm(dumpFileName); - - silhouette_buff->initborder(rendermanager->depth); - //sprintf(dumpFileName,"Bbord%i.pfm",cam_ind); - //silhouette_buff->dumppfm(dumpFileName); - - maxsildist = silhouette_buff->distancefield(); - //sprintf(dumpFileName,"Cbord%i.pfm",cam_ind); - //silhouette_buff->dumppfm(dumpFileName); - } - - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) { - if(!(*vi).IsD() && (!onselection || (*vi).IsS())) { - // pp is the projected point in image space - Point2m pp = raster.shot.Project((*vi).P()); - // pray is the vector from the point-to-be-colored to the camera center - Point3m pray = (raster.shot.GetViewPoint() - (*vi).P()).Normalize(); - - //if inside image - if(pp[0]>=0 && pp[1]>=0 && pp[0]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) { - Point3m pixnorm = (*vi).N(); - Point3m viewaxis = raster.shot.GetViewPoint() - (*vi).P(); - pixnorm.Normalize(); - 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); - //borderw = min(1.0,borderw); //debug debug - //borderw = max(0.0,borderw); //debug debug - - 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; - //silw = min(1.0f,silw); //debug debug - //silw = max(0.0f,silw); //debug debug - - pweight *= silw; - } - - if(usealphamask) { //alpha channel of image is an additional mask - pweight *= (qAlpha(pcolor) / 255.0); - } - - weights[buff_ind] += pweight; - acc_red[buff_ind] += (qRed(pcolor) * pweight / 255.0); - acc_grn[buff_ind] += (qGreen(pcolor) * pweight / 255.0); - acc_blu[buff_ind] += (qBlue(pcolor) * pweight / 255.0); - } - } - } - } - buff_ind++; - } - cam_ind ++; - - if(usesilhouettes) - { - delete silhouette_buff; - } - - } // end foreach camera - } // end foreach camera - } - - buff_ind = 0; - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) - { - if(!(*vi).IsD() && (!onselection || (*vi).IsS())) - { - if (weights[buff_ind] != 0) // if 0, it has not found any valid projection on any camera - { - (*vi).C() = vcg::Color4b( (acc_red[buff_ind] / weights[buff_ind]) *255.0, - (acc_grn[buff_ind] / weights[buff_ind]) *255.0, - (acc_blu[buff_ind] / weights[buff_ind]) *255.0, - 255); - } - else - { - if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) - (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); - } - } - buff_ind++; - } - - // the mesh has to return to its original position - tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); - tri::UpdateBounding::Box(model->cm); - - // delete rendermanager - if(rendermanager != NULL) - delete rendermanager; - - // delete accumulation buffers - delete[] weights; - delete[] acc_red; - delete[] acc_grn; - delete[] acc_blu; + // the mesh has to be correctly transformed before mapping + tri::UpdatePosition::Matrix(model->cm, model->cm.Tr, true); + tri::UpdateBounding::Box(model->cm); + // init accumulation buffers for colors and weights + log("init color accumulation buffers"); + weights = new double[model->cm.vn]; + acc_red = new double[model->cm.vn]; + acc_grn = new double[model->cm.vn]; + acc_blu = new double[model->cm.vn]; + for (int buff_ind = 0; buff_ind < model->cm.vn; buff_ind++) { + weights[buff_ind] = 0.0; + acc_red[buff_ind] = 0.0; + acc_grn[buff_ind] = 0.0; + acc_blu[buff_ind] = 0.0; } - break; + // calculate accuratenear/far for all cameras + std::vector my_near; + std::vector my_far; + calculateNearFarAccurate(md, &my_near, &my_far); - case FP_MULTIIMAGETRIVIALPROJTEXTURE : - { + allcammaxdepth = -1000000; + allcammindepth = 1000000; + allcammaximagesize = -1000000; + cam_ind = 0; + for (const RasterModel& rm : md.rasterIterator()) { + if (my_far[cam_ind] > allcammaxdepth) + allcammaxdepth = my_far[cam_ind]; + if (my_near[cam_ind] < allcammindepth) + allcammindepth = my_near[cam_ind]; - if(!tri::HasPerWedgeTexCoord(md.mm()->cm)) - { - throw MLException("Error: nothing have been done. Mesh has no Texture Coordinates."); - } + float imgdiag = sqrt( + double(rm.shot.Intrinsics.ViewportPx[0] * rm.shot.Intrinsics.ViewportPx[1])); + if (imgdiag > allcammaximagesize) + allcammaximagesize = imgdiag; + cam_ind++; + } - //bool onselection = par.getBool("onselection"); - int texsize = par.getInt("texsize"); - bool dorefill = par.getBool("dorefill"); - Scalarm eta = par.getFloat("deptheta"); - bool useangle = par.getBool("useangle"); - bool usedistance = par.getBool("usedistance"); - bool useborders = par.getBool("useborders"); - bool usesilhouettes = par.getBool("usesilhouettes"); - bool usealphamask = par.getBool("usealpha"); - QString textName = par.getString("textName"); + //-- cycle all cameras + cam_ind = 0; + for (const RasterModel& raster : md.rasterIterator()) { + if (raster.isVisible()) { + do_project = true; - int textW = texsize; - int textH = texsize; + // no drawing if camera not valid + if (!raster.shot.IsValid()) + do_project = false; - Scalarm depth=0; // depth of point (distance from camera) - Scalarm pdepth=0; // depth value of projected point (from depth map) - double pweight; // pixel weight - MeshModel *model; - bool do_project; - int cam_ind; + // no drawing if raster is not active + // if(!raster->shot.IsValid()) + // do_project = false; - // min max depth for depth weight normalization - float allcammaxdepth; - float allcammindepth; + if (do_project) { + // making context current + glContext->makeCurrent(); - // max image size for border weight normalization - float allcammaximagesize; + // delete & reinit rendermanager + if (rendermanager != NULL) + delete rendermanager; + rendermanager = new RenderHelper(); + if (rendermanager->initializeGL(cb) != 0) { + delete rendermanager; + throw MLException("Failed on initializing GL rendermanager."); + } + log("init GL"); + /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + return false; + Log("init Buffers");*/ - // get the working model - model = md.mm(); + // render normal & depth + rendermanager->renderScene( + raster.shot, + model, + RenderHelper::NORMAL, + glContext, + my_near[cam_ind] * 0.5, + my_far[cam_ind] * 1.25); - // the mesh has to be correctly transformed before mapping - tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); - tri::UpdateBounding::Box(model->cm); + // unmaking context current + glContext->doneCurrent(); - // 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); + buff_ind = 0; - // 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 + // 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); - // Compute (texture-space) border edges - if(dorefill) - { - model->updateDataMask(MeshModel::MM_FACEFACETOPO); - tri::UpdateTopology::FaceFaceFromTexCoord(model->cm); - tri::UpdateFlags::FaceBorderFromFF(model->cm); - } + silhouette_buff->applysobel(rendermanager->depth); + // sprintf(dumpFileName,"Abord%i.pfm",cam_ind); + // silhouette_buff->dumppfm(dumpFileName); - // create a list of to-be-filled texels and accumulators - // storing texel 2d coords, texel mesh-space point, texel mesh normal + silhouette_buff->initborder(rendermanager->depth); + // sprintf(dumpFileName,"Bbord%i.pfm",cam_ind); + // silhouette_buff->dumppfm(dumpFileName); - vector texels; - texels.clear(); - texels.reserve(textW*textH); // just to avoid the 2x reallocate rule... + maxsildist = silhouette_buff->distancefield(); + // sprintf(dumpFileName,"Cbord%i.pfm",cam_ind); + // silhouette_buff->dumppfm(dumpFileName); + } - vector accums; - accums.clear(); - accums.reserve(textW*textH); // just to avoid the 2x reallocate rule... + for (vi = model->cm.vert.begin(); vi != model->cm.vert.end(); ++vi) { + if (!(*vi).IsD() && (!onselection || (*vi).IsS())) { + // pp is the projected point in image space + Point2m pp = raster.shot.Project((*vi).P()); + // pray is the vector from the point-to-be-colored to the camera + // center + Point3m pray = (raster.shot.GetViewPoint() - (*vi).P()).Normalize(); - // 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); + // if inside image + if (pp[0] >= 0 && pp[1] >= 0 && + pp[0] < raster.shot.Intrinsics.ViewportPx[0] && + pp[1] < raster.shot.Intrinsics.ViewportPx[1]) { + if ((pray.dot(-raster.shot.Axis(2))) <= 0.0) { + depth = raster.shot.Depth((*vi).P()); + pdepth = rendermanager->depth->getval( + int(pp[0]), + int(pp[1])); // rendermanager->depth[(int(pp[1]) * + // raster->shot.Intrinsics.ViewportPx[0]) + // + int(pp[0])]; - // 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; - cam_ind = 0; - for(const RasterModel& rm : md.rasterIterator()) { - 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(rm.shot.Intrinsics.ViewportPx[0] * rm.shot.Intrinsics.ViewportPx[1])); - if (imgdiag > allcammaximagesize) - allcammaximagesize = imgdiag; - cam_ind++; - } - - //-- cycle all cameras - cam_ind = 0; - for(const RasterModel& raster : md.rasterIterator()) { - if(raster.isVisible()) { - 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) { - // making context current - glContext->makeCurrent(); - - // delete & reinit rendermanager - if(rendermanager != NULL) - delete rendermanager; - rendermanager = new RenderHelper(); - if( rendermanager->initializeGL(cb) != 0 ) { - delete rendermanager; - throw MLException("Failed on initializing GL rendermanager."); - } - log("init GL"); - /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) - return false; - Log("init Buffers");*/ - - // render normal & depth - rendermanager->renderScene(raster.shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); - - // unmaking context current - glContext->doneCurrent(); - - // 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(size_t texcount=0; texcount < texels.size(); texcount++) { - Point2m pp = raster.shot.Project(texels[texcount].meshpoint); - // pray is the vector from the point-to-be-colored to the camera center - Point3m pray = (raster.shot.GetViewPoint() - texels[texcount].meshpoint).Normalize(); - - //if inside image - if(pp[0]>0 && pp[1]>0 && pp[0]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)) { + if (depth <= (pdepth + eta)) { // determine color - QRgb pcolor = raster.currentPlane->image.pixel(pp[0],raster.shot.Intrinsics.ViewportPx[1] - pp[1]); + QRgb pcolor = raster.currentPlane->image.pixel( + pp[0], + raster.shot.Intrinsics.ViewportPx[1] - pp[1]); // determine weight pweight = 1.0; - if(useangle) { - Point3m pixnorm = texels[texcount].meshnormal; + if (useangle) { + Point3m pixnorm = (*vi).N(); + Point3m viewaxis = + raster.shot.GetViewPoint() - (*vi).P(); pixnorm.Normalize(); - - Point3m viewaxis = raster.shot.GetViewPoint() - texels[texcount].meshpoint; viewaxis.Normalize(); float ang = abs(pixnorm * viewaxis); - ang = min(1.0f, ang); + ang = min(1.0f, ang); pweight *= ang; } - if(usedistance) { + if (usedistance) { float distw = depth; - distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); + 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); + 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); + // borderw = min(1.0,borderw); //debug debug + // borderw = max(0.0,borderw); //debug debug pweight *= borderw; } - if(usesilhouettes) { - // here the silhouette weight is applied, but it is calculated before, on a per-image basis + 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; + silw = silhouette_buff->getval( + int(pp[0]), int(pp[1])) / + maxsildist; + // silw = min(1.0f,silw); //debug debug + // silw = max(0.0f,silw); //debug debug + pweight *= silw; } - if(usealphamask) { //alpha channel of image is an additional mask + if (usealphamask) { // alpha channel of image is an + // additional mask pweight *= (qAlpha(pcolor) / 255.0); } - 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); + weights[buff_ind] += pweight; + acc_red[buff_ind] += (qRed(pcolor) * pweight / 255.0); + acc_grn[buff_ind] += (qGreen(pcolor) * pweight / 255.0); + acc_blu[buff_ind] += (qBlue(pcolor) * pweight / 255.0); } } } + } + buff_ind++; + } + cam_ind++; - } // end foreach texel - cam_ind ++; + if (usesilhouettes) { + delete silhouette_buff; + } - if(usesilhouettes) { - delete silhouette_buff; + } // end foreach camera + } // end foreach camera + } + + buff_ind = 0; + for (vi = model->cm.vert.begin(); vi != model->cm.vert.end(); ++vi) { + if (!(*vi).IsD() && (!onselection || (*vi).IsS())) { + if (weights[buff_ind] != + 0) // if 0, it has not found any valid projection on any camera + { + (*vi).C() = vcg::Color4b( + (acc_red[buff_ind] / weights[buff_ind]) * 255.0, + (acc_grn[buff_ind] / weights[buff_ind]) * 255.0, + (acc_blu[buff_ind] / weights[buff_ind]) * 255.0, + 255); + } + else { + if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || + (blank.alpha() != 0)) + (*vi).C() = vcg::Color4b( + blank.red(), blank.green(), blank.blue(), blank.alpha()); + } + } + buff_ind++; + } + + // the mesh has to return to its original position + tri::UpdatePosition::Matrix(model->cm, Inverse(model->cm.Tr), true); + tri::UpdateBounding::Box(model->cm); + + // delete rendermanager + if (rendermanager != NULL) + delete rendermanager; + + // delete accumulation buffers + delete[] weights; + delete[] acc_red; + delete[] acc_grn; + delete[] acc_blu; + + } break; + + case FP_MULTIIMAGETRIVIALPROJTEXTURE: { + if (!tri::HasPerWedgeTexCoord(md.mm()->cm)) { + throw MLException( + "Error: nothing have been done. Mesh has no Texture Coordinates."); + } + + // bool onselection = par.getBool("onselection"); + int texsize = par.getInt("texsize"); + bool dorefill = par.getBool("dorefill"); + Scalarm eta = par.getFloat("deptheta"); + bool useangle = par.getBool("useangle"); + bool usedistance = par.getBool("usedistance"); + bool useborders = par.getBool("useborders"); + bool usesilhouettes = par.getBool("usesilhouettes"); + bool usealphamask = par.getBool("usealpha"); + QString textName = par.getString("textName"); + + int textW = texsize; + int textH = texsize; + + Scalarm depth = 0; // depth of point (distance from camera) + Scalarm pdepth = 0; // depth value of projected point (from depth map) + double pweight; // pixel weight + MeshModel* model; + bool do_project; + int cam_ind; + + // 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 + if (dorefill) { + model->updateDataMask(MeshModel::MM_FACEFACETOPO); + 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 < textH; ++y) { + for (int x = 0; x < textW; ++x) { + QRgb px = img.pixel(x, y); + if (qAlpha(px) < 255 && qAlpha(px) > 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; + cam_ind = 0; + for (const RasterModel& rm : md.rasterIterator()) { + 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(rm.shot.Intrinsics.ViewportPx[0] * rm.shot.Intrinsics.ViewportPx[1])); + if (imgdiag > allcammaximagesize) + allcammaximagesize = imgdiag; + cam_ind++; + } + + //-- cycle all cameras + cam_ind = 0; + for (const RasterModel& raster : md.rasterIterator()) { + if (raster.isVisible()) { + 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) { + // making context current + glContext->makeCurrent(); + + // delete & reinit rendermanager + if (rendermanager != NULL) + delete rendermanager; + rendermanager = new RenderHelper(); + if (rendermanager->initializeGL(cb) != 0) { + delete rendermanager; + throw MLException("Failed on initializing GL rendermanager."); + } + log("init GL"); + /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + return false; + Log("init Buffers");*/ + + // render normal & depth + rendermanager->renderScene( + raster.shot, + model, + RenderHelper::NORMAL, + glContext, + my_near[cam_ind] * 0.5, + my_far[cam_ind] * 1.25); + + // unmaking context current + glContext->doneCurrent(); + + // 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 (size_t texcount = 0; texcount < texels.size(); texcount++) { + Point2m pp = raster.shot.Project(texels[texcount].meshpoint); + // pray is the vector from the point-to-be-colored to the camera center + Point3m pray = (raster.shot.GetViewPoint() - texels[texcount].meshpoint) + .Normalize(); + + // if inside image + if (pp[0] > 0 && pp[1] > 0 && + pp[0] < raster.shot.Intrinsics.ViewportPx[0] && + pp[1] < raster.shot.Intrinsics.ViewportPx[1]) { + if ((pray.dot(-raster.shot.Axis(2))) <= 0.0) { + 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) { + Point3m pixnorm = texels[texcount].meshnormal; + pixnorm.Normalize(); + + Point3m 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; + } + + if (usealphamask) { // alpha channel of image is an + // additional mask + pweight *= (qAlpha(pcolor) / 255.0); + } + + 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 if(do_project) + } // end foreach texel + cam_ind++; - } - } // end foreach camera + if (usesilhouettes) { + delete silhouette_buff; + } - // for each texel.... divide accumulated values by weight and write to texture - for(size_t texcount=0; texcount < texels.size(); texcount++) - { - if(accums[texcount].weights > 0.0) - { - float texel_red = accums[texcount].acc_red / accums[texcount].weights; - float texel_green = accums[texcount].acc_grn / accums[texcount].weights; - float 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)); - } - else // if no projected data available, black (to be refilled later on - { - img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(0, 0, 0, 0)); - } + } // end if(do_project) } + } // end foreach camera - // cleaning - texels.clear(); - accums.clear(); + // for each texel.... divide accumulated values by weight and write to texture + for (size_t texcount = 0; texcount < texels.size(); texcount++) { + if (accums[texcount].weights > 0.0) { + float texel_red = accums[texcount].acc_red / accums[texcount].weights; + float texel_green = accums[texcount].acc_grn / accums[texcount].weights; + float texel_blue = accums[texcount].acc_blu / accums[texcount].weights; - // PullPush - if(dorefill) - { - cb(85, "Filling texture holes..."); - - PullPush(img, qRgba(0,0,0,0)); // atlas gaps + 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)); } - - // Undo topology changes - if(dorefill) + else // if no projected data available, black (to be refilled later on { - tri::UpdateTopology::FaceFace(model->cm); - tri::UpdateFlags::FaceBorderFromFF(model->cm); + img.setPixel( + texels[texcount].texcoord.X(), + img.height() - 1 - texels[texcount].texcoord.Y(), + qRgba(0, 0, 0, 0)); } + } - // Assign texture - cb(90, "Assigning texture ..."); - model->clearTextures(); - model->addTexture(textName.toStdString(), img); + // cleaning + texels.clear(); + accums.clear(); - // 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; - default: - wrongActionCalled(filter); + // PullPush + if (dorefill) { + cb(85, "Filling texture holes..."); + + PullPush(img, qRgba(0, 0, 0, 0)); // atlas gaps + } + + // Undo topology changes + if (dorefill) { + tri::UpdateTopology::FaceFace(model->cm); + tri::UpdateFlags::FaceBorderFromFF(model->cm); + } + + // Assign texture + cb(90, "Assigning texture ..."); + model->clearTextures(); + model->addTexture(textName.toStdString(), img); + + // 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; + default: wrongActionCalled(filter); } return std::map(); } @@ -911,53 +1025,44 @@ std::map FilterColorProjectionPlugin::applyFilter(const Q } } -FilterColorProjectionPlugin::FilterClass FilterColorProjectionPlugin::getClass(const QAction *a) const +FilterColorProjectionPlugin::FilterClass +FilterColorProjectionPlugin::getClass(const QAction* a) const { - switch(ID(a)) { - case FP_SINGLEIMAGEPROJ: - return FilterClass(Camera + VertexColoring); - break; - case FP_MULTIIMAGETRIVIALPROJ: - return FilterClass(Camera + VertexColoring); - break; - case FP_MULTIIMAGETRIVIALPROJTEXTURE: - return FilterClass(Camera + Texture); - break; - default : assert(0); - return FilterPlugin::Generic; - } + switch (ID(a)) { + case FP_SINGLEIMAGEPROJ: return FilterClass(Camera + VertexColoring); break; + case FP_MULTIIMAGETRIVIALPROJ: return FilterClass(Camera + VertexColoring); break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE: return FilterClass(Camera + Texture); break; + default: assert(0); return FilterPlugin::Generic; + } } -int FilterColorProjectionPlugin::postCondition( const QAction* a ) const{ - switch(ID(a)) { - case FP_SINGLEIMAGEPROJ: - return MeshModel::MM_VERTCOLOR; - break; - case FP_MULTIIMAGETRIVIALPROJ: - return MeshModel::MM_VERTCOLOR; - break; - case FP_MULTIIMAGETRIVIALPROJTEXTURE: - return MeshModel::MM_WEDGTEXCOORD; - break; - default: - return MeshModel::MM_ALL; - } +int FilterColorProjectionPlugin::postCondition(const QAction* a) const +{ + switch (ID(a)) { + case FP_SINGLEIMAGEPROJ: return MeshModel::MM_VERTCOLOR; break; + case FP_MULTIIMAGETRIVIALPROJ: return MeshModel::MM_VERTCOLOR; break; + case FP_MULTIIMAGETRIVIALPROJTEXTURE: return MeshModel::MM_WEDGTEXCOORD; break; + default: return MeshModel::MM_ALL; + } } //--- this function calculates the near and far values -int FilterColorProjectionPlugin::calculateNearFarAccurate(MeshDocument &md, std::vector *near_acc, std::vector *far_acc) +int FilterColorProjectionPlugin::calculateNearFarAccurate( + MeshDocument& md, + std::vector* near_acc, + std::vector* far_acc) { CMeshO::VertexIterator vi; - int rasterindex; + int rasterindex; - if(near_acc != nullptr) { + if (near_acc != nullptr) { near_acc->clear(); near_acc->resize(md.rasterNumber()); } else return -1; - if(far_acc != nullptr) { + if (far_acc != nullptr) { far_acc->clear(); far_acc->resize(md.rasterNumber()); } @@ -965,43 +1070,44 @@ int FilterColorProjectionPlugin::calculateNearFarAccurate(MeshDocument &md, std: return -1; // init near and far vectors - for(unsigned int rasterindex = 0; rasterindex < md.rasterNumber(); rasterindex++) { - (*near_acc)[rasterindex] = 1000000; + for (unsigned int rasterindex = 0; rasterindex < md.rasterNumber(); rasterindex++) { + (*near_acc)[rasterindex] = 1000000; (*far_acc)[rasterindex] = -1000000; } // current model - MeshModel *model = md.mm(); + MeshModel* model = md.mm(); // scan all vertices - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) { - if(!(*vi).IsD()) { + for (vi = model->cm.vert.begin(); vi != model->cm.vert.end(); ++vi) { + if (!(*vi).IsD()) { // check against all cameras rasterindex = 0; - for(const RasterModel& raster: md.rasterIterator()) { - if(raster.shot.IsValid()) { + for (const RasterModel& raster : md.rasterIterator()) { + if (raster.shot.IsValid()) { Point2m pp = raster.shot.Project((*vi).P()); Point3m viewaxis = raster.shot.GetViewPoint() - (*vi).P(); viewaxis.Normalize(); - //if(viewaxis * raster->shot.GetViewDir() > 0.0) // if facing - if(pp[0]>0 && pp[1]>0 && pp[0]shot.GetViewDir() > 0.0) // if facing + if (pp[0] > 0 && pp[1] > 0 && pp[0] < raster.shot.Intrinsics.ViewportPx[0] && + pp[1] < raster.shot.Intrinsics.ViewportPx[1]) { // if inside image // then update near and far - if(raster.shot.Depth((*vi).P()) < (*near_acc)[rasterindex]) + if (raster.shot.Depth((*vi).P()) < (*near_acc)[rasterindex]) (*near_acc)[rasterindex] = raster.shot.Depth((*vi).P()); - if(raster.shot.Depth((*vi).P()) > (*far_acc)[rasterindex]) - (*far_acc)[rasterindex] = raster.shot.Depth((*vi).P()); + if (raster.shot.Depth((*vi).P()) > (*far_acc)[rasterindex]) + (*far_acc)[rasterindex] = raster.shot.Depth((*vi).P()); } - } rasterindex++; } } } - for(unsigned rasterindex = 0; rasterindex < md.rasterNumber(); rasterindex++) { // set to 0 0 invalid and "strange" cameras - if ( ((*near_acc)[rasterindex] == 1000000) || ((*far_acc)[rasterindex] == -1000000) ) { + for (unsigned rasterindex = 0; rasterindex < md.rasterNumber(); + rasterindex++) { // set to 0 0 invalid and "strange" cameras + if (((*near_acc)[rasterindex] == 1000000) || ((*far_acc)[rasterindex] == -1000000)) { (*near_acc)[rasterindex] = 0; (*far_acc)[rasterindex] = 0; } diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.h b/src/meshlabplugins/filter_color_projection/filter_color_projection.h index 0643990c7..06206a19c 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.h +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.h @@ -40,6 +40,7 @@ class FilterColorProjectionPlugin : public QObject, public FilterPlugin QString pluginName() const; QString filterName(ActionIDType filter) const; + QString pythonFilterName(ActionIDType f) const; QString filterInfo(ActionIDType filter) const; int postCondition( const QAction* ) const; @@ -50,7 +51,6 @@ class FilterColorProjectionPlugin : public QObject, public FilterPlugin std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} - private: int calculateNearFarAccurate(MeshDocument &md, std::vector *near, std::vector *far); }; diff --git a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp index c9b3f5823..cfed75fc8 100644 --- a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp +++ b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp @@ -61,15 +61,22 @@ QString FilterMutualGlobal::pluginName() const return "FilterMutualGlobal"; } -// ST() must return the very short string describing each filtering action -// (this string is used also to define the menu entry) QString FilterMutualGlobal::filterName(ActionIDType filterId) const { - switch(filterId) { - case FP_IMAGE_GLOBALIGN : return QString("Image Registration: Global refinement using Mutual Information"); - default : assert(0); - } - return QString(); + switch (filterId) { + case FP_IMAGE_GLOBALIGN: + return QString("Image Registration: Global refinement using Mutual Information"); + default: assert(0); return QString(); + } +} + +QString FilterMutualGlobal::pythonFilterName(ActionIDType f) const +{ + switch (f) { + case FP_IMAGE_GLOBALIGN: + return QString("raster_global_refinement_mutual_information"); + default: assert(0); return QString(); + } } // Info() must return the longer string describing each filtering action diff --git a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h index 40ac56b2d..13df33082 100644 --- a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h +++ b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h @@ -54,6 +54,8 @@ public: QString filterName(ActionIDType filter) const; QString filterInfo(ActionIDType filter) const; + QString pythonFilterName(ActionIDType f) const; + RichParameterList initParameterList(const QAction*, const MeshDocument & md); std::map applyFilter( const QAction* action, @@ -83,7 +85,6 @@ public: void initGL(); - }; diff --git a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp index b954f7e0a..bd8e3ad39 100644 --- a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp +++ b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp @@ -49,12 +49,17 @@ QString FilterMutualInfoPlugin::pluginName() const QString FilterMutualInfoPlugin::filterName(ActionIDType filterId) const { - switch(filterId) { - case FP_IMAGE_MUTUALINFO: - return "Image alignment: Mutual Information"; - default : - assert(0); - return ""; + switch (filterId) { + case FP_IMAGE_MUTUALINFO: return "Image alignment: Mutual Information"; + default: assert(0); return QString(); + } +} + +QString FilterMutualInfoPlugin::pythonFilterName(ActionIDType f) const +{ + switch (f) { + case FP_IMAGE_MUTUALINFO: return "raster_alignment_mutual_information"; + default: assert(0); return QString(); } } diff --git a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h index d76ffe372..00297c442 100644 --- a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h +++ b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h @@ -44,6 +44,7 @@ public: QString pluginName() const; QString filterName(ActionIDType filter) const; + QString pythonFilterName(ActionIDType f) const; QString filterInfo(ActionIDType filter) const; FilterClass getClass(const QAction* a) const; bool requiresGLContext(const QAction* action) const; @@ -56,7 +57,6 @@ public: unsigned int& postConditionMask, vcg::CallBackPos * cb); int postCondition(const QAction*) const; - private: AlignSet align;