Improved a bit the 4pcs autoalignment filter

This commit is contained in:
Paolo Cignoni cignoni 2014-05-23 12:37:28 +00:00
parent 122a528c73
commit e68ee1e068
2 changed files with 105 additions and 66 deletions

View File

@ -11,21 +11,21 @@
* *
****************************************************************************/
#include "filter_autoalign.h"
#include <vcg/complex/algorithms/autoalign_4pcs.h>
#include "../../meshlabplugins/edit_align/align/Guess.h"
using namespace vcg;
using namespace std;
// Constructor usually performs only two simple tasks of filling the two lists
// - typeList: with all the possible id of the filtering actions
// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly
FilterAutoalign::FilterAutoalign()
{
typeList << FP_AUTOALIGN
//<< FP_BEST_ROTATION
typeList << FP_ALIGN_4PCS
<< FP_BEST_ROTATION
;
foreach(FilterIDType tt , types())
@ -37,8 +37,8 @@ FilterAutoalign::FilterAutoalign()
QString FilterAutoalign::filterName(FilterIDType filterId) const
{
switch(filterId) {
case FP_AUTOALIGN : return QString("Automatic pair Alignement");
case FP_BEST_ROTATION : return QString("Automatic Alignement (Brute)");
case FP_ALIGN_4PCS : return QString("Automatic Rough Alignement (4PCS)");
case FP_BEST_ROTATION : return QString("Automatic Rough Alignement (Brute Force)");
default : assert(0);
}
}
@ -48,7 +48,7 @@ QString FilterAutoalign::filterName(FilterIDType filterId) const
QString FilterAutoalign::filterInfo(FilterIDType filterId) const
{
switch(filterId) {
case FP_AUTOALIGN : return QString("Automatic Rough Alignment of two meshes. Based on the paper <b> 4-Points Congruent Sets for Robust Pairwise Surface Registration</b>, by Aiger,Mitra, Cohen-Or. Siggraph 2008 ");
case FP_ALIGN_4PCS : return QString("Automatic Rough Alignment of two meshes. Based on the paper <b> 4-Points Congruent Sets for Robust Pairwise Surface Registration</b>, by Aiger,Mitra, Cohen-Or. Siggraph 2008 ");
case FP_BEST_ROTATION : return QString("Automatic Rough Alignment of two meshes. Brute Force Approach");
default : assert(0);
}
@ -65,29 +65,35 @@ void FilterAutoalign::initParameterSet(QAction *action,MeshDocument & md/*m*/, R
{
MeshModel *target;
switch(ID(action)) {
case FP_AUTOALIGN :
case FP_ALIGN_4PCS :
target= md.mm();
foreach (target, md.meshList)
if (target != md.mm()) break;
parlst.addParam(new RichMesh ("FirstMesh", md.mm(),&md, "First Mesh",
parlst.addParam(new RichMesh ("fixMesh", md.mm(),&md, "Fixed Mesh",
"The mesh were the coplanar bases are sampled (it will contain the trasformation)"));
parlst.addParam(new RichMesh ("SecondMesh", target,&md, "Second Mesh",
parlst.addParam(new RichMesh ("movMesh", target,&md, "Moving Mesh",
"The mesh were similar coplanar based are searched."));
parlst.addParam(new RichFloat("overlapping",0.5f,"Estimated fraction of the\n first mesh overlapped by the second"));
parlst.addParam(new RichFloat("tolerance [0.0,1.0]",0.3f,"Error tolerance"));
parlst.addParam(new RichFloat("overlap",0.5f,"Overlap %","Estimated fraction of the\n first mesh overlapped by the second"));
parlst.addParam(new RichInt("sampleNum",1000,"Sample Num"));
parlst.addParam(new RichFloat("tolerance",0.3f,"Error tolerance",""));
parlst.addParam(new RichBool("showSample",true,"show subsamples",""));
parlst.addParam(new RichInt("randSeed",0,"Random Seed","0 means the random generator it is intializised with internal clock to guarantee different result every time"));
break;
case FP_BEST_ROTATION :
target= md.mm();
foreach (target, md.meshList)
if (target != md.mm()) break;
parlst.addParam(new RichMesh ("FirstMesh", md.mm(),&md, "First Mesh",
parlst.addParam(new RichMesh ("fixMesh", md.mm(),&md, "Fix Mesh",
"The mesh that will be moved"));
parlst.addParam(new RichMesh ("SecondMesh", target,&md, "Second Mesh",
parlst.addParam(new RichMesh ("movMesh", target,&md, "Mov Mesh",
"The mesh that will be kept fixed."));
parlst.addParam(new RichInt("GridSize",10,"Grid Size", "The size of the uniform grid that is used for searching the best translation for a given rotation"));
parlst.addParam(new RichInt("Rotation Num",64,"RotationNumber", "sss"));
parlst.addParam(new RichInt("searchRange",6,"Search Range", "The size of the uniform grid that is used for searching the best translation for a given rotation"));
parlst.addParam(new RichInt("sampleSize",5000,"Sample Size", "The size of the uniform grid that is used for searching the best translation for a given rotation"));
parlst.addParam(new RichInt("gridSize",100000,"Grid Size", "The size of the uniform grid that is used for searching the best translation for a given rotation"));
parlst.addParam(new RichInt("RotationNumber",64,"Rotation Number", "sss"));
break;
default: break; // do not add any parameter for the other filters
@ -97,56 +103,91 @@ void FilterAutoalign::initParameterSet(QAction *action,MeshDocument & md/*m*/, R
// The Real Core Function doing the actual mesh processing.
bool FilterAutoalign::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb)
{
vcg::tri::FourPCS<CMeshO> *fpcs ;
switch(ID(filter)) {
case FP_AUTOALIGN :
case FP_ALIGN_4PCS :
{
MeshModel *fixMesh= par.getMesh("fixMesh");
MeshModel *movMesh= par.getMesh("movMesh");
MeshModel *sampleMesh= 0;
bool showSample = par.getBool("showSample");
if(showSample) sampleMesh = md.addOrGetMesh("sample","sample",false, RenderMode(vcg::GLW::DMPoints));
tri::UpdateNormal<CMeshO>::NormalizePerVertex(fixMesh->cm);
tri::UpdateNormal<CMeshO>::NormalizePerVertex(movMesh->cm);
tri::Clean<CMeshO>::RemoveUnreferencedVertex(fixMesh->cm);
tri::Clean<CMeshO>::RemoveUnreferencedVertex(movMesh->cm);
tri::Allocator<CMeshO>::CompactEveryVector(fixMesh->cm);
tri::Allocator<CMeshO>::CompactEveryVector(movMesh->cm);
fixMesh->updateDataMask(MeshModel::MM_VERTMARK);
movMesh->updateDataMask(MeshModel::MM_VERTMARK);
MeshModel *firstMesh= par.getMesh("FirstMesh");
MeshModel *secondMesh= par.getMesh("SecondMesh");
vcg::tri::FourPCS<CMeshO> fpcs;
fpcs.par.Default();
fpcs.par.f = par.getFloat("overlapping");
firstMesh->updateDataMask(MeshModel::MM_VERTMARK);
secondMesh->updateDataMask(MeshModel::MM_VERTMARK);
fpcs.Init(firstMesh->cm,secondMesh->cm);
bool res = fpcs.Align(0,firstMesh->cm.Tr,cb);
firstMesh->clearDataMask(MeshModel::MM_VERTMARK);
secondMesh->clearDataMask(MeshModel::MM_VERTMARK);
fpcs.par.overlap = par.getFloat("overlap");
fpcs.par.sampleNumP = par.getInt("sampleNum");
fpcs.par.deltaPerc = par.getFloat("tolerance");
fpcs.par.seed = par.getInt("randSeed");
fpcs.Init(movMesh->cm,fixMesh->cm);
Matrix44f Tr;
bool res = fpcs.Align(Tr,cb);
if(res) Log("Automatic Rough Alignment Done");
else Log("Automatic Rough Alignment Failed");
if(res)
{
Log("4PCS Completed, radius %f",fpcs.par.samplingRadius);
Log("Tested %i candidate, best score was %i\n",fpcs.U.size(),fpcs.U[fpcs.iwinner].score);
Log("Estimated overlap is now %f \n",fpcs.par.overlap);
Log("Init %5.0f Coplanar Search %5.0f",fpcs.stat.init(),fpcs.stat.select());
Log("findCongruent %5.0f testAlignment %5.0f",fpcs.stat.findCongruent(),fpcs.stat.testAlignment());
movMesh->cm.Tr = Tr;
if(showSample)
{
sampleMesh->cm.Clear();
for(int i=0;i<fpcs.subsetQ.size();++i)
tri::Allocator<CMeshO>::AddVertex(sampleMesh->cm, fpcs.subsetQ[i]->P(), fpcs.subsetQ[i]->N());
tri::UpdateBounding<CMeshO>::Box(sampleMesh->cm);
}
}
else Log("4PCS Failed");
} break;
case FP_BEST_ROTATION :
{
MeshModel *firstMesh= par.getMesh("FirstMesh");
MeshModel *secondMesh= par.getMesh("SecondMesh");
MeshModel *fixMesh= par.getMesh("fixMesh");
MeshModel *movMesh= par.getMesh("movMesh");
int searchRange = par.getInt("searchRange");
int rotNum = par.getInt("RotationNumber");
int gridSize = par.getInt("gridSize");
int sampleSize = par.getInt("sampleSize");
MeshModel *sample=md.addOrGetMesh("sample", "sample",false);
MeshModel *occ=md.addOrGetMesh("occ", "occ",false);
tri::Guess GG;
GG.pp.MatrixNum = 100;
GG.GenRotMatrix();
GG.Init<CMeshO>(firstMesh->cm, secondMesh->cm);
static int counterMV=0;
static int step=0;
//for(int i=0;i<GG.MV.size();++i)
int i=counterMV;
step = (step +1)%4;
// if(step==0) counterMV++;
std::vector<tri::Guess::Result> ResultVec;
GG.pp.MatrixNum = rotNum;
GG.pp.GridSize =gridSize;
GG.pp.SampleNum = sampleSize;
GG.Init<CMeshO>(fixMesh->cm, movMesh->cm);
qDebug("Counter %i step %i",counterMV,step);
{
Point3f baseTran = GG.InitBaseTranslation(GG.MV[i]);
Point3f bestTran;
for(int i=0;i<GG.RotMVec.size();++i)
{
Point3f baseTran = GG.ComputeBaseTranslation(GG.RotMVec[i]);
Point3f bestTran;
int res = GG.SearchBestTranslation(GG.u[0],GG.RotMVec[i],searchRange,baseTran,bestTran);
ResultVec.push_back(tri::Guess::Result(GG.BuildResult(GG.RotMVec[i],baseTran,bestTran), res, i, bestTran));
}
sort(ResultVec.begin(),ResultVec.end());
movMesh->cm.Tr = ResultVec.back().m;
int res = GG.SearchBestTranslation(GG.u[0],GG.MV[i],4,1,baseTran,bestTran);
if(step==0) firstMesh->cm.Tr.SetIdentity();
if(step==1) firstMesh->cm.Tr = GG.MV[i];
if(step==2) firstMesh->cm.Tr = GG.BuildTransformation(GG.MV[i],baseTran);
if(step==3) firstMesh->cm.Tr = GG.BuildTransformation(GG.MV[i],bestTran);
}
//Log(0,(res)?" Automatic Rough Alignment Done":"Automatic Rough Alignment Failed");
tri::Build(sample->cm,GG.movVertBase);
sample->cm.Tr = ResultVec.back().m;
qDebug("Result %i",ResultVec.back().score);
GG.GenerateOccupancyMesh(occ->cm,0,ResultVec.back().m);
occ->UpdateBoxAndNormals();
Log("Automatic Rough Alignment Tested %i rotations, best err was %i",GG.RotMVec.size(), ResultVec.back().score);
} break;
default: assert (0);
}
@ -157,7 +198,7 @@ FilterAutoalign::FilterClass FilterAutoalign::getClass(QAction *a)
{
switch(ID(a))
{
case FP_AUTOALIGN :
case FP_ALIGN_4PCS :
case FP_BEST_ROTATION :
return FilterClass(MeshFilterInterface::Layer+MeshFilterInterface::RangeMap);
default :

View File

@ -8,7 +8,7 @@
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* 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. *
@ -24,29 +24,27 @@
#ifndef SAMPLEFILTERSPLUGIN_H
#define SAMPLEFILTERSPLUGIN_H
#include <QObject>
#include <common/interfaces.h>
class FilterAutoalign : public QObject, public MeshFilterInterface
{
Q_OBJECT
MESHLAB_PLUGIN_IID_EXPORTER(MESH_FILTER_INTERFACE_IID)
Q_INTERFACES(MeshFilterInterface)
Q_OBJECT
MESHLAB_PLUGIN_IID_EXPORTER(MESH_FILTER_INTERFACE_IID)
Q_INTERFACES(MeshFilterInterface)
public:
enum {
FP_AUTOALIGN,
FP_BEST_ROTATION
} ;
public:
enum {
FP_ALIGN_4PCS,
FP_BEST_ROTATION
};
FilterAutoalign();
FilterAutoalign();
virtual QString filterName(FilterIDType filter) const;
virtual QString filterInfo(FilterIDType filter) const;
virtual FilterClass getClass(QAction *);
virtual void initParameterSet(QAction *,MeshDocument &/*m*/, RichParameterSet & /*parent*/);
virtual bool applyFilter(QAction *filter, MeshDocument &m, RichParameterSet & /*parent*/, vcg::CallBackPos * cb) ;
virtual void initParameterSet(QAction *,MeshDocument &/*m*/, RichParameterSet & /*parent*/);
virtual bool applyFilter(QAction *filter, MeshDocument &m, RichParameterSet & /*parent*/, vcg::CallBackPos * cb) ;
};
#endif