/**************************************************************************** * MeshLab o o * * An extendible mesh processor o o * * _ O _ * * Copyright(C) 2005, 2006 \/)\/ * * 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. * * * ****************************************************************************/ /**************************************************************************** History $Log$ Revision 1.3 2006/11/29 00:59:16 cignoni Cleaned plugins interface; changed useless help class into a plain string Revision 1.2 2006/11/08 15:49:42 cignoni Added quality to the loaded masks Revision 1.1 2006/11/07 18:14:21 cignoni Moved from the epoch svn repository Revision 1.1 2006/01/20 13:03:27 cignoni *** empty log message *** *****************************************************************************/ #include #include #include #include #include // temporaneamente prendo la versione corrente dalla cartella test #include #include #include #include #include #include #include #include #include #include #include #include "epoch_io.h" #include "epoch_reconstruction.h" #include "../cleanfilter/remove_small_cc.h" using namespace vcg; bool EpochModel::CombineMaskAndQuality(CharImage &qualityImg, QString maskName ) { QImage maskImg(maskName); if(maskImg.isNull()) return false; if(maskImg.width()!= qualityImg.w) return false; if(maskImg.height()!= qualityImg.h) return false; for(int j=0;j128) qualityImg.Val(i,j)=0; } void EpochModel::SmartSubSample(int factor, FloatImage &fli, CharImage &chi, FloatImage &subD, FloatImage &subQ, int minCount) { assert(fli.w==chi.w && fli.h==chi.h); int w=fli.w/factor; int h=fli.h/factor; subQ.resize(w,h); subD.resize(w,h); for(int i=0;i0) { maxcount+= q; bestVal +=q*fli.Val(i*factor+ki,j*factor+kj); cnt++; } } if(cnt>0) { subD.Val(i,j)=float(bestVal)/maxcount; subQ.Val(i,j)=minCount-1 + float(maxcount)/cnt ; } else { subD.Val(i,j)=0; subQ.Val(i,j)=0; } } } void EpochModel::Laplacian(FloatImage &depth, CharImage &mask) { FloatImage Sum; int w=depth.w,h=depth.h; Sum.resize(w,h); for(int x=1;x0) { Sum.Val(x,y)+=q*depth.Val(x+i,y+j); cnt+=q; } } if(cnt>0) { Sum.Val(x,y)/=cnt; } else Sum.Val(x,y)=depth.Val(x,y); } for(int x=1;x(m,flisub.w,flisub.h,fli.w,fli.h,&*flisub.v.begin()); for(int i=0;iIsD() ||(*fi).V(1)->IsD() ||(*fi).V(2)->IsD() ) { (*fi).SetD(); --m.fn; } else { Point3f n=vcg::Normal(*fi); n.Normalize(); Point3f dir=Point3f::Construct(cam.t)-vcg::Barycenter(*fi); dir.Normalize(); if(dir*n < minAngleCos) { (*fi).SetD(); --m.fn; } } } // Matrix44d Rot; // Rot.SetRotate(M_PI,Point3d(1,0,0)); // vcg::tri::UpdatePosition::Matrix(m, Rot); return true; } void EpochModel::AddCameraIcon(CMeshO &m) { tri::Allocator::AddVertices(m,3); m.vert[m.vert.size()-3].P()=Point3f::Construct(cam.t+Point3d(0,0,0)); m.vert[m.vert.size()-3].C()=Color4b::Green; m.vert[m.vert.size()-2].P()=Point3f::Construct(cam.t+Point3d(0,1,0)); m.vert[m.vert.size()-2].C()=Color4b::Green; m.vert[m.vert.size()-1].P()=Point3f::Construct(cam.t+Point3d(1,0,0)); m.vert[m.vert.size()-1].C()=Color4b::Green; tri::Allocator::AddFaces(m,1); m.face[m.face.size()-1].V(0)= &m.vert[m.vert.size()-3]; m.face[m.face.size()-1].V(1)= &m.vert[m.vert.size()-2]; m.face[m.face.size()-1].V(2)= &m.vert[m.vert.size()-1]; } bool EpochModel::Init(QDomNode &node) { if(!node.hasAttributes()) return false; QDomNamedNodeMap attr= node.attributes(); QString indexString = (attr.namedItem("index")).nodeValue() ; qDebug("reading Model with index %i ",indexString.toInt()); for(QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) { if(n.nodeName() == QString("camera")) cameraName = n.attributes().namedItem("filename").nodeValue(); if(n.nodeName() == QString("texture")) textureName= n.attributes().namedItem("filename").nodeValue(); if(n.nodeName() == QString("depth")) depthName = n.attributes().namedItem("filename").nodeValue(); if(n.nodeName() == QString("count")) countName = n.attributes().namedItem("filename").nodeValue(); } QString tmpName=textureName.left(textureName.length()-4); maskName = tmpName.append(".mask.png"); return true; } QString EpochModel::ThumbName(QString &imageName) { QString tmpName=imageName.left(imageName.length()-4); return tmpName.append(".thumb.jpg"); } EpochIO::EpochIO() { epochDialog = new v3dImportDialog(); epochDialog->hide(); } EpochIO::~EpochIO() { delete epochDialog; } bool EpochIO::open(const QString &formatName, QString &fileName, MeshModel &m, int& mask, CallBackPos *cb, QWidget *parent) { EpochReconstruction er; mask = MeshModel::IOM_VERTCOLOR | MeshModel::IOM_VERTQUALITY; // just to be sure... if (fileName.isEmpty()) return false; // initializing progress bar status if (cb != NULL) (*cb)(0, "Loading..."); // this change of dir is needed for subsequent texture/material loading QString FileNameDir = fileName.left(fileName.lastIndexOf("/")); QDir::setCurrent(FileNameDir); QString errorMsgFormat = "Error encountered while loading file %1:\n%2"; string filename = fileName.toUtf8().data(); QDomDocument doc; if(formatName.toUpper() == tr("V3D") && fileName.endsWith(".v3d")) { QFile file(fileName); if (file.open(QIODevice::ReadOnly) && doc.setContent(&file)) { file.close(); QDomElement root = doc.documentElement(); if (root.nodeName() == tr("reconstruction")) { QDomNode nhead = root.firstChildElement("head"); for(QDomNode n = nhead.firstChildElement("meta"); !n.isNull(); n = n.nextSiblingElement("meta")) { if(!n.hasAttributes()) return false; QDomNamedNodeMap attr= n.attributes(); if(attr.contains("name")) er.name = (attr.namedItem("name")).nodeValue() ; if(attr.contains("author")) er.author = (attr.namedItem("author")).nodeValue() ; if(attr.contains("created")) er.created = (attr.namedItem("created")).nodeValue() ; } for(QDomNode n = root.firstChildElement("model"); !n.isNull(); n = n.nextSiblingElement("model")) { EpochModel em; em.Init(n); er.modelList.push_back(em); } } } } epochDialog->setEpochReconstruction( &er, cb); //Here we invoke the modal dialog and wait for its termination int continueValue = epochDialog->exec(); int subSampleVal = epochDialog->subsampleSpinBox->value(); int minCountVal= epochDialog->minCountSpinBox->value(); float maxCCDiagVal= epochDialog->maxCCDiagSpinBox->value(); int mergeResolution=epochDialog->mergeResolutionSpinBox->value(); int smoothSteps=epochDialog->smoothSpinBox->value(); bool closeHole = epochDialog->holeCheckBox->isChecked(); int maxHoleSize = epochDialog->holeSpinBox->value(); if (continueValue == QDialog::Rejected) { QMessageBox::warning(parent, "Open V3d format","Aborted"); return false; } CMeshO mm; QTableWidget *qtw=epochDialog->imageTableWidget; float MinAngleCos=cos(vcg::math::ToRad(epochDialog->qualitySpinBox->value())); bool clustering=epochDialog->fastMergeCheckBox->isChecked(); bool removeSmallCC=epochDialog->removeSmallCCCheckBox->isChecked(); vcg::tri::Clustering > Grid; int selectedNum=0,selectedCount=0; int i; for(i=0;irowCount();++i) if(qtw->isItemSelected(qtw->item(i,0))) ++selectedNum; if(selectedNum==0) { QMessageBox::warning(parent, "Open V3d format","No range map selected. Nothing loaded"); return false; } bool firstTime=true; QList::iterator li; for(li=er.modelList.begin(), i=0;li!=er.modelList.end();++li,++i) { if(qtw->isItemSelected(qtw->item(i,0))) { ++selectedCount; mm.Clear(); (*li).BuildMesh(mm,subSampleVal,minCountVal,MinAngleCos,smoothSteps); if(clustering) { if (firstTime) { //Grid.Init(mm.bbox,100000); vcg::tri::UpdateBounding::Box(mm); //Grid.Init(mm.bbox,1000.0*pow(10.0,mergeResolution),mm.bbox.Diag()/1000.0f); Grid.Init(mm.bbox,100000.0*pow(10.0,mergeResolution)); firstTime=false; } Grid.Add(mm); } else tri::Append::Mesh(m.cm,mm); // append mesh mr to ml } if (cb)(*cb)(selectedCount*90/selectedNum, "Building meshes"); } if (cb != NULL) (*cb)(90, "Final Processing: clustering"); if(clustering) { Grid.Extract(m.cm); } if (cb != NULL) (*cb)(95, "Final Processing: Removing Small Connected Components"); if(removeSmallCC) { vcg::tri::UpdateBounding::Box(m.cm); // updates bounding box m.updateDataMask(MeshModel::MM_FACETOPO | MeshModel::MM_BORDERFLAG | MeshModel::MM_FACEMARK); RemoveSmallConnectedComponentsDiameter(m.cm,m.cm.bbox.Diag()*maxCCDiagVal/100.0); } vcg::tri::UpdateBounding::Box(m.cm); // updates bounding box if (cb != NULL) (*cb)(97, "Final Processing: Closing Holes"); if(closeHole) { tri::UpdateTopology::FaceFace(m.cm); tri::UpdateNormals::PerVertexNormalizedPerFace(m.cm); tri::holeFillingEar > (m.cm,maxHoleSize,false); tri::UpdateNormals::PerVertexNormalizedPerFace(m.cm); tri::UpdateTopology::FaceFace(m.cm); } if (cb != NULL) (*cb)(100, "Done"); vcg::tri::UpdateNormals::PerVertex(m.cm); // updates normals return true; } bool EpochIO::save(const QString &/*formatName*/,QString &/*fileName*/, MeshModel &/*m*/, const int &/*mask*/, vcg::CallBackPos * /*cb*/, QWidget *parent) { QMessageBox::warning(parent, "Unknow type", "file's extension not supported!!!"); return false; } QList EpochIO::importFormats() const { QList formatList; formatList << Format("Epoch Reconstructed mesh","V3D"); return formatList; }; const PluginInfo &EpochIO::Info() { static PluginInfo ai; ai.Date=tr("March 2006"); ai.Version = tr("0.1"); ai.Author = ("Paolo Cignoni"); return ai; } QIcon *EpochModel::getIcon() { QString iconName(textureName); iconName+=QString(".xbm"); QIcon *ico=new QIcon(); return ico; } Q_EXPORT_PLUGIN(EpochIO)