Several Improvements

This commit is contained in:
Paolo Cignoni cignoni 2007-08-20 09:22:47 +00:00
parent 42300dab71
commit 457eaae5f4
4 changed files with 153 additions and 175 deletions

View File

@ -1,3 +1,6 @@
#ifndef MESHCUTCURVATURE_H
#define MESHCUTCURVATURE_H
#include <vcg/container/simple_temporary_data.h>
#include <vcg/simplex/face/pos.h>
#include <vcg/simplex/face/jumping_pos.h>
@ -9,7 +12,7 @@
#include <vcg/complex/trimesh/update/normal.h>
#include <vcg/math/matrix.h>
#include <vcg/math/matrix33.h>
#include <values.h>
namespace vcg {
class CurvData {
@ -57,7 +60,7 @@ namespace vcg {
for (vi = mesh->vert.begin(); vi != mesh->vert.end(); ++vi) {
if ( ! (*vi).IsD()) {
if ( ! (*vi).IsD() && (*vi).VFp() != NULL) {
VertexType * central_vertex = &(*vi);
@ -71,13 +74,13 @@ namespace vcg {
VertexType* tempV;
float totalDoubleAreaSize = 0.0f;
/* if (((firstV->P()-central_vertex->P())^(pos.VFlip()->P()-central_vertex->P()))*central_vertex->N()<=0.0f)
if (((firstV->P()-central_vertex->P())^(pos.VFlip()->P()-central_vertex->P()))*central_vertex->N()<=0.0f)
{
pos.Set(central_vertex->VFp(), central_vertex);
pos.FlipE();
firstV = pos.VFlip();
}
else pos.Set(central_vertex->VFp(), central_vertex);*/
else pos.Set(central_vertex->VFp(), central_vertex);
do
{
@ -95,7 +98,7 @@ namespace vcg {
}
while(tempV != firstV);
for (int i = 0; i<vertices.size(); ++i) {
for (int i = 0; i < vertices.size(); ++i) {
if (vertices[i].isBorder) {
weights.push_back(vertices[i].doubleArea / totalDoubleAreaSize);
} else {
@ -186,14 +189,14 @@ namespace vcg {
c = best_c;
s = best_s;
vcg::ndim::MatrixMNf minor (2,2);
vcg::ndim::MatrixMNf minor2x2 (2,2);
vcg::ndim::MatrixMNf S (2,2);
minor[0][0] = QtMQ[1][1];
minor[0][1] = QtMQ[1][2];
minor[0][0] = QtMQ[2][1];
minor[1][1] = QtMQ[2][2];
minor2x2[0][0] = QtMQ[1][1];
minor2x2[0][1] = QtMQ[1][2];
minor2x2[1][0] = QtMQ[2][1];
minor2x2[1][1] = QtMQ[2][2];
S[0][0] = S[1][1] = c;
S[0][1] = s;
@ -202,132 +205,28 @@ namespace vcg {
vcg::ndim::MatrixMNf St (S);
St.Transpose();
vcg::ndim::MatrixMNf StMS(St * minor * S);
vcg::ndim::MatrixMNf StMS(St * minor2x2 * S);
float Principal_Curvature1 = 3.0f * StMS[0][0] - StMS[1][1];
float Principal_Curvature2 = 3.0f * StMS[1][1] - StMS[0][0];
float stms00 = StMS[0][0];
float stms01 = StMS[0][1];
float stms10 = StMS[1][0];
float stms11 = StMS[1][1];
float Principal_Curvature1 = (3.0f * StMS[0][0]) - StMS[1][1];
float Principal_Curvature2 = (3.0f * StMS[1][1]) - StMS[0][0];
Point3f Principal_Direction1 = T1 * c - T2 * s;
Point3f Principal_Direction2 = T1 * s + T2 * c;
(*TDCurvPtr)[*vi].T1 = Principal_Direction1;
(*TDCurvPtr)[*vi].T2 = Principal_Direction2;
(*TDCurvPtr)[*vi].k1 = Principal_Curvature1;
(*TDCurvPtr)[*vi].k2 = Principal_Curvature2;
}
}
}
/* OLD VERSION
void oldComputeCurvatureTensor () {
//updating per-vertex normals
vcg::tri::UpdateNormals<MESH_TYPE>::PerVertex(*mesh);
VertexIterator vi;
for (vi = mesh->vert.begin(); vi != mesh->vert.end(); ++vi) {
if (!vi->IsD() ) {
Matrix33<float> Mvi;
Mvi.SetZero();
Matrix33<float> I;
I.SetIdentity();
Matrix33<float> n_nM;
//Point3<float> normal_d = Point3<double>((double)vi->N()[0], (double)vi->N()[1],(double)vi->N()[2]);
Point3<float> normal = vi->N();
normal = normal.Normalize();
n_nM.ExternalProduct(normal, normal);
n_nM = I - n_nM;
//Inizio Calcolo dei wij per tutti i vertici adiacenti
FaceType* first_face = vi->VFp();
vcg::face::Pos<FaceType> pos2(first_face, vi->VFi(), &(*vi));
vector<float> wij_container;
float totalDoubleAreaSize = 0;
do {
float doubleArea = vcg::DoubleArea<FaceType>(*pos2.F());
totalDoubleAreaSize += doubleArea;
wij_container.push_back(doubleArea);
pos2.NextE();
} while (first_face != pos2.F());
totalDoubleAreaSize *= 2;
int last_wij = wij_container[wij_container.size()-1];
for (int i = (wij_container.size()-1); i > 0; --i) {
wij_container[i] += wij_container[i-1];
wij_container[i] /= totalDoubleAreaSize;
}
wij_container[0] += last_wij;
wij_container[0] /= totalDoubleAreaSize;
//calcola la matrice Mvi per ogni vertice
vcg::face::Pos<FaceType> pos(first_face, vi->VFi(), &(*vi));
pos.FlipV();
pos.FlipE();
int i = 0;
ComputePerVertexMatrix(*vi, *(pos.V()), Mvi, n_nM, wij_container[i]);
pos.FlipV();
pos.FlipE();
pos.FlipF();
pos.FlipE();
while (first_face != pos.F()) {
++i;
ComputePerVertexMatrix(*vi, *(pos.V()), Mvi, n_nM, wij_container[i]);
pos.FlipV();
pos.FlipE();
pos.FlipF();
pos.FlipE();
}
//Mvi matrix ready for the vertex vi
//calculate principal directions and curvature
Point3f Wvi;
Matrix33f Qvi;
Matrix33f QviT;
Matrix33f tempMatrix;
Matrix33f A;
Point3f E1(1.0,0.0,0.0);
Point3f Nvi = (*vi).N();
Nvi.Normalize();
Point3f E1nNvi = E1 - Nvi;
Point3f E1pNvi = E1 + Nvi;
if (E1nNvi.Norm() > E1pNvi.Norm() ) Wvi = E1nNvi / E1nNvi.Norm();
else Wvi = E1pNvi / E1pNvi.Norm();
tempMatrix.ExternalProduct(Wvi, Wvi);
Qvi.SetIdentity();
Qvi -= tempMatrix * 2;
QviT = Qvi;
QviT.Transpose();
A = QviT * Mvi * Qvi;
float c;
float s;
givens(A[1][1], A[2][1], &c, &s);
Point3<float> T1 = (A.GetColumn(1) * c) - (A.GetColumn(2) * s);
Point3<float> T2 = (A.GetColumn(1) * s) + (A.GetColumn(2) * c);
float k1 = 3*T1[1] - T2[2];
float k2 = 3*T2[2] - T1[1];
(*TDCurvPtr)[*vi].T1 = T1;
(*TDCurvPtr)[*vi].T2 = T2;
(*TDCurvPtr)[*vi].k1 = k1;
(*TDCurvPtr)[*vi].k2 = k2;
}
}
}
*/
};
}
#endif

View File

@ -4,11 +4,13 @@
#ifdef max
#undef max
#endif
#ifdef minor
#undef minor
#endif
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <queue>
#include <set>
#include <math.h>
#include <limits>
#include <vcg/container/simple_temporary_data.h>
@ -24,12 +26,10 @@
#include <vcg/math/histogram.h>
#include <vcg/complex/trimesh/stat.h>
namespace vcg {
enum MarkType {U, //unmarked
enum MarkType {
U, //unmarked
F, //foreground
B, //background
iF, //inputForeground
@ -51,7 +51,7 @@ namespace vcg {
template <class VERTEX_TYPE> class MinTriplet {
public:
bool operator() (const CuttingTriplet<VERTEX_TYPE> & a, const CuttingTriplet<VERTEX_TYPE> & b) const {
return (a.d > b.d);
return (a.d < b.d);
}
};
@ -73,42 +73,44 @@ namespace vcg {
SimpleTempData<VertContainer, CurvData> *TDCurvPtr;
TripletQueue Q;
set<CuttingTriplet<VertexType>, MinTriplet<VertexType> > setQ; //usato come coda principale, serve a garantire l'ordinamento e allo stesso tempo a permettere la cancellazione di elementi in ordine sparso
multimap<VertexType*,VertexType*> VertToV; //ogni vertice inserito nella coda principale ha una coppia qui che punta al vertice che ne ha provocato l'inserimento
map<VertexType*,CuttingTriplet<VertexType> > VToTriplet; //ogni vertice ha una referenza alle triplette da esso inserite
float ImprovedIsophoticDist(VertexType * p, VertexType * q) {
float dist;
double kpq = 0.0;
float kpq = 0.0f;
const float e = 2.71828182845904523536;
const float W1 = 0.1f;
const float W2 = 0.9f;
const float W1 = 5.0f;
const float W2 = 5.0f;
Matrix33<float> n_nMatrix;
Point3<float> ViVj = p->P() - q->P();
Point3<float> Tij;
Point3<float> n = p->N();
n = n.Normalize();
n_nMatrix.ExternalProduct(n, n);
Tij = (n_nMatrix * ViVj) / Norm(n_nMatrix * ViVj);
float cos = (Tij * (*TDCurvPtr)[*p].T1) / (Tij.Norm() * ((*TDCurvPtr)[*p].T1).Norm());
Tij = (n_nMatrix * ViVj).Normalize();
float cos = (Tij * (*TDCurvPtr)[*p].T1.Normalize());
cos *= cos;
//k = k1 * cos^2(@) + k2 * sin^2(@); @ = angle between T1 and direction P->Q projected onto the plane N
kpq = ((*TDCurvPtr)[*p].k1 * cos) + ((*TDCurvPtr)[*p].k2 * (1 - cos));
if (kpq < 0) {
//kpq = pow(e,fabs(kpq)) - 1; //if kpq < 0 -> kpq = (e^|kpq|) - 1
if (kpq < 0)
kpq = powf(e,fabs(kpq)) -1;
}
dist = (p->P() - q->P()).Norm() + W1 * (p->N() - q->N()).Norm() + W2 * kpq;
dist = (p->P() - q->P()).Norm() + (W1 * (p->N() - q->N()).Norm()) + (W2 * kpq);
return dist;
}
void AddNearestToQ(VertexType * v) {
void AddNearestToQ(VertexType * v, std::ofstream & file) {
float dist = 0.0f;
float min_dist = std::numeric_limits<float>::max();
@ -123,7 +125,6 @@ namespace vcg {
for (int i = 0; i < 3; ++i) {
tempV = pos.F()->V(i);
if (tempV->P() != v->P() && (*TDMarkPtr)[tempV].Mark == U) {
//dist = vcg::SquaredDistance<ScalarType>(v->P(), tempV->P());
dist = ImprovedIsophoticDist(v, tempV);
if (dist < min_dist) {
min_dist = dist;
@ -136,13 +137,17 @@ namespace vcg {
if (nearestV) {
CuttingTriplet<VertexType> tempTriplet;
tempTriplet.v = nearestV;
tempTriplet.d = ImprovedIsophoticDist(v, nearestV);
tempTriplet.d = min_dist;
switch((*TDMarkPtr)[v].Mark) {
case iF: tempTriplet.m = F; break;
case iB: tempTriplet.m = B; break;
default : tempTriplet.m = (*TDMarkPtr)[v].Mark; break;
}
Q.push(tempTriplet);
setQ.insert(tempTriplet);
VertToV.insert(make_pair(tempTriplet.v, v));
VToTriplet.insert(make_pair(v,tempTriplet));
if (file) file << "inserita tripletta con distanza: " << tempTriplet.d << std::endl;
}
}
@ -169,13 +174,13 @@ namespace vcg {
void MeshCut() {
VertexIterator vi;
int counter = 0;
int vertex_to_go = 0;
int inputCounter = 0;
for (vi=(*mesh).vert.begin(); vi!=(*mesh).vert.end(); ++vi) {
if ( !vi->IsD() && (*TDMarkPtr)[*vi].Mark != iF && (*TDMarkPtr)[*vi].Mark != iB) {
(*TDMarkPtr)[*vi].Mark = U;
++counter;
++vertex_to_go;
} else {
++inputCounter;
}
@ -184,31 +189,82 @@ namespace vcg {
//check if no input is given to prevent infinite loop.
if (!inputCounter) return;
std::ofstream file;
file.open("editsegment.log");
//Computing principal curvatures and directions for all vertices
vcg::CurvatureTensor<MESH_TYPE>ct(mesh, TDCurvPtr);
ct.ComputeCurvatureTensor();
//now each vertex has principals curvatures and directions in its temp data
if (file) file << "Inizializzazione da input." << std::endl;
while (counter != 0) {
//second iteration on the marked vertex
for (vi=(*mesh).vert.begin(); vi!=(*mesh).vert.end(); ++vi) {
if ( !vi->IsD() && ((*TDMarkPtr)[*vi].Mark != U))
AddNearestToQ(&(*vi));
}
//second iteration on the marked vertex
for (vi=(*mesh).vert.begin(); vi!=(*mesh).vert.end(); ++vi) {
if ( !vi->IsD() && ((*TDMarkPtr)[*vi].Mark != U))
AddNearestToQ(&(*vi),file);
}
if (file) file << "Fine inizializzazione da input. Elementi aggiunti: " << setQ.size() << std::endl;
while (vertex_to_go != 0) {
//algorithm main loop
CuttingTriplet<VertexType> tempTriplet;
while(!Q.empty()) {
tempTriplet = Q.top();
Q.pop();
if ( (*TDMarkPtr)[tempTriplet.v].Mark == U) {
(*TDMarkPtr)[tempTriplet.v].Mark = tempTriplet.m;
AddNearestToQ(tempTriplet.v);
--counter;
}
if (setQ.empty()) {
if (file) file << "Coda vuota. Re-Inizializzazione." << std::endl;
for (vi=(*mesh).vert.begin(); vi!=(*mesh).vert.end(); ++vi) {
if ( !vi->IsD() && ((*TDMarkPtr)[*vi].Mark != U))
AddNearestToQ(&(*vi),file);
}
if (setQ.empty()) break;
} else {
CuttingTriplet<VertexType> tempTriplet;
//prendo la tripletta con distanza minima
tempTriplet = *(setQ.begin());
assert((*TDMarkPtr)[tempTriplet.v].Mark == U);
(*TDMarkPtr)[tempTriplet.v].Mark = tempTriplet.m;
--vertex_to_go;
if (file) file << "Estratta tripletta con distanza: " << tempTriplet.d << std::endl;
//prendo tutti i vertici che avevano inserito il vertice estratto
vector<VertexType*> tempVertex;
typedef multimap<VertexType*,VertexType*>::iterator MMI;
pair<MMI,MMI> mm_range = VertToV.equal_range(tempTriplet.v);
for (MMI mm_iter = mm_range.first; mm_iter != mm_range.second; ++mm_iter) {
tempVertex.push_back(mm_iter->second);
}
VertToV.erase(tempTriplet.v);
//rimuovo dalla coda tutte le triplette che sono state inserite dai vertici presi prima
vector<VertexType*>::iterator tempV_iter;
for (tempV_iter = tempVertex.begin(); tempV_iter != tempVertex.end(); tempV_iter++) {
if (setQ.find(VToTriplet[*tempV_iter]) != setQ.end())
setQ.erase(setQ.find(VToTriplet[*tempV_iter]));
if (VToTriplet.find(*tempV_iter) != VToTriplet.end() )
VToTriplet.erase(VToTriplet.find(*tempV_iter));
}
for (tempV_iter = tempVertex.begin(); tempV_iter != tempVertex.end(); tempV_iter++) {
AddNearestToQ((*tempV_iter), file);
}
AddNearestToQ(tempTriplet.v, file);
tempVertex.clear();
}
}
VToTriplet.clear();
setQ.clear();
VertToV.clear();
if (file) file.close();
}
void Colorize(bool selectForeground) {
@ -244,7 +300,7 @@ namespace vcg {
void ColorizeCurvature(bool gaussian) {
vcg::CurvatureTensor<MESH_TYPE>ct(mesh, TDCurvPtr);
ct.ComputeCurvatureTensor();
VertexIterator vi;
if (gaussian) { //gaussian
@ -261,7 +317,22 @@ namespace vcg {
Histogramf H;
tri::Stat<CMeshO>::ComputePerVertexQualityHistogram(*mesh,H);
tri::UpdateColor<CMeshO>::VertexQuality(*mesh,H.Percentile(0.1),H.Percentile(0.9));
tri::UpdateColor<CMeshO>::VertexQuality(*mesh,H.Percentile(0.1f),H.Percentile(0.9f));
}
void Reset() {
VertexIterator vi;
for (vi = mesh->vert.begin(); vi != mesh->vert.end(); ++vi) {
(*TDMarkPtr)[*vi].Mark = U;
vi->C() = Color4b::White;
vi->Q() = 0.0f;
}
FaceIterator fi;
for (fi = mesh->face.begin(); fi != mesh->face.end(); ++fi) {
(*fi).ClearS();
}
}
};

View File

@ -229,7 +229,7 @@ Color4b toVcgColor(QColor c) {
EditSegment::EditSegment() {
actionList << new QAction(QIcon(":/images/editsegment.png"),"Mesh Segmentation", this);
pixels = 0;
pen.radius = 5;
pen.radius = 3;
pen.backface = false;
pen.invisible = false;
pressed = false;
@ -247,7 +247,7 @@ QList<QAction * > EditSegment::actions() const {
const QString EditSegment::Info(QAction *action) {
if( action->text() != tr("Mesh Segmentation") ) assert (0);
return tr("blablabla");
return tr("Segment the mesh by selecting the foreground and background");
}
const PluginInfo &EditSegment::Info() {
@ -261,7 +261,8 @@ const PluginInfo &EditSegment::Info() {
void EditSegment::StartEdit(QAction * mode, MeshModel & m, GLArea * parent) {
parent->setCursor(QCursor(QPixmap(":/images/editsegment_cursor.png","PNG"),1,1));
if (!meshCut) meshCut = new MeshCutting<CMeshO>(&m.cm);
if (!meshCut)
meshCut = new MeshCutting<CMeshO>(&m.cm);
if (!meshCutDialog) {
meshCutDialog = new MeshCutDialog(parent->window());
@ -275,6 +276,7 @@ void EditSegment::StartEdit(QAction * mode, MeshModel & m, GLArea * parent) {
QObject::connect(meshCutDialog, SIGNAL(meshCutSignal()),this, SLOT(MeshCutSlot()));
QObject::connect(meshCutDialog, SIGNAL(selectForegroundSignal(bool)),this, SLOT(SelectForegroundSlot(bool)));
QObject::connect(meshCutDialog, SIGNAL(resetSignal()),this,SLOT(ResetSlot()));
QObject::connect(meshCutDialog, SIGNAL(colorizeGaussianSignal()),this, SLOT(ColorizeGaussianSlot()));
QObject::connect(meshCutDialog, SIGNAL(colorizeMeanSignal()),this, SLOT(ColorizeMeanSlot()));
@ -317,15 +319,13 @@ void EditSegment::Decorate (QAction * ac, MeshModel & m, GLArea * gla) {
getInternFaces(m,&currentSelection,&newSel,&faceSel,gla,pen,current_point,previous_point,pixels,mvmatrix,projmatrix,viewport);
vector<CMeshO::FacePointer>::iterator fpo;
bool sel_or_not=(mouse_button_pressed==Qt::LeftButton);
for(fpo=faceSel.begin();fpo!=faceSel.end();++fpo) {
for (int i=0; i<3; ++i) {
if (sel_or_not) {
if (mouse_button_pressed==Qt::LeftButton) {
meshCut->Mark((*fpo)->V(i), iF);
(*fpo)->V(i)->C() = toVcgColor(meshCutDialog->getForegroundColor());
//(*fpo)->SetS();
} else {
//(*fpo)->ClearS();
meshCut->Mark((*fpo)->V(i), iB);
(*fpo)->V(i)->C() = toVcgColor(meshCutDialog->getBackgroundColor());
}
@ -429,4 +429,11 @@ void EditSegment::ColorizeMeanSlot() {
}
}
void EditSegment::ResetSlot() {
if (meshCut) {
meshCut->Reset();
glarea->update();
}
}
Q_EXPORT_PLUGIN(EditSegment)

View File

@ -84,6 +84,7 @@ public slots:
void ColorizeGaussianSlot();
void ColorizeMeanSlot();
void ResetSlot();
};