From 810e38942fb3473cc3edb77f2df0d2071e3ffc0c Mon Sep 17 00:00:00 2001 From: Matteo Dellepiane matteodelle Date: Tue, 31 Jan 2012 16:52:39 +0000 Subject: [PATCH] dellepiane: porting of arc3D filter to edit --- .../edit_epoch/edit_epoch.cpp | 376 +++++++++ .../edit_epoch/edit_epoch.h | 102 +++ .../edit_epoch/edit_epoch.pro | 50 ++ .../edit_epoch/edit_epoch.qrc | 8 + .../edit_epoch/edit_epoch_factory.cpp | 57 ++ .../edit_epoch/edit_epoch_factory.h | 55 ++ .../edit_epoch/epoch_camera.cpp | 111 +++ .../edit_epoch/epoch_camera.h | 46 ++ .../edit_epoch/epoch_io.cpp | 739 ++++++++++++++++++ .../edit_epoch/epoch_io.h | 69 ++ .../edit_epoch/epoch_reconstruction.h | 72 ++ .../edit_epoch/fillImage.cpp | 127 +++ .../edit_epoch/fillImage.h | 117 +++ .../edit_epoch/images/cur_align.png | Bin 0 -> 291 bytes .../edit_epoch/images/icon_align.png | Bin 0 -> 4870 bytes .../edit_epoch/images/icon_align.svg | 85 ++ .../edit_epoch/images/icon_arc3d.png | Bin 0 -> 6786 bytes .../edit_epoch/maskImageWidget.cpp | 333 ++++++++ .../edit_epoch/maskImageWidget.h | 76 ++ .../edit_epoch/maskRenderWidget.cpp | 385 +++++++++ .../edit_epoch/maskRenderWidget.h | 125 +++ .../edit_epoch/radial_distortion.cpp | 109 +++ .../edit_epoch/radial_distortion.h | 60 ++ .../edit_epoch/reconstruction.cpp | 195 +++++ .../edit_epoch/resource.h | 16 + .../edit_epoch/resource1.h | 16 + .../edit_epoch/scalar_image.cpp | 195 +++++ .../edit_epoch/scalar_image.h | 150 ++++ .../edit_epoch/ui/v3dImportDialog.ui | 678 ++++++++++++++++ .../edit_epoch/ui_v3dImportDialog.h | 555 +++++++++++++ .../edit_epoch/v3dImportDialog.cpp | 246 ++++++ .../edit_epoch/v3dImportDialog.h | 81 ++ 32 files changed, 5234 insertions(+) create mode 100644 src/plugins_experimental/edit_epoch/edit_epoch.cpp create mode 100644 src/plugins_experimental/edit_epoch/edit_epoch.h create mode 100644 src/plugins_experimental/edit_epoch/edit_epoch.pro create mode 100644 src/plugins_experimental/edit_epoch/edit_epoch.qrc create mode 100644 src/plugins_experimental/edit_epoch/edit_epoch_factory.cpp create mode 100644 src/plugins_experimental/edit_epoch/edit_epoch_factory.h create mode 100644 src/plugins_experimental/edit_epoch/epoch_camera.cpp create mode 100644 src/plugins_experimental/edit_epoch/epoch_camera.h create mode 100644 src/plugins_experimental/edit_epoch/epoch_io.cpp create mode 100644 src/plugins_experimental/edit_epoch/epoch_io.h create mode 100644 src/plugins_experimental/edit_epoch/epoch_reconstruction.h create mode 100644 src/plugins_experimental/edit_epoch/fillImage.cpp create mode 100644 src/plugins_experimental/edit_epoch/fillImage.h create mode 100644 src/plugins_experimental/edit_epoch/images/cur_align.png create mode 100644 src/plugins_experimental/edit_epoch/images/icon_align.png create mode 100644 src/plugins_experimental/edit_epoch/images/icon_align.svg create mode 100644 src/plugins_experimental/edit_epoch/images/icon_arc3d.png create mode 100644 src/plugins_experimental/edit_epoch/maskImageWidget.cpp create mode 100644 src/plugins_experimental/edit_epoch/maskImageWidget.h create mode 100644 src/plugins_experimental/edit_epoch/maskRenderWidget.cpp create mode 100644 src/plugins_experimental/edit_epoch/maskRenderWidget.h create mode 100644 src/plugins_experimental/edit_epoch/radial_distortion.cpp create mode 100644 src/plugins_experimental/edit_epoch/radial_distortion.h create mode 100644 src/plugins_experimental/edit_epoch/reconstruction.cpp create mode 100644 src/plugins_experimental/edit_epoch/resource.h create mode 100644 src/plugins_experimental/edit_epoch/resource1.h create mode 100644 src/plugins_experimental/edit_epoch/scalar_image.cpp create mode 100644 src/plugins_experimental/edit_epoch/scalar_image.h create mode 100644 src/plugins_experimental/edit_epoch/ui/v3dImportDialog.ui create mode 100644 src/plugins_experimental/edit_epoch/ui_v3dImportDialog.h create mode 100644 src/plugins_experimental/edit_epoch/v3dImportDialog.cpp create mode 100644 src/plugins_experimental/edit_epoch/v3dImportDialog.h diff --git a/src/plugins_experimental/edit_epoch/edit_epoch.cpp b/src/plugins_experimental/edit_epoch/edit_epoch.cpp new file mode 100644 index 000000000..56a085c4d --- /dev/null +++ b/src/plugins_experimental/edit_epoch/edit_epoch.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** + * 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. * + * * + ****************************************************************************/ +/**************************************************************************** + History +$Log: meshedit.cpp,v $ +****************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "edit_epoch.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace vcg; +FILE *logFP=0; + +EditEpochPlugin::EditEpochPlugin() { + epochDialog = new v3dImportDialog(); + epochDialog->hide(); + qFont.setFamily("Helvetica"); + qFont.setPixelSize(10); + + + + + +} + +const QString EditEpochPlugin::Info() +{ + return tr("Culo."); +} + +void EditEpochPlugin::Decorate(MeshModel &m, GLArea * gla) +{ + +} + +bool EditEpochPlugin::StartEdit(MeshDocument &_md, GLArea *_gla ) +{ + /////// + + MeshModel *m;// = md->mm(); + EpochReconstruction er; + + QString fileName=epochDialog->fileName; + + 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 stdfilename = QFile::encodeName(fileName).constData (); + //string filename = fileName.toUtf8().data(); + + QDomDocument doc; + + + 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); + + //connect(epochDialog, SIGNAL(closing()),gla,SLOT(endEdit()) ); + + int continueValue = epochDialog->exec(); + //// OK till here + + epochDialog->exportToPLY=false; + // do + //{ + // epochDialog->exportToPLY=false; + // + // //Here we invoke the modal dialog and wait for its termination + // int continueValue = epochDialog->exec(); + + // // The user has pressed the ok button: now start the real processing: + // + // if(epochDialog->exportToPLY == true) qDebug("Starting the ply exporting process"); + // + // int t0=clock(); + // logFP=fopen("epoch.log","w"); + + // 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 dilationFlag = epochDialog->dilationCheckBox->isChecked(); + // int dilationN = epochDialog->dilationNumPassSpinBox->value(); + // int dilationSz = epochDialog->dilationSizeSlider->value() * 2 + 1; + // bool erosionFlag = epochDialog->erosionCheckBox->isChecked(); + // int erosionN = epochDialog->erosionNumPassSpinBox->value(); + // int erosionSz = epochDialog->erosionSizeSlider->value() * 2 + 1; + // float scalingFactor = epochDialog->scaleLineEdit->text().toFloat(); + // std::vector savedMeshVector; + + // 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(); + // int tt0=clock(); + // (*li).BuildMesh(mm,subSampleVal,minCountVal,MinAngleCos,smoothSteps, + // dilationFlag, dilationN, dilationSz, erosionFlag, erosionN, erosionSz,scalingFactor); + // int tt1=clock(); + // if(logFP) fprintf(logFP,"** Mesh %i : Build in %i\n",selectedCount,tt1-tt0); + + // if(epochDialog->exportToPLY) + // { + // QString plyFilename =(*li).textureName.left((*li).textureName.length()-4); + // plyFilename.append(".x.ply"); + // savedMeshVector.push_back(qPrintable(plyFilename)); + // int mask= tri::io::Mask::IOM_VERTCOORD + tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY; + // tri::io::ExporterPLY::Save(mm,qPrintable(plyFilename),mask); + // } + // else + // { + // 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.AddMesh(mm); + // } + // else + // tri::Append::Mesh(m->cm,mm); // append mesh mr to ml + // } + // int tt2=clock(); + // if(logFP) fprintf(logFP,"** Mesh %i : Append in %i\n",selectedCount,tt2-tt1); + + // } + // //if (cb)(*cb)(selectedCount*90/selectedNum, "Building meshes"); + // } + // + // //if (cb != NULL) (*cb)(90, "Final Processing: clustering"); + // if(clustering) + // { + // Grid.ExtractPointSet(m->cm); + // } + // + // if(epochDialog->exportToPLY) + // { + // QString ALNfilename = fileName.left(fileName.length()-4).append(".aln"); + // ALNParser::SaveALN(qPrintable(ALNfilename), savedMeshVector); + // } + // int t1=clock(); + // if(logFP) fprintf(logFP,"Extracted %i meshes in %i\n",selectedCount,t1-t0); + + // //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_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK); + // tri::Clean::RemoveSmallConnectedComponentsDiameter(m->cm,m->cm.bbox.Diag()*maxCCDiagVal/100.0); + // } + + // int t2=clock(); + // if(logFP) fprintf(logFP,"Topology and removed CC in %i\n",t2-t1); + + // vcg::tri::UpdateBounding::Box(m->cm); // updates bounding box + // + // //if (cb != NULL) (*cb)(97, "Final Processing: Closing Holes"); + // if(closeHole) + // { + // m->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK); + // tri::UpdateNormals::PerVertexNormalizedPerFace(m->cm); + // vcg::tri::Hole::EarCuttingFill >(m->cm,maxHoleSize,false); + // } + + // //if (cb != NULL) (*cb)(100, "Done"); + // // vcg::tri::UpdateNormals::PerVertex(m.cm); // updates normals + // + // m->updateDataMask(MeshModel::MM_VERTCOLOR); + + // int t3=clock(); + // if(logFP) fprintf(logFP,"---------- Total Processing Time%i\n\n\n",t3-t0); + // if(logFP) fclose(logFP); + // logFP=0; + + + ////// Importing rasters + + // //QList::iterator li; + // for(li=er.modelList.begin(), i=0;li!=er.modelList.end();++li,++i) + // { + // //RasterModel &pm =addNewRaster("","Poisson mesh"); + + + // } + + + //} while(epochDialog->exportToPLY); + + + + return true; +} + +void EditEpochPlugin::EndEdit(MeshModel &/*m*/, GLArea * /*parent*/) +{ + assert(epochDialog); + delete epochDialog; + epochDialog=0; + +} + +void EditEpochPlugin::hideRevealGluedMesh() +{ + +} + +void EditEpochPlugin::setBaseMesh() +{ + +} + + +void EditEpochPlugin::glueByPicking() +{ + +} + + +void EditEpochPlugin::glueManual() +{ + +} + +void EditEpochPlugin:: alignParamCurrent() +{ + +} + +void EditEpochPlugin:: alignParam() +{ + +} + +void EditEpochPlugin::glueHere() +{ + +} + +void EditEpochPlugin::glueHereAll() +{ + +} + +void EditEpochPlugin::process() +{ + +} + +void EditEpochPlugin::recalcCurrentArc() +{ + +} + + +void EditEpochPlugin::mousePressEvent(QMouseEvent *e, MeshModel &, GLArea * ) +{ + +} + +void EditEpochPlugin::mouseMoveEvent(QMouseEvent *e, MeshModel &, GLArea * ) +{ + + +} + +void EditEpochPlugin::mouseReleaseEvent(QMouseEvent * e, MeshModel &/*m*/, GLArea * gla) +{ + +} + + +// this function toggles on and off all the buttons (according to the "modal" states of the interface), +// do not confuse it with the updatebuttons function of the epochDialog class. +void EditEpochPlugin::toggleButtons() +{ + +} + diff --git a/src/plugins_experimental/edit_epoch/edit_epoch.h b/src/plugins_experimental/edit_epoch/edit_epoch.h new file mode 100644 index 000000000..63d9db0b1 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/edit_epoch.h @@ -0,0 +1,102 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef EditEpochPLUGIN_H +#define EditEpochPLUGIN_H + +#include +#include +#include "epoch_io.h" + + + +class EditEpochPlugin : public QObject, public MeshEditInterface +{ + Q_OBJECT + Q_INTERFACES(MeshEditInterface) + + enum + { + ALIGN_IDLE = 0x01, + ALIGN_INSPECT_ARC = 0x02, + ALIGN_MOVE = 0x03 + }; + + void Pick( MeshModel &m, GLArea * gla); + +public: + EditEpochPlugin(); + virtual ~EditEpochPlugin() { + mode=ALIGN_IDLE; + } + + static const QString Info(); + + bool StartEdit(MeshDocument &/*m*/, GLArea * /*parent*/); + void EndEdit(MeshModel &/*m*/, GLArea * /*parent*/); + void Decorate(MeshModel &/*m*/, GLArea * /*parent*/); + void mousePressEvent(QMouseEvent *, MeshModel &, GLArea * ) ; + void mouseMoveEvent(QMouseEvent *, MeshModel &, GLArea * ) ; + void mouseReleaseEvent(QMouseEvent *event, MeshModel &/*m*/, GLArea * ); + + QFont qFont; + int mode; + + v3dImportDialog *epochDialog; //the widget with the list of the meshes. + + void toggleButtons(); + + + + MeshDocument *md; + + GLArea * gla; + +public: + + + // this callback MUST be redefined because we are able to manage internally the layer change. + virtual void LayerChanged(MeshDocument &/*md*/, MeshModel &/*oldMeshModel*/, GLArea */*parent*/) + { + // add code here to manage the external layer switching + } + +public slots: + void process(); + void recalcCurrentArc(); + void glueHere(); + void glueHereAll(); + void glueManual(); + void glueByPicking(); + void alignParam(); + void alignParamCurrent(); + void setBaseMesh(); + void hideRevealGluedMesh(); + + +signals: + void suspendEditToggle(); + +}; + +#endif diff --git a/src/plugins_experimental/edit_epoch/edit_epoch.pro b/src/plugins_experimental/edit_epoch/edit_epoch.pro new file mode 100644 index 000000000..4b376d80f --- /dev/null +++ b/src/plugins_experimental/edit_epoch/edit_epoch.pro @@ -0,0 +1,50 @@ +include (../../shared.pri) + +TEMPLATE = lib + +FORMS = ui/v3dImportDialog.ui +HEADERS += epoch_io.h \ + epoch_reconstruction.h \ + epoch_camera.h \ + radial_distortion.h\ + v3dImportDialog.h \ + scalar_image.h \ + maskRenderWidget.h \ + maskImageWidget.h \ + fillImage.h + +SOURCES += epoch_io.cpp \ + epoch_camera.cpp \ + radial_distortion.cpp \ + scalar_image.cpp \ + v3dImportDialog.cpp \ + maskRenderWidget.cpp \ + maskImageWidget.cpp \ + fillImage.cpp \ + $$VCGDIR/wrap/ply/plylib.cpp + +TARGET = edit_epoch +QT += xml + +win32-msvc2005:LIBS += ../../external/lib/win32-msvc2005/bz2.lib +win32-msvc2008:LIBS += ../../external/lib/win32-msvc2008/bz2.lib +win32-g++:LIBS += ../../external/lib/win32-gcc/libbz2.a +linux-g++:LIBS += ../../external/lib/linux-g++/libbz2.a +linux-g++-32:LIBS += ../../external/lib/linux-g++-32/libbz2.a +linux-g++-64:LIBS += ../../external/lib/linux-g++-64/libbz2.a + +win32-msvc2005:INCLUDEPATH += ../../external/bzip2-1.0.5 +win32-msvc2008:INCLUDEPATH += ../../external/bzip2-1.0.5 +win32-g++:INCLUDEPATH += ../../external/bzip2-1.0.5 +linux-g++:INCLUDEPATH += ../../external/bzip2-1.0.5 +linux-g++-32:INCLUDEPATH += ../../external/bzip2-1.0.5 +linux-g++-64:INCLUDEPATH += ../../external/bzip2-1.0.5 + +mac:LIBS += -lbz2 + +CONFIG(release, debug|release) { + win32-g++:release:QMAKE_CXXFLAGS -= -O2 + win32-g++:release:QMAKE_CFLAGS -= -O2 + win32-g++:release:QMAKE_CXXFLAGS += -O3 -mtune=pentium3 -ffast-math +} + diff --git a/src/plugins_experimental/edit_epoch/edit_epoch.qrc b/src/plugins_experimental/edit_epoch/edit_epoch.qrc new file mode 100644 index 000000000..3b93e5a57 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/edit_epoch.qrc @@ -0,0 +1,8 @@ + + + images/icon_arc3d.png + images/cur_align.png + ../../meshlab/images/layer_eye_open.png + ../../meshlab/images/layer_eye_close.png + + diff --git a/src/plugins_experimental/edit_epoch/edit_epoch_factory.cpp b/src/plugins_experimental/edit_epoch/edit_epoch_factory.cpp new file mode 100644 index 000000000..89a80cda5 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/edit_epoch_factory.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2008 \/)\/ * +* 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 "edit_epoch_factory.h" +#include "edit_epoch.h" + +EditEpochFactory::EditEpochFactory() +{ + editEpoch = new QAction(QIcon(":/images/icon_arc3d.png"), "Arc3D Importer", this); + + actionList << editEpoch; + + foreach(QAction *editAction, actionList) + editAction->setCheckable(true); +} + +//gets a list of actions available from this plugin +QList EditEpochFactory::actions() const +{ + return actionList; +} + +//get the edit tool for the given action +MeshEditInterface* EditEpochFactory::getMeshEditInterface(QAction *action) +{ + if(action == editEpoch) + { + return new EditEpochPlugin(); + } else assert(0); //should never be asked for an action that isnt here +} + +QString EditEpochFactory::getEditToolDescription(QAction *) +{ + return EditEpochPlugin::Info(); +} + +Q_EXPORT_PLUGIN(EditEpochFactory) diff --git a/src/plugins_experimental/edit_epoch/edit_epoch_factory.h b/src/plugins_experimental/edit_epoch/edit_epoch_factory.h new file mode 100644 index 000000000..7bd72c4c5 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/edit_epoch_factory.h @@ -0,0 +1,55 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2008 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + + +#ifndef EditEpochFactoryPLUGIN_H +#define EditEpochFactoryPLUGIN_H + +#include +#include + +class EditEpochFactory : public QObject, public MeshEditInterfaceFactory +{ + Q_OBJECT + Q_INTERFACES(MeshEditInterfaceFactory) + +public: + EditEpochFactory(); + virtual ~EditEpochFactory() { delete editEpoch; } + + //gets a list of actions available from this plugin + virtual QList actions() const; + + //get the edit tool for the given action + virtual MeshEditInterface* getMeshEditInterface(QAction *); + + //get the description for the given action + virtual QString getEditToolDescription(QAction *); + +private: + QList actionList; + + QAction *editEpoch; +}; + +#endif diff --git a/src/plugins_experimental/edit_epoch/epoch_camera.cpp b/src/plugins_experimental/edit_epoch/epoch_camera.cpp new file mode 100644 index 000000000..1adf882bd --- /dev/null +++ b/src/plugins_experimental/edit_epoch/epoch_camera.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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 +#include +#include +#include + +using namespace vcg; +using namespace std; + +#include "radial_distortion.h" +#include "epoch_camera.h" + + +/* +Epoch Camera + + +*/ +// This function take in input a point in image space (e.g. with coords in range [0..1024]x[0..768] +// a depth value and it returns the point in absolute 3D coords +// +void EpochCamera::DepthTo3DPoint(double x, double y, double depth, Point3d &M) const +{ + Point3d m_temp = Kinv * Point3d(x,y,1); + + double oldx, oldy; + rd.ComputeOldXY(m_temp[0] / m_temp[2], m_temp[1] / m_temp[2], oldx, oldy); + + m_temp=Point3d(oldx,oldy,1); + Point3d fp=t; + Point3d end = TRinv*m_temp; + Point3d dir =fp-end; + dir.Normalize(); + M = fp-dir*depth; +} + + + + +bool EpochCamera::Open(const char *filename) +{ + FILE *fp=fopen(filename,"rb"); + if(!fp) return false; + + fscanf(fp,"%lf %lf %lf",&(K[0][0]),&(K[0][1]),&(K[0][2])); + fscanf(fp,"%lf %lf %lf",&(K[1][0]),&(K[1][1]),&(K[1][2])); + fscanf(fp,"%lf %lf %lf",&(K[2][0]),&(K[2][1]),&(K[2][2])); + + k.resize(3); + fscanf(fp,"%lf %lf %lf",&(k[0]),&(k[1]),&(k[2])); + + fscanf(fp,"%lf %lf %lf",&(R[0][0]),&(R[0][1]),&(R[0][2])); + fscanf(fp,"%lf %lf %lf",&(R[1][0]),&(R[1][1]),&(R[1][2])); + fscanf(fp,"%lf %lf %lf",&(R[2][0]),&(R[2][1]),&(R[2][2])); + + fscanf(fp,"%lf %lf %lf",&(t[0]),&(t[1]),&(t[2])); + + fscanf(fp,"%i %i",&width,&height); + + fclose(fp); + Kinv=Inverse(K); + + rd.SetParameters(k); + + // TR = [R | -Rt] 4x4 matrix with upperleft a 3x3 rotation + // on the right the rotated translation -Rt and 0001 in the + // lower line. + + R.transposeInPlace(); + #ifndef VCG_USE_EIGEN + for(int i=0;i<3;++i) + for(int j=0;j<3;++j) + TR[i][j]= R[i][j]; + #else + TR.corner<3,3>(Eigen::TopLeft) = R.transpose(); + #endif + + Point3d rt= R*(-t); + + for(int i=0;i<3;++i) + TR[i][3]=rt[i]; + + for(int j=0;j<3;++j) + TR[3][j]=0; + + TR[3][3]=1; + TRinv=Inverse(TR); + return true; +} diff --git a/src/plugins_experimental/edit_epoch/epoch_camera.h b/src/plugins_experimental/edit_epoch/epoch_camera.h new file mode 100644 index 000000000..5e44814d9 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/epoch_camera.h @@ -0,0 +1,46 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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. * +* * +****************************************************************************/ + +namespace vcg +{ +class EpochCamera +{ +public: + Matrix33d K; // parametri intriseci camera + Matrix33d Kinv; + + std::vector k; + Matrix33d R; + Matrix44d TR; // [R | -Rt] e.g. la matrice in cui + Matrix44d TRinv; + Point3d t; + int width, height; + + RadialDistortion rd; + + void DepthTo3DPoint(double x, double y, double depth, Point3d &M) const; + + bool Open(const char * filename); +}; + +} \ No newline at end of file diff --git a/src/plugins_experimental/edit_epoch/epoch_io.cpp b/src/plugins_experimental/edit_epoch/epoch_io.cpp new file mode 100644 index 000000000..e733f12ac --- /dev/null +++ b/src/plugins_experimental/edit_epoch/epoch_io.cpp @@ -0,0 +1,739 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + +#include +#include +#include +#include +#include + + + +#include +#include + + +#include "epoch_reconstruction.h" +#include +#include +#include +#include +#include +#include +#include + +FILE *logFP2=0; +using namespace std; +using namespace vcg; + +void EpochModel::depthFilter(FloatImage &depthImgf, FloatImage &countImgf, float depthJumpThr, + bool dilation, int dilationNumPasses, int dilationWinsize, + bool erosion, int erosionNumPasses, int erosionWinsize) +{ + FloatImage depth; + FloatImage depth2; + int w = depthImgf.w; + int h = depthImgf.h; + + depth=depthImgf; + + if (dilation) + { + for (int k = 0; k < dilationNumPasses; k++) + { + depth.Dilate(depth2, dilationWinsize / 2); + depth=depth2; + } + } + + if (erosion) + { + for (int k = 0; k < erosionNumPasses; k++) + { + depth.Erode(depth2, erosionWinsize / 2); + depth=depth2; + } + } + + Histogramf HH; + HH.Clear(); + HH.SetRange(0,depthImgf.MaxVal()-depthImgf.MinVal(),10000); + for(int i=1; i < static_cast(depthImgf.v.size()); ++i) + HH.Add(fabs(depthImgf.v[i]-depth.v[i-1])); + + if(logFP2) fprintf(logFP2,"**** Depth histogram 2 Min %f Max %f Avg %f Percentiles ((10)%f (25)%f (50)%f (75)%f (90)%f)\n",HH.MinV(),HH.MaxV(),HH.Avg(), + HH.Percentile(.1),HH.Percentile(.25),HH.Percentile(.5),HH.Percentile(.75),HH.Percentile(.9)); + + int deletedCnt=0; + + depthJumpThr = static_cast(HH.Percentile(0.8)); + for (int y = 0; y < h; y++) + for (int x = 0; x < w; x++) + { + if ((depthImgf.Val(x, y) - depth.Val(x, y)) / depthImgf.Val(x, y) > 0.6) + { + countImgf.Val(x, y) = 0.0f; + ++deletedCnt; + } + } + + countImgf.convertToQImage().save("tmp_filteredcount.jpg","jpg"); + + if(logFP2) fprintf(logFP2,"**** depthFilter: deleted %i on %i\n",deletedCnt,w*h); + +} + +float EpochModel::ComputeDepthJumpThr(FloatImage &depthImgf, float percentile) +{ + Histogramf HH; + HH.Clear(); + HH.SetRange(0,depthImgf.MaxVal()-depthImgf.MinVal(),10000); + for(unsigned int i=1; i < static_cast(depthImgf.v.size()); ++i) + HH.Add(fabs(depthImgf.v[i]-depthImgf.v[i-1])); + + if(logFP2) fprintf(logFP2,"**** Depth histogram Min %f Max %f Avg %f Percentiles ((10)%f (25)%f (50)%f (75)%f (90)%f)\n",HH.MinV(),HH.MaxV(),HH.Avg(), + HH.Percentile(.1),HH.Percentile(.25),HH.Percentile(.5),HH.Percentile(.75),HH.Percentile(.9)); + + return HH.Percentile(percentile); +} + + + +/// Apply the hand drawn mask image +bool EpochModel::CombineHandMadeMaskAndCount(CharImage &CountImg, QString maskName ) +{ + QImage maskImg(maskName); + qDebug("Trying to read maskname %s",qPrintable(maskName)); + if(maskImg.isNull()) + return false; + + if( (maskImg.width()!= CountImg.w) || (maskImg.height()!= CountImg.h) ) + { + qDebug("Warning mask and images does not match! %i %i vs %i %i",maskImg.width(),CountImg.w,maskImg.height(),CountImg.h); + return false; + } + + for(int j=0;j128) + CountImg.Val(i,j)=0; + + return true; +} + + +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; + } + } +} + +/* +This filter average apply a laplacian smoothing over a depth map averaging the samples with a weighting scheme that follows the Counting masks. +The result of the laplacian is applied only on sample with low quality. +*/ + +void EpochModel::Laplacian2(FloatImage &depthImg, FloatImage &countImg, int minCount, CharImage &featureMask, float depthThr) +{ + FloatImage Sum; + int w=depthImg.w,h=depthImg.h; + Sum.resize(w,h); + + for(int y=1;y0 && fabs(depthImg.Val(x+i,y+j)-curDepth) < depthThr) { + Sum.Val(x,y)+=q*depthImg.Val(x+i,y+j); + cnt+=q; + } + } + if(cnt>0) { + Sum.Val(x,y)/=cnt; + } + else Sum.Val(x,y)=depthImg.Val(x,y); + } + + for(int y=1;y(m,depthSubf.w,depthSubf.h,depthImgf.w,depthImgf.h,&*depthSubf.v.begin()); + + int ttt4=clock(); + if(logFP2) fprintf(logFP2,"**** Buildmesh: trimesh building %i\n",ttt4-ttt3); + + + // The depth is filtered and the minimum count mask is update accordingly. + // To be more specific the border of the depth map are identified by erosion + // and the relative vertex removed (by setting mincount equal to 0). + float depthThr2 = ComputeDepthJumpThr(depthSubf,0.95f); + depthFilter(depthSubf, countSubf, depthThr2, + dilation, dilationPasses, dilationSize, + erosion, erosionPasses, erosionSize); + + int vn = m.vn; + 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=CameraPos-vcg::Barycenter(*fi); + dir.Normalize(); + if(dir.dot(n) < minAngleCos) + { + (*fi).SetD(); + --m.fn; + } + } + } + + tri::Clean::RemoveUnreferencedVertex(m); + int ttt6=clock(); + if(logFP2) fprintf(logFP2,"**** Buildmesh: Deleting skewed %i\n",ttt6-ttt5); + +// Matrix44d Rot; +// Rot.SetRotate(M_PI,Point3d(1,0,0)); +// vcg::tri::UpdatePosition::Matrix(m, Rot); + + Matrix44f scaleMat; + scaleMat.SetScale(scalingFactor,scalingFactor,scalingFactor); + vcg::tri::UpdatePosition::Matrix(m, scaleMat); + + 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(); + + // import leuven camera + { + double cam[9]; + float focus,scale; + + FILE* lvcam; + + lvcam = fopen(cameraName.toAscii(),"rb"); + + // focus + image centers + fscanf(lvcam,"%lf %lf %lf",&(cam[0]),&(cam[1]),&(cam[2])); + fscanf(lvcam,"%lf %lf %lf",&(cam[3]),&(cam[4]),&(cam[5])); + fscanf(lvcam,"%lf %lf %lf",&(cam[6]),&(cam[7]),&(cam[8])); + + shot.Intrinsics.CenterPx[0] = cam[2]; + shot.Intrinsics.CenterPx[1] = cam[5]; + focus = cam[0]; + scale = 1.0f; + while(focus>10.0f) + { + focus /= 10.0f; + scale /= 10.0f; + } + shot.Intrinsics.FocalMm = focus; + shot.Intrinsics.PixelSizeMm[0] = scale; + shot.Intrinsics.PixelSizeMm[1] = scale; + + // distortion + fscanf(lvcam,"%lf %lf %lf",&(cam[0]),&(cam[1]),&(cam[2])); + shot.Intrinsics.k[0] = cam[0]; + shot.Intrinsics.k[1] = cam[1]; + + // orientation axis + fscanf(lvcam,"%lf %lf %lf",&(cam[0]),&(cam[1]),&(cam[2])); + fscanf(lvcam,"%lf %lf %lf",&(cam[3]),&(cam[4]),&(cam[5])); + fscanf(lvcam,"%lf %lf %lf",&(cam[6]),&(cam[7]),&(cam[8])); + + Matrix44f myrot; + + myrot[0][0] = cam[0]; myrot[0][1] = cam[3]; myrot[0][2] = cam[6]; myrot[0][3] = 0.0f; + myrot[1][0] = -cam[1]; myrot[1][1] = -cam[4]; myrot[1][2] = -cam[7]; myrot[1][3] = 0.0f; + myrot[2][0] = -cam[2]; myrot[2][1] = -cam[5]; myrot[2][2] = -cam[8]; myrot[2][3] = 0.0f; + myrot[3][0] = 0.0f; myrot[3][1] = 0.0f; myrot[3][2] = 0.0f; myrot[3][3] = 1.0; + + shot.Extrinsics.SetRot(myrot); + + // camera position + fscanf(lvcam,"%lf %lf %lf",&(cam[0]),&(cam[1]),&(cam[2])); + shot.Extrinsics.SetTra(Point3f(-cam[0], -cam[1], -cam[2])); + // shot.Extrinsics.sca = 1.0f; + + + // image size + fscanf(lvcam,"%lf %lf",&(cam[0]),&(cam[1])); + shot.Intrinsics.ViewportPx.X() = (int)(cam[0]); + shot.Intrinsics.ViewportPx.Y() = (int)(cam[1]); + + fclose(lvcam); + } + } + + 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"); +} + +//bool EpochIO::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const RichParameterSet & /*par*/, CallBackPos *cb, QWidget *parent) +//{ +// EpochReconstruction er; +// +// mask = vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::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 stdfilename = QFile::encodeName(fileName).constData (); +// //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); +// do +// { +// epochDialog->exportToPLY=false; +// +// //Here we invoke the modal dialog and wait for its termination +// int continueValue = epochDialog->exec(); +// +// // The user has pressed the ok button: now start the real processing: +// +// if(epochDialog->exportToPLY == true) qDebug("Starting the ply exporting process"); +// +// int t0=clock(); +// logFP2=fopen("epoch.log","w"); +// +// 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 dilationFlag = epochDialog->dilationCheckBox->isChecked(); +// int dilationN = epochDialog->dilationNumPassSpinBox->value(); +// int dilationSz = epochDialog->dilationSizeSlider->value() * 2 + 1; +// bool erosionFlag = epochDialog->erosionCheckBox->isChecked(); +// int erosionN = epochDialog->erosionNumPassSpinBox->value(); +// int erosionSz = epochDialog->erosionSizeSlider->value() * 2 + 1; +// float scalingFactor = epochDialog->scaleLineEdit->text().toFloat(); +// std::vector savedMeshVector; +// +// 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(); +// int tt0=clock(); +// (*li).BuildMesh(mm,subSampleVal,minCountVal,MinAngleCos,smoothSteps, +// dilationFlag, dilationN, dilationSz, erosionFlag, erosionN, erosionSz,scalingFactor); +// int tt1=clock(); +// if(logFP2) fprintf(logFP2,"** Mesh %i : Build in %i\n",selectedCount,tt1-tt0); +// +// if(epochDialog->exportToPLY) +// { +// QString plyFilename =(*li).textureName.left((*li).textureName.length()-4); +// plyFilename.append(".x.ply"); +// savedMeshVector.push_back(qPrintable(plyFilename)); +// int mask= tri::io::Mask::IOM_VERTCOORD + tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY; +// tri::io::ExporterPLY::Save(mm,qPrintable(plyFilename),mask); +// } +// else +// { +// 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.AddMesh(mm); +// } +// else +// tri::Append::Mesh(m.cm,mm); // append mesh mr to ml +// } +// int tt2=clock(); +// if(logFP2) fprintf(logFP2,"** Mesh %i : Append in %i\n",selectedCount,tt2-tt1); +// +// } +// if (cb)(*cb)(selectedCount*90/selectedNum, "Building meshes"); +// } +// +// if (cb != NULL) (*cb)(90, "Final Processing: clustering"); +// if(clustering) +// { +// Grid.ExtractPointSet(m.cm); +// } +// +// if(epochDialog->exportToPLY) +// { +// QString ALNfilename = fileName.left(fileName.length()-4).append(".aln"); +// ALNParser::SaveALN(qPrintable(ALNfilename), savedMeshVector); +// } +// int t1=clock(); +// if(logFP2) fprintf(logFP2,"Extracted %i meshes in %i\n",selectedCount,t1-t0); +// +// 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_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK); +// tri::Clean::RemoveSmallConnectedComponentsDiameter(m.cm,m.cm.bbox.Diag()*maxCCDiagVal/100.0); +// } +// +// int t2=clock(); +// if(logFP2) fprintf(logFP2,"Topology and removed CC in %i\n",t2-t1); +// +// vcg::tri::UpdateBounding::Box(m.cm); // updates bounding box +// +// if (cb != NULL) (*cb)(97, "Final Processing: Closing Holes"); +// if(closeHole) +// { +// m.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK); +// tri::UpdateNormals::PerVertexNormalizedPerFace(m.cm); +// vcg::tri::Hole::EarCuttingFill >(m.cm,maxHoleSize,false); +// } +// +// if (cb != NULL) (*cb)(100, "Done"); +// // vcg::tri::UpdateNormals::PerVertex(m.cm); // updates normals +// +// m.updateDataMask(MeshModel::MM_VERTCOLOR); +// +// int t3=clock(); +// if(logFP2) fprintf(logFP2,"---------- Total Processing Time%i\n\n\n",t3-t0); +// if(logFP2) fclose(logFP2); +// logFP2=0; +// +// +// //// Importing rasters +// +// //QList::iterator li; +// for(li=er.modelList.begin(), i=0;li!=er.modelList.end();++li,++i) +// { +// //RasterModel &pm =addNewRaster("","Poisson mesh"); +// +// +// } +// +// +// } while(epochDialog->exportToPLY); +// +// return true; +//} + + + diff --git a/src/plugins_experimental/edit_epoch/epoch_io.h b/src/plugins_experimental/edit_epoch/epoch_io.h new file mode 100644 index 000000000..092a30312 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/epoch_io.h @@ -0,0 +1,69 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ +/**************************************************************************** + History + + $Log$ + Revision 1.4 2007/11/26 07:35:26 cignoni + Yet another small cosmetic change to the interface of the io filters. + + Revision 1.3 2007/11/25 09:48:39 cignoni + Changed the interface of the io filters. Now also a default bit set for the capabilities has to specified + + Revision 1.2 2006/11/29 00:59:16 cignoni + Cleaned plugins interface; changed useless help class into a plain string + + 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 *** + + *****************************************************************************/ +#ifndef EXTRAIOPLUGINV3D_H +#define EXTRAIOPLUGINV3D_H + +#include +#include +#include "v3dImportDialog.h" + +class EpochIO : public QObject, public MeshIOInterface +{ + Q_OBJECT + Q_INTERFACES(MeshIOInterface) + +public: + QList importFormats() const; + QList exportFormats() const {return QList();}; + + EpochIO(); + ~EpochIO(); + QString lastFileName; + void GetExportMaskCapability(QString &, int &, int &) const {assert(0); return ;} + + bool open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const RichParameterSet & par, vcg::CallBackPos *cb=0, QWidget *parent=0); + bool save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const RichParameterSet &, vcg::CallBackPos *cb=0, QWidget *parent= 0); +}; + + +#endif diff --git a/src/plugins_experimental/edit_epoch/epoch_reconstruction.h b/src/plugins_experimental/edit_epoch/epoch_reconstruction.h new file mode 100644 index 000000000..02551cb2b --- /dev/null +++ b/src/plugins_experimental/edit_epoch/epoch_reconstruction.h @@ -0,0 +1,72 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef _EPOCH_RECONSTRUCTION_H +#define _EPOCH_RECONSTRUCTION_H + +#include + +#include + +#include "radial_distortion.h" +#include "epoch_camera.h" +#include "scalar_image.h" + + +class EpochModel +{ +public: + int index; + QString cameraName; + QString maskName; + QString depthName; + QString textureName; + QString countName; + vcg::EpochCamera cam; + vcg::Shotf shot; + bool Init(QDomNode &node); + static QString ThumbName(QString &imageName); + + bool BuildMesh(CMeshO &m, int subsampleFactor, int minCount, float minAngleCos, int smoothSteps, + bool dilation, int dilationPasses, int dilationSize, bool erosion, int erosionPasses, int erosionSize,float scalingFactor); + void SmartSubSample(int subsampleFactor, FloatImage &fli, CharImage &chi, FloatImage &subD,FloatImage &subQ, int minCount); + void AddCameraIcon(CMeshO &m); + bool CombineHandMadeMaskAndCount(CharImage &qualityImg, QString maskName ); + void GenerateCountImage(); + void GenerateGradientSmoothingMask(int subsampleFactor, QImage &OriginalTexture, CharImage &mask); + void Laplacian2(FloatImage &depth, FloatImage &Q, int minCount, CharImage &mask, float depthThr); + float ComputeDepthJumpThr(FloatImage &depthImgf, float percentile); + void depthFilter(FloatImage &depthImgf, FloatImage &countImgf, float depthJumpThr, + bool dilation, int dilationNumPasses, int dilationWinsize, bool erosion, int erosionNumPasses, int erosionWinsize); + + QIcon *getIcon(); +}; + +class EpochReconstruction +{ + public: + QString name, author, created; + QList modelList; +}; + +#endif \ No newline at end of file diff --git a/src/plugins_experimental/edit_epoch/fillImage.cpp b/src/plugins_experimental/edit_epoch/fillImage.cpp new file mode 100644 index 000000000..a2154af99 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/fillImage.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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 "fillImage.h" +#include +#include + +namespace ui +{ + + fillImage::fillImage() + { + } + + fillImage::~fillImage() + { + } + + void fillImage::Compute(const QImage& input, int x, int y, int threshold_gradient, int threshold_fixed, QImage& output) + { + threshold_gradient_ = threshold_gradient; + threshold_fixed_ = threshold_fixed; + input_ = input; + W = input.width(); + H = input.height(); + xo = x; + yo = y; + + output = QImage(W, H, QImage::Format_Mono); + computed_ = QImage(W, H, QImage::Format_Mono); + output.fill(0); + computed_.fill(0); + + ComputeGradient(input, gradient_); + + pixels_to_do_.push_back(std::make_pair(x,y)); + while(!pixels_to_do_.empty()) + { + DealWithPixel(pixels_to_do_.front(),output); + pixels_to_do_.pop_front(); + } + + } + + bool fillImage::ShouldWeCompute(int x, int y) + { + if (input_.isGrayscale()) + return (gradient_.get(x,y) < threshold_gradient_ && computed_.pixelIndex(x,y) == 0 && std::abs(qGray(input_.pixel(x,y)) - qGray(input_.pixel(xo,yo))) < threshold_fixed_); + else + return (gradient_.get(x,y) < threshold_gradient_ && computed_.pixelIndex(x,y) == 0 && std::abs(qRed(input_.pixel(x,y)) - qRed(input_.pixel(xo,yo))) < threshold_fixed_ && std::abs(qGreen(input_.pixel(x,y)) - qGreen(input_.pixel(xo,yo))) < threshold_fixed_ && std::abs(qBlue(input_.pixel(x,y)) - qBlue(input_.pixel(xo,yo))) < threshold_fixed_); + } + + void fillImage::DealWithPixel(const std::pair& xy, QImage& output) + { + int x = xy.first; + int y = xy.second; + if (computed_.pixelIndex(x,y) == 1) + return; + output.setPixel(x,y,1); + computed_.setPixel(x,y,1); + + if (x>0 && ShouldWeCompute(x-1,y)) + pixels_to_do_.push_back(std::make_pair(x-1,y)); + if (x0 && ShouldWeCompute(x, y-1)) + pixels_to_do_.push_back(std::make_pair(x,y-1)); + if (y::max(); + float max = -std::numeric_limits::max(); + + for (size_t i=1; i max) + max = dx; + if (dx < min) + min = dx; + } + output = myGSImage(W, H); + + float range = 255./(max-min); + for (size_t i=0; i +#include +#include + +namespace ui +{ + struct myGSImage + { + unsigned char* data; + size_t w, h; + + myGSImage() + { + data = 0; + } + + myGSImage(const myGSImage& image) + { + w = image.w; + h = image.h; + if (data) + delete [] data; + data = new unsigned char[w*h]; + memcpy(data, image.data, w*h); + } + + myGSImage & operator = (const myGSImage& image) + { + w = image.w; + h = image.h; + if (data) + delete [] data; + data = new unsigned char[w*h]; + memcpy(data, image.data, w*h); + return *this; + } + + myGSImage(size_t width, size_t height): w(width), h(height) + { + data = new unsigned char[width*height]; + }; + + ~myGSImage() + { + if (data) + delete [] data; + } + + unsigned char get(size_t i, size_t j) const + { + return data[j*w + i]; + } + + void put(size_t i, size_t j, unsigned char a) + { + data[j*w + i] = a; + } + + void fill(unsigned char a) + { + for (size_t i=0; i&, QImage& output); + QImage input_, computed_; + myGSImage gradient_; + int threshold_gradient_, threshold_fixed_; + int W,H; + int xo, yo; + std::deque > pixels_to_do_; + }; +} + +#endif diff --git a/src/plugins_experimental/edit_epoch/images/cur_align.png b/src/plugins_experimental/edit_epoch/images/cur_align.png new file mode 100644 index 0000000000000000000000000000000000000000..b92ccca35e3260ae1d680ed886db268a4757e657 GIT binary patch literal 291 zcmV+;0o?wHP)BenZ`G65jI5mm=;S2=#p{|<=e0%}2!jBi9BNlX1m#s;%CsYPE? zkUC6-Kq;HEmX%(x3?M`)hO($#v9v7E7Dc1t%wpu9nyUb*F(lz>4G7?pHv{4h4%2Dy zX(?9AJ7p9BK+=rGB(*8Yv427jz%qc|<8?d(LW9(vbC p^%}M`>lO@^V5W{Y;REmhyaDu3d1WM`ScCuo002ovPDHLkV1i^ob(;VH literal 0 HcmV?d00001 diff --git a/src/plugins_experimental/edit_epoch/images/icon_align.png b/src/plugins_experimental/edit_epoch/images/icon_align.png new file mode 100644 index 0000000000000000000000000000000000000000..61ed84a88acae1eff147e850d09acd73910dca4d GIT binary patch literal 4870 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 literal 0 HcmV?d00001 diff --git a/src/plugins_experimental/edit_epoch/images/icon_align.svg b/src/plugins_experimental/edit_epoch/images/icon_align.svg new file mode 100644 index 000000000..fceeeb5a7 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/images/icon_align.svg @@ -0,0 +1,85 @@ + + + + + + + + + image/svg+xml + + + + + + + A + + diff --git a/src/plugins_experimental/edit_epoch/images/icon_arc3d.png b/src/plugins_experimental/edit_epoch/images/icon_arc3d.png new file mode 100644 index 0000000000000000000000000000000000000000..fda2520e678b44606fcebb279edb868dac2b50f2 GIT binary patch literal 6786 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 literal 0 HcmV?d00001 diff --git a/src/plugins_experimental/edit_epoch/maskImageWidget.cpp b/src/plugins_experimental/edit_epoch/maskImageWidget.cpp new file mode 100644 index 000000000..6c615cefa --- /dev/null +++ b/src/plugins_experimental/edit_epoch/maskImageWidget.cpp @@ -0,0 +1,333 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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 "maskImageWidget.h" +#include "maskRenderWidget.h" +#include "fillImage.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#undef min +#undef max +#endif + + +namespace ui +{ + + struct maskImageWidget::Impl + { + enum DrawMode { Pen, Eraser } mode_; + + maskRenderWidget *render_area_; + int threshold_gradient_, threshold_fixed_; + int realwidth_, realheight_; + Impl(); + }; + + + maskImageWidget::Impl::Impl() + { + mode_ = Pen; + threshold_gradient_ = 100; + threshold_fixed_ = 30; + } + + + maskImageWidget::maskImageWidget(const QImage& image, QWidget *parent) : QDialog(parent), pimpl_(new Impl) + { + init(image); + } + + + maskImageWidget::~maskImageWidget() throw() + { + delete pimpl_; + } + + QImage maskImageWidget::getMask() const + { + return pimpl_->render_area_->getMask(pimpl_->realwidth_, pimpl_->realheight_); + } + + void maskImageWidget::loadMask(const QString& filename) + { + pimpl_->render_area_->load(filename); + } + + void maskImageWidget::init(const QImage& image) + { + setWindowTitle(tr("Mask Editor")); + + QPixmap load("coral_open32x32.png"); + QPixmap save("coral_save32x32.png"); + QPixmap undo("coral_undo32x32.png"); + QPixmap redo("coral_redo32x32.png"); + QPixmap pen("coral_pencil32x32.png"); + QPixmap eraser("coral_eraser32x32.png"); + + QAction *canvasloadmask = new QAction(this); + canvasloadmask->setIcon(load); + canvasloadmask->setText(tr("&Load Mask")); + QAction *canvassavemask = new QAction(this); + canvassavemask->setIcon(QIcon(save)); + canvassavemask->setText(tr("&Save Mask")); + QAction *canvasundo = new QAction(this); + canvasundo->setIcon(QIcon(undo)); + canvasundo->setText(tr("&Undo")); + canvasundo->setShortcut(QKeySequence("Ctrl+Z")); + QAction *canvasredo = new QAction(this); + canvasredo->setIcon(QIcon(redo)); + canvasredo->setText(tr("&Redo")); + canvasredo->setShortcut(QKeySequence("Ctrl+Shift+Z")); + QAction *canvasclear = new QAction(tr("&Clear"), this); + canvasclear->setShortcut(QKeySequence("Ctrl+C")); + + QAction *canvaspen = new QAction(this); + canvaspen->setIcon(QIcon(pen)); + canvaspen->setText(tr("&Pen")); + QAction *canvaseraser = new QAction(this); + canvaseraser->setIcon(QIcon(eraser)); + canvaseraser->setText(tr("&Eraser")); + + QActionGroup *actions(new QActionGroup(this)); + actions->addAction(canvaspen); + actions->addAction(canvaseraser); + canvaspen->setCheckable(true); + canvaseraser->setCheckable(true); + canvaspen->setChecked(true); + actions->setExclusive(true); + + QAction *canvasOK = new QAction(this); + canvasOK->setText("OK"); + QAction *canvasCancel = new QAction(this); + canvasCancel->setText("Cancel"); + + QBoxLayout *layout(new QVBoxLayout(this)); + + // We don't want a real-size image. We will downscale it! + QImage image_to_use = image; + pimpl_->realwidth_ = image.width(); + pimpl_->realheight_ = image.height(); + qDebug("maskImageWidget::Init real wxh %i x%i",pimpl_->realwidth_,pimpl_->realheight_); + QDesktopWidget *desktop(QApplication::desktop()); + if (image.width() > (desktop->width() * .8) || + image.height() > (desktop->height() * .8)) + { + int width(desktop->width()), height(desktop->height()); + image_to_use = image.scaled((int)std::floor(width * .75), + (int)std::floor(height * .75), Qt::KeepAspectRatio); + } + pimpl_->render_area_ = new maskRenderWidget(image_to_use, this); + + QToolBar *canvas_toolbar(new QToolBar(this)); + canvas_toolbar->addSeparator(); + canvas_toolbar->addAction(canvasloadmask); + canvas_toolbar->addAction(canvassavemask); + canvas_toolbar->addSeparator(); + + canvas_toolbar->addAction(canvasundo); + canvas_toolbar->addAction(canvasredo); + canvas_toolbar->addSeparator(); + + QSpinBox *pen_width(new QSpinBox(canvas_toolbar)); + pen_width->setToolTip(tr("Pen Width")); + pen_width->setRange(0, 80); + pen_width->setSingleStep(2); + pen_width->setValue(16); + connect(pen_width, SIGNAL(valueChanged(int)), SLOT(setCanvasPenWidth(int))); + canvas_toolbar->addWidget(pen_width); + canvas_toolbar->addAction(canvaspen); + canvas_toolbar->addAction(canvaseraser); + canvas_toolbar->addSeparator(); + + QSpinBox *gradient(new QSpinBox(canvas_toolbar)); + gradient->setToolTip("Gradient Threshold"); + gradient->setRange(0, 255); + gradient->setValue(pimpl_->threshold_gradient_); + connect(gradient, SIGNAL(valueChanged(int)), SLOT(setGradientThreshold(int))); + + QSpinBox *fixed(new QSpinBox(canvas_toolbar)); + fixed->setToolTip("Fixed Threshold"); + fixed->setRange(0, 255); + fixed->setValue(pimpl_->threshold_fixed_); + connect(fixed, SIGNAL(valueChanged(int)), SLOT(setFixedThreshold(int))); + + canvas_toolbar->addWidget(gradient); + canvas_toolbar->addWidget(fixed); + canvas_toolbar->addSeparator(); + + canvas_toolbar->addAction(canvasOK); + canvas_toolbar->addAction(canvasCancel); + + layout->addWidget(canvas_toolbar); + layout->addWidget(pimpl_->render_area_); + layout->setSizeConstraint(QLayout::SetFixedSize); + + connect(canvasloadmask, SIGNAL(activated()), SLOT(loadMask())); + connect(canvassavemask, SIGNAL(activated()), SLOT(saveMask())); + connect(canvasundo, SIGNAL(activated()), pimpl_->render_area_, SLOT(undo())); + connect(canvasredo, SIGNAL(activated()), pimpl_->render_area_, SLOT(redo())); + connect(canvasclear, SIGNAL(activated()), pimpl_->render_area_, SLOT(clear())); + connect(canvaspen, SIGNAL(activated()), SLOT(setCanvasPen())); + connect(canvaseraser, SIGNAL(activated()), SLOT(setCanvasEraser())); + + connect(pimpl_->render_area_, SIGNAL(pointSelected(const QPoint &)), SLOT(automaticMask(const QPoint &))); + + connect(canvasOK, SIGNAL(activated()), SLOT(accept())); + connect(canvasCancel, SIGNAL(activated()), SLOT(reject())); + } + + void maskImageWidget::setCanvasPenWidth(int width) + { + QPen pen(pimpl_->render_area_->pen()); + pen.setWidth(width); + pimpl_->render_area_->setPen(pen); + } + + + void maskImageWidget::setCanvasPen() + { + QPen pen(pimpl_->render_area_->pen()); + pen.setColor(QColor(Qt::black)); + pen.setJoinStyle(Qt::RoundJoin); + pimpl_->render_area_->setPen(pen); + } + + + void maskImageWidget::setCanvasEraser() + { + QPen pen(pimpl_->render_area_->pen()); + pen.setColor(QColor(Qt::transparent)); + pen.setJoinStyle(Qt::RoundJoin); + pimpl_->render_area_->setPen(pen); + } + + + void maskImageWidget::setGradientThreshold(int threshold_gradient) + { + pimpl_->threshold_gradient_ = threshold_gradient; + } + + + void maskImageWidget::setFixedThreshold(int threshold_fixed) + { + pimpl_->threshold_fixed_ = threshold_fixed; + } + + void maskImageWidget::loadMask() + { + try + { + QString filename(QFileDialog::getOpenFileName(this, QString("Open mask file"), QString(), QString("*.png"))); + if (QString::null != filename) + pimpl_->render_area_->load(filename); + } + catch (std::exception &e) + { + QMessageBox::warning(this, tr("Problem"), e.what()); + } + } + + namespace + { + bool check_extension(QString &filename, const QString &ext) + { + bool ret(false); + if (ext != filename.section('.', -1)) + { + int index(filename.lastIndexOf('.')); + if (-1 == index) + { + filename += '.'; + index += filename.size(); + } + filename.replace(index + 1, ext.size(), ext); + filename.resize(index + 1 + ext.size()); + ret = true; + } + return ret; + } + }; + + void maskImageWidget::saveMask() + { + try + { + QString filename(QFileDialog::getSaveFileName(this, QString("Save mask file"), QString(), QString("*.png"))); + if (QString::null != filename) + { + check_extension(filename, QString("png")); + pimpl_->render_area_->save(filename, pimpl_->realwidth_, pimpl_->realheight_); + } + } + catch (std::exception &e) + { + QMessageBox::warning(this, tr("Epoch 3D Webservice"), e.what()); + } + } + + + void maskImageWidget::automaticMask(const QPoint &p) + { + QImage image = (pimpl_->render_area_->palette().base().texture()).toImage(); + QImage out; + fillImage fi; + fi.Compute(image, p.x(), p.y(), pimpl_->threshold_gradient_, pimpl_->threshold_fixed_, out); + + const size_t width(image.width()), height(image.height()); + QImage temp(pimpl_->render_area_->alphaMask()); + for (size_t i = 0; i < width; ++i) + { + for (size_t j = 0; j < height; ++j) + { + if (out.pixelIndex(i, j) > 0) + temp.setPixel(i, j, QColor(Qt::black).rgba()); + } + } + //temp.save("temp.jpg","jpg"); + pimpl_->render_area_->setAlphaMask(temp); + } +}; diff --git a/src/plugins_experimental/edit_epoch/maskImageWidget.h b/src/plugins_experimental/edit_epoch/maskImageWidget.h new file mode 100644 index 000000000..71783cb25 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/maskImageWidget.h @@ -0,0 +1,76 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef __IO_MASK_IMAGE_WIDGET_INC__ +#define __IO_MASK_IMAGE_WIDGET_INC__ + + +#include + + +namespace ui +{ + /*! \class maskImageWidget + \brief A brief description + \author Maarten Vergauwen + */ + class maskImageWidget : public QDialog + { + Q_OBJECT + + struct Impl; + Impl* pimpl_; + + void init (const QImage &); + + public: + /*! \brief Constructor + \param The image. + */ + explicit maskImageWidget(const QImage &, QWidget *parent = 0); +; + /*! \brief Destructor + */ + virtual ~maskImageWidget() throw(); + + QImage getMask() const; + + public slots: + + void loadMask(const QString& filename); + + private slots: + + void setCanvasPenWidth(int); + void setCanvasPen(); + void setCanvasEraser(); + void setGradientThreshold(int); + void setFixedThreshold(int); + void automaticMask(const QPoint &); + void loadMask(); + void saveMask(); + }; +}; + + +#endif diff --git a/src/plugins_experimental/edit_epoch/maskRenderWidget.cpp b/src/plugins_experimental/edit_epoch/maskRenderWidget.cpp new file mode 100644 index 000000000..0d6960572 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/maskRenderWidget.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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 "maskRenderWidget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#undef min +#undef max +#endif + + +namespace ui +{ + namespace priv + { + template + inline void unwind(std::stack &stack) + { + while (!stack.empty()) + stack.pop(); + } + }; + + + struct maskRenderWidget::Impl + { + enum Shape { Nothing, Polyline, Rect, Rubber, Point } shape_; + + QPen pen_; + QPolygon polygon_; + + QPoint start_point_, last_point_, end_point_; + QRect rubber_band_; + + QImage foreground_, band_buffer_; + std::stack undo_, redo_; + + Impl(); + + void paintOnDevice(QPaintDevice *); + }; + + + maskRenderWidget::Impl::Impl() : pen_(Qt::black) + { + shape_ = Nothing; + pen_.setWidth(16); + pen_.setCapStyle(Qt::RoundCap); + } + + + void maskRenderWidget::Impl::paintOnDevice(QPaintDevice *device) + { + assert(device); + QPainter painter(device); + painter.setCompositionMode(QPainter::CompositionMode_Source); + switch (shape_) + { + case Impl::Polyline: + { + painter.setPen(pen_); + painter.drawPolyline(polygon_); + } + break; + case Impl::Point: + { + painter.setPen(pen_); + QPoint p2(end_point_.x() + 1, end_point_.y() + 1); + painter.drawLine(end_point_, p2); + } + break; + case Impl::Rect: + { + QPen pen; + pen.setColor(pen_.color()); + painter.setPen(pen); + const int x(rubber_band_.x()), y(rubber_band_.y()); + const int w(rubber_band_.width()), h(rubber_band_.height()); + for (int i = 0; i < w; ++i) + for (int j = 0; j < h; ++j) + painter.drawPoint(QPoint(x + i, y + j)); + rubber_band_ = QRect(0, 0, 0, 0); + } + break; + case Impl::Rubber: + { + QPen pen(Qt::gray); + pen.setWidth(1); + painter.setPen(pen); + painter.drawRect(rubber_band_); + } + break; + default: + break; + } + } + + + maskRenderWidget::maskRenderWidget(QWidget *parent) : QWidget(parent), pimpl_(new Impl) + { + setAttribute(Qt::WA_StaticContents); + setBackgroundRole(QPalette::Base); + QImage image(640, 480, QImage::Format_ARGB32); + image.fill(Qt::white); + setImage(image); + setFocusPolicy(Qt::StrongFocus); + } + + maskRenderWidget::maskRenderWidget(const QImage& image, QWidget *parent) : QWidget(parent), pimpl_(new Impl) + { + qDebug("MaskRenderWidget started with an image %i x %i",image.width(),image.height()); + setAttribute(Qt::WA_StaticContents); + setBackgroundRole(QPalette::Base); + setImage(image); + setFocusPolicy(Qt::StrongFocus); + } + + maskRenderWidget::~maskRenderWidget() throw() + { + delete pimpl_; + } + + void maskRenderWidget::keyPressEvent(QKeyEvent *e) + { + if (e->key() == Qt::Key_Z && (e->modifiers() & Qt::ControlModifier)) + { + undo(); + } + } + + + void maskRenderWidget::mousePressEvent(QMouseEvent *e) + { + if (e->button() == Qt::LeftButton) + { + if (e->modifiers() & Qt::ShiftModifier) + { + emit pointSelected(e->pos()); + } + else + { + pimpl_->undo_.push(pimpl_->foreground_); + pimpl_->end_point_ = e->pos(); + pimpl_->polygon_ = QPolygon(); + pimpl_->polygon_ << e->pos(); + priv::unwind(pimpl_->redo_); + pimpl_->shape_ = Impl::Point; + update(); + } + } + else if (e->button() == Qt::RightButton) + { + pimpl_->undo_.push(pimpl_->foreground_); + QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); + pimpl_->start_point_ = e->pos(); + pimpl_->shape_ = Impl::Rubber; + } + } + + + void maskRenderWidget::mouseMoveEvent(QMouseEvent *e) + { + if (Impl::Rubber == pimpl_->shape_) + { + pimpl_->band_buffer_ = pimpl_->foreground_; + int x(std::min(e->pos().x(), pimpl_->start_point_.x())); + int y(std::min(e->pos().y(), pimpl_->start_point_.y())); + int w(std::abs((float)e->pos().x() - pimpl_->start_point_.x())); + int h(std::abs((float)e->pos().y() - pimpl_->start_point_.y())); + + pimpl_->rubber_band_ = QRect(x, y, w, h); + update(); + } + else if (Impl::Point == pimpl_->shape_) + { + pimpl_->shape_ = Impl::Polyline; + } + else if (Impl::Polyline == pimpl_->shape_) + { + pimpl_->last_point_ = pimpl_->end_point_; + pimpl_->end_point_ = e->pos(); + pimpl_->polygon_ << e->pos(); + update(); + } + } + + + void maskRenderWidget::mouseReleaseEvent(QMouseEvent *e) + { + if (Impl::Rubber == pimpl_->shape_) + { + QApplication::restoreOverrideCursor(); + pimpl_->shape_ = Impl::Rect; + update(); + return; + } + else if (Impl::Polyline == pimpl_->shape_) + { + pimpl_->last_point_ = pimpl_->end_point_; + pimpl_->end_point_ = e->pos(); + update(); + } + pimpl_->shape_ = Impl::Nothing; + } + + + void maskRenderWidget::paintEvent(QPaintEvent *e) + { + QImage * device = &pimpl_->foreground_; + + if (Impl::Rubber == pimpl_->shape_) + device = &pimpl_->band_buffer_; + + pimpl_->paintOnDevice(device); + + QPainter painter(this); + QVector rects(e->region().rects()); + for (int i = 0; i < rects.count(); ++i) + { + QRect r = rects[i]; + painter.drawImage(r, *device, r); + } + } + + + QSize maskRenderWidget::sizeHint() const + { + return minimumSizeHint(); + } + + + QSize maskRenderWidget::minimumSizeHint() const + { + return pimpl_->foreground_.isNull()? QSize(400, 400) : pimpl_->foreground_.size(); + } + + + void maskRenderWidget::setPen(const QPen &pen) + { + pimpl_->pen_ = pen; + } + + + QPen maskRenderWidget::pen() const + { + return pimpl_->pen_; + } + + + void maskRenderWidget::setImage(const QImage &image) + { + QPalette palette; +#if (QT_VERSION >= 0x040100) + setAutoFillBackground(true); +#endif + palette.setBrush(backgroundRole(), QBrush(QPixmap::fromImage(image))); + setPalette(palette); + pimpl_->foreground_ = image; + QImage alpha(image.width(), image.height(),QImage::Format_Mono); + alpha.fill(0); + + pimpl_->foreground_.setAlphaChannel(alpha); + + priv::unwind(pimpl_->undo_); + priv::unwind(pimpl_->redo_); + + update(); + } + + + void maskRenderWidget::load(const QString &filename) + { + QImage alpha(filename); + // I would have liked to use KeepAspectRatio but if someone loads a + // bogus mask with a different ratio, the rest will crash. The output + // is now undefined but it won't crash. + alpha = alpha.scaled(pimpl_->foreground_.width(), pimpl_->foreground_.height(), Qt::IgnoreAspectRatio); + QImage temp(pimpl_->foreground_); + const int width(temp.width()), height(temp.height()); + for (int i = 0; i < width; ++i) + for (int j = 0; j < height; ++j) + { + QRgb rgb = temp.pixel(i, j); + temp.setPixel(i, j, QColor(qRed(rgb), qGreen(rgb), qBlue(rgb), qGray(alpha.pixel(i, j))).rgba()); + } + setAlphaMask(temp); + } + + + void maskRenderWidget::save(const QString &filename, int w, int h) + { + pimpl_->foreground_.alphaChannel().scaled(w, h, Qt::KeepAspectRatio).save(filename, "PGM"); + } + + QImage maskRenderWidget::getMask(int w, int h) const + { +// return pimpl_->foreground_.alphaChannel().scaled(w, h, Qt::KeepAspectRatio); + return pimpl_->foreground_.alphaChannel().scaled(w, h); // changed to this becouse sometimes for rounding error did not create the original size. + + } + + + void maskRenderWidget::setAlphaMask(const QImage &image) + { + pimpl_->undo_.push(pimpl_->foreground_); + pimpl_->foreground_ = image; + update(); + } + + + QImage maskRenderWidget::alphaMask() const + { + return pimpl_->foreground_; + } + + + void maskRenderWidget::undo() + { + if (!pimpl_->undo_.empty()) + { + pimpl_->redo_.push(pimpl_->foreground_); + pimpl_->foreground_ = pimpl_->undo_.top(); + pimpl_->undo_.pop(); + update(); + } + } + + + void maskRenderWidget::redo() + { + if (!pimpl_->redo_.empty()) + { + pimpl_->undo_.push(pimpl_->foreground_); + pimpl_->foreground_ = pimpl_->redo_.top(); + pimpl_->redo_.pop(); + update(); + } + } + + + void maskRenderWidget::clear() + { + pimpl_->undo_.push(pimpl_->foreground_); + priv::unwind(pimpl_->redo_); + pimpl_->foreground_.fill(QColor(Qt::transparent).rgba()); + update(); + } +}; diff --git a/src/plugins_experimental/edit_epoch/maskRenderWidget.h b/src/plugins_experimental/edit_epoch/maskRenderWidget.h new file mode 100644 index 000000000..1ebcd62cb --- /dev/null +++ b/src/plugins_experimental/edit_epoch/maskRenderWidget.h @@ -0,0 +1,125 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef __IO_MASK_RENDER_WIDGET_INC__ +#define __IO_MASK_RENDER_WIDGET_INC__ + + +#include + + +namespace ui +{ + /*! \class maskRenderWidget + \brief A brief description + \author gmatthew + */ + class maskRenderWidget : public QWidget + { + Q_OBJECT + + struct Impl; + Impl* pimpl_; + + virtual void keyPressEvent(QKeyEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void paintEvent(QPaintEvent *); + + public: + /*! \brief Constructor + */ + explicit maskRenderWidget(QWidget *parent = 0); + /*! \brief Constructor + */ + explicit maskRenderWidget(const QImage &, QWidget *parent = 0); + /*! \brief Destructor + */ + virtual ~maskRenderWidget() throw(); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; +#endif + + /*! \brief Set the drawable pen. + \param The pen object. + */ + void setPen(const QPen &pen); + /*! \brief Returns the drawable pen. + \return pen The pen object. + */ + QPen pen() const; + /*! \brief Set the background Image. + \param image The image to be set as the background. + */ + void setImage(const QImage &); + /*! \brief Load the alpha mask. + \param filename The path to the image to be used as the mask. + */ + void load(const QString &filename); + /*! \brief Save the alpha mask. + \param filename The path to the image to be used as the mask. + \param w The width of the image to save to. + \param h The height of the image to save to. + */ + void save(const QString &filename, int w, int h); + /*! \brief Get the alpha mask. + \param w The width of the image to return. + \param h The height of the image to return. + */ + QImage getMask(int w, int h) const; + /*! \brief Set the alpha mask. + \param image The image to be set as the mask. + */ + void setAlphaMask(const QImage &image); + /*! \brief Returns the alpha mask. + \return An qimage object. + */ + QImage alphaMask() const; + + public slots: + /*! \brief Undoes the last action and adds the current action to the redo stack and updates the display. If no more actions could be undone, does nothing. + + The number of times this can be done is limited only by the resources available. + */ + void undo(); + /*! \brief Redoes the last action and adds the current action to the undo stack and updates the display. If no more actions could be redone, does nothing. + + The number of times this can be done is limited only by the resources available. + */ + void redo(); + /*! \brief Clears the display. + + This action is also added to the undo actions. + */ + void clear(); + + signals: + void pointSelected(const QPoint &); + }; +}; + + +#endif diff --git a/src/plugins_experimental/edit_epoch/radial_distortion.cpp b/src/plugins_experimental/edit_epoch/radial_distortion.cpp new file mode 100644 index 000000000..65aefa143 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/radial_distortion.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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 "radial_distortion.h" +#include + +using namespace std; + + +void RadialDistortion::SetParameters(vector& k, double max, int resolution) +{ + k_ = k; + max_ = max; + resolution_ = resolution; + + SetupLookupTable(max_, resolution_); +} + +void RadialDistortion::forward_map(double x1, double y1, double* x2, double* y2) const +{ + ComputeNewXY(x1-ocx_, y1-ocy_, *x2, *y2); + *x2 += ncx_; + *y2 += ncy_; +} + + +void RadialDistortion::inverse_map(double x2, double y2, double* x1, double* y1) const +{ + ComputeOldXY(x2-ncx_, y2-ncy_, *x1, *y1); + *x1 += ocx_; + *y1 += ocy_; +} + +//---------------------------------------------------------------------------- +// Relative w.r.t. center ! +void RadialDistortion::ComputeNewXY(double xo, double yo, double& xn, double& yn) const +{ + double r = (xo*xo) + (yo*yo); // r is r squared + double f = 1.0; + for (int i = 0; i < static_cast(k_.size()); i++) f += (k_[i] * pow(r, i+1)); + xn = f*xo; + yn = f*yo; +} + + +void RadialDistortion::ComputeOldXY(double xn, double yn, double& xo, double& yo) const +{ + double rn = sqrt((xn*xn) + (yn*yn)); //// r is r squared + map::const_iterator next = lookup_.upper_bound(rn); + map::const_iterator prev = next; prev--; + + // The compiler will optimise this. + double a = (*prev).first; + double b = (*next).first; + double c = rn; + double d = (*prev).second; + double e = (*next).second; + double f = ((e-d)/(b-a))*(c-a) + d; + + xo = f*xn; + yo = f*yn; +} + + +void RadialDistortion::SetupLookupTable(double max, int resolution) +{ + lookup_.clear(); + double incr = max/(double)resolution; + double value = 0.0; + double old=-1.0; + while (value < max) + { + double f = 1.0; + for (int i = 0; i < static_cast(k_.size()); i++) + f += (k_[i] * pow(value*value, i+1)); + if ((f*value)>old) + { + //cout << "R = " << value << " ,Rd = " << f*value << " ,f = " << f << endl; + lookup_[f*value] = 1.0/f; + old=f*value; + value += incr; + } + else { + //vstDebug(100)<<"vstUndoRadialDistortion::SetupLookupTable:warning RADIAL DISTORTION FOLDING BACK at "< +#include +// using namespace std; +//#include + +class RadialDistortion // : public vil_warp_mapping +{ +public: + RadialDistortion() { } + RadialDistortion(const RadialDistortion &obj): + k_(obj.k_), ocx_(obj.ocx_), ocy_(obj.ocy_), ncx_(obj.ncx_), ncy_(obj.ncy_), lookup_(obj.lookup_), max_(obj.max_), resolution_(obj.resolution_) {} + + void SetParameters(std::vector& k, double max = 2000, int resolution = 10000); + + std::vector GetParameters() { return k_; }; + + void ComputeNewXY(double xo, double yo, double& xn, double& yn) const; + void ComputeOldXY(double xn, double yn, double& xo, double& yo) const; + + // for vil_warp, which doesn't work + void forward_map(double x1, double y1, double* x2, double* y2) const; + void inverse_map(double x2, double y2, double* x1, double* y1) const; + +protected: + std::vector k_; + double ocx_; + double ocy_; + double ncx_; + double ncy_; + + void SetupLookupTable(double max, int resolution); + + std::map lookup_; + + double max_; + int resolution_; +}; diff --git a/src/plugins_experimental/edit_epoch/reconstruction.cpp b/src/plugins_experimental/edit_epoch/reconstruction.cpp new file mode 100644 index 000000000..d4479fa90 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/reconstruction.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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. * +* * +****************************************************************************/ + +// A camera consists of K, R, t and the radial distortion parameters. +// We have an UndoRadialDistortion member (undoraddist_) which is +// initialized with the distortion parameters. + +// Furthermore we have an SVD with the P-matrix (R,t, no K). This is used +// to compute the point at infinity (direction of a line) from a point in +// the image. + +// We use vnl (of VXL: www.vxl.org) for the math but any other library will +// do. + +void vstRadialEuclideanCamera::RecomputeSvd() +{ + vnl_matrix_fixed P; + P.update(R_.transpose(), 0, 0); + P.set_column(3, -R_.transpose() * T_); + Psvd_ = vstSvd(P); +} + +// from depth and 2D point to a 3D point: + +void vstRadialEuclideanCamera::DepthTo3DPoint(const vstPoint2D &m, double depth, vstPoint3D &M) const +{ + vnl_vector_fixed m_temp = Kinv_ * m.GetVector(); + + double x, y; + undoraddist_.ComputeOldXY(m_temp(0) / m_temp(2), m_temp(1) / m_temp(2), x, y); + m_temp(0) = x; + m_temp(1) = y; + m_temp(2) = 1; + + vstPoint3D fp(T_); + vnl_vector_fixed end(Psvd_.solve(m_temp)); + vstLine3D l(fp, vstPoint3D(end)); + vnl_vector_fixed dir(l.GetPointInfinite().GetVector()); + dir.normalize(); + + M.SetVector(fp.GetVector() + depth * dir); + if (IsBehindCamera(M)) + M.SetVector(fp.GetVector() - depth * dir); +} + + + +// Undo Radial Distortion: This class has two maps to map undistorted to +// distorted coordinates and vice versa. + +#include +#include +// using namespace std; +//#include + +class vstUndoRadialDistortion // : public vil_warp_mapping +{ +public: + vstUndoRadialDistortion() { } + vstUndoRadialDistortion(const vstUndoRadialDistortion &obj): + k_(obj.k_), ocx_(obj.ocx_), ocy_(obj.ocy_), ncx_(obj.ncx_), ncy_(obj.ncy_), lookup_(obj.lookup_), max_(obj.max_), resolution_(obj.resolution_) {} + + void SetParameters(std::vector& k, double max = 2000, int resolution = 10000); + + std::vector GetParameters() { return k_; }; + + void ComputeNewXY(double xo, double yo, double& xn, double& yn) const; + void ComputeOldXY(double xn, double yn, double& xo, double& yo) const; + + // for vil_warp, which doesn't work + void forward_map(double x1, double y1, double* x2, double* y2) const; + void inverse_map(double x2, double y2, double* x1, double* y1) const; + +protected: + std::vector k_; + double ocx_; + double ocy_; + double ncx_; + double ncy_; + + void SetupLookupTable(double max, int resolution); + + std::map lookup_; + + double max_; + int resolution_; +}; + + + +#include + +using namespace std; + + +void vstUndoRadialDistortion::SetParameters(vector& k, double max, int resolution) +{ + k_ = k; + max_ = max; + resolution_ = resolution; + + SetupLookupTable(max_, resolution_); +} + +void vstUndoRadialDistortion::forward_map(double x1, double y1, double* x2, double* y2) const +{ + ComputeNewXY(x1-ocx_, y1-ocy_, *x2, *y2); + *x2 += ncx_; + *y2 += ncy_; +} + + +void vstUndoRadialDistortion::inverse_map(double x2, double y2, double* x1, double* y1) const +{ + ComputeOldXY(x2-ncx_, y2-ncy_, *x1, *y1); + *x1 += ocx_; + *y1 += ocy_; +} + +//---------------------------------------------------------------------------- +// Relative w.r.t. center ! +void vstUndoRadialDistortion::ComputeNewXY(double xo, double yo, double& xn, double& yn) const +{ + double r = (xo*xo) + (yo*yo); // r is r squared + double f = 1.0; + for (int i = 0; i < k_.size(); i++) f += (k_[i] * pow(r, i+1)); + xn = f*xo; + yn = f*yo; +} + + +void vstUndoRadialDistortion::ComputeOldXY(double xn, double yn, double& xo, double& yo) const +{ + double rn = sqrt((xn*xn) + (yn*yn)); //// r is r squared + map::const_iterator next = lookup_.upper_bound(rn); + map::const_iterator prev = next; prev--; + + // The compiler will optimise this. + double a = (*prev).first; + double b = (*next).first; + double c = rn; + double d = (*prev).second; + double e = (*next).second; + double f = ((e-d)/(b-a))*(c-a) + d; + + xo = f*xn; + yo = f*yn; +} + + +void vstUndoRadialDistortion::SetupLookupTable(double max, int resolution) +{ + lookup_.clear(); + double incr = max/(double)resolution; + double value = 0.0; + double old=-1.0; + while (value < max) + { + double f = 1.0; + for (int i = 0; i < k_.size(); i++) + f += (k_[i] * pow(value*value, i+1)); + if ((f*value)>old) + { + //cout << "R = " << value << " ,Rd = " << f*value << " ,f = " << f << endl; + lookup_[f*value] = 1.0/f; + old=f*value; + value += incr; + } + else { + //vstDebug(100)<<"vstUndoRadialDistortion::SetupLookupTable:warning RADIAL DISTORTION FOLDING BACK at "< +#include +#include +#include +#include "scalar_image.h" + + + +using namespace std; +/* + +Images with bit-depths greater than 8bpp and up to 31bpp are supported by the JJ2000 codec if they are stored in PGX files +(one file per component). PGX is a custom monochrome file format invented specifically to simplify the use of JPEG 2000 +with images of different bit-depths in the range of 1 to 31 bits per pixel. + +The file consists of a one line text header followed by the (raw) data. + +Header: "PG"+ ws ++ ws +[sign]+ws + +" "++" "++[compressed_size]'\n' + +where: + + * ws (white-spaces) is any combination of characters ' ' and '\t'. + * endianess equals "LM" or "ML"(resp. little-endian or big-endian) + * sign equals "+" or "-" (resp. unsigned or signed). If omited, values are supposed to be unsigned. + * bit-depth that can be any number between 1 and 31. This number must take into account the eventual sign bit. + * width and height are the image dimensions (in pixels). + +Data: The image binary values appear one after the other (in raster order) immediately after the last header character ('\n') +and are byte-aligned (they are packed into 1,2 or 4 bytes per sample, depending upon the bit-depth value). +*/ +template <> +bool ScalarImage::Open(const char *filename) +{ + FILE *fp=fopen(filename,"rb"); + if(!fp) return false; + char buf[256]; + fgets(buf,255,fp); + qDebug("Header of %s is '%s'",filename,buf); + float ll,lh; + int depth; + char mode; + int compressed_size=0; + sscanf(buf,"PG LM %i %i %i %c %f %f %i",&depth,&w,&h,&mode,&ll,&lh,&compressed_size); + qDebug("image should be of %i x %i %i depth and with range in %f -- %f in mode %c",w,h,depth,ll,lh,mode); + if(depth!=16) + { + qDebug("Wrong depth of image 16 bit expected"); + return false; + } + if (mode != 'l' && mode != 'L') + { + qDebug("Wrong mode, expected l or L"); + return false; + } + + if (mode == 'l') + { + vector bb(w*h); + fread(&*bb.begin(),w*h,sizeof(short),fp); + v.resize(w*h); + for(int i =0; i +bool ScalarImage::Open(const char *filename) +{ + FILE *fp=fopen(filename,"rb"); + if(!fp) return false; + char buf[256]; + fgets(buf,255,fp); + qDebug("Header of %s is '%s'",filename,buf); + int depth; + char mode = ' '; + int compressed_size=0; + int nrscan = sscanf(buf,"PG LM %i %i %i %c %i",&depth,&w,&h,&mode,&compressed_size); + if (nrscan == 3) + qDebug("image should be of %i x %i %i depth ",w,h,depth); + else + qDebug("compressed image of %i x %i %i depth ",w,h,depth); + if(depth!=8) + { + qDebug("Wrong depth of image: 8 bit expected"); + return false; + } + + if (mode != 'C') + { + v.resize(w*h); + fread(&*v.begin(),w*h,sizeof(unsigned char),fp); + } + else + { + char* compressed_buffer = new char[compressed_size]; + fread(compressed_buffer,compressed_size,1,fp); + // decompress! + unsigned int mysize = w*h; + v.resize(w*h); + BZ2_bzBuffToBuffDecompress((char*)&*v.begin(), &mysize, compressed_buffer, compressed_size, 0, 0); + if (mysize != (unsigned int)(w*h)) + { + qDebug("This is very wrong. The uncompressed size is not the expected size"); + return false; + } + } + + fclose(fp); + return true; +} + + +template <> +ScalarImage::ScalarImage(QImage img) +{ + resize(img.width(),img.height()); + + for(int y=0;y +bool ScalarImage::Subsample(const int factor, ScalarImage &fli) +{ + resize(fli.w/factor,fli.h/factor); + + for(int i=0;i +#include +#include +/* +Very simple class to store a bitmap of floating point values. +*/ +template +class ScalarImage +{ +public: + std::vector v; + int w,h; + void resize(int _w, int _h) { w=_w; h=_h; v.resize(w*h);} + bool Open(const char *filename); + ScalarType &Val(int x,int y) { + assert(x>=0 && x=0 && y=0 && x=0 && y maximum) + maximum = Val(xx, yy); + + Dilated.Val(x, y) = maximum; + } + } + + ScalarImage(QImage img); + ScalarImage(){}; + bool Subsample(const int factor, ScalarImage &fli); + static QPixmap colorizedScaledToHeight(const int desiredH, ScalarImage &fli, float colormax=10) + { + assert(fli.h>desiredH); + int factor = fli.h / desiredH; + + int newW=fli.w/factor -1; + int newH=fli.h/factor -1; + QImage newImage(newW,newH,QImage::Format_RGB32); + + for(int i=0;i FloatImage; +typedef ScalarImage CharImage; + + +#endif diff --git a/src/plugins_experimental/edit_epoch/ui/v3dImportDialog.ui b/src/plugins_experimental/edit_epoch/ui/v3dImportDialog.ui new file mode 100644 index 000000000..f449a923f --- /dev/null +++ b/src/plugins_experimental/edit_epoch/ui/v3dImportDialog.ui @@ -0,0 +1,678 @@ + + v3dImportDialog + + + + 0 + 0 + 792 + 606 + + + + + 0 + 0 + + + + V3D Import Settings + + + + + + + + TextLabel + + + + + + + + 0 + 0 + + + + TextLabel + + + + + + + + + SubSample + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + TextLabel + + + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the subsample factor:</p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 1 the image is not resized</p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 2 image is halved <span style=" font-style:italic;">(one point every 4)</span></p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> 3 image is reduced to one third <span style=" font-style:italic;">(one point every 9)</span></p></body></html> + + + + + + + + + + + Minimum Count + + + + + + + Qt::Horizontal + + + + 91 + 20 + + + + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the minimum number of match for a sample to be accepted</p><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3 means that only samples that had been found a correspondence with other 2 images or more are considered</p></body></html> + + + + + + + 0 + + + + + + 0 + 0 + + + + 10 + + + Qt::Horizontal + + + + + + + TextLabel + + + + + + + + + + + + + Minimum Angle + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 1 + + + 90.000000000000000 + + + 5.000000000000000 + + + 75.000000000000000 + + + + + + + + + + + Feature Aware Smoothing + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + 20.000000000000000 + + + 3.000000000000000 + + + + + + + + + + + Qt::RightToLeft + + + Remove pieces less than + + + true + + + + + + + + 0 + 0 + + + + When enabled, all the floating pieces smaller than the indicated percentage are deleted. Unit is the diagonal of the bounding box of the object + + + 0 + + + 25.000000000000000 + + + 5.000000000000000 + + + 5.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + Qt::RightToLeft + + + Close Holes less than + + + + + + + 5 + + + 10 + + + + + + + + + + + 1 + + + 6 + + + 1 + + + 5 + + + 2 + + + Qt::Horizontal + + + + + + + 1 + + + 10 + + + 3 + + + + + + + Size: + + + + + + + 5 x 5 + + + + + + + 1 + + + 5 + + + + + + + Num. passes: + + + + + + + 1 + + + 6 + + + 1 + + + 5 + + + 2 + + + Qt::Horizontal + + + + + + + 5 x 5 + + + + + + + Num. passes: + + + + + + + Depth Filter + + + + + + + Size: + + + + + + + Dilation + + + true + + + + + + + Erosion + + + true + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Perform a fast, fixed resolution merging of all the range maps. If unchecked all the rangemaps are simply put in the same space without merging them.</p></body></html> + + + Qt::RightToLeft + + + Fast merge + + + + + + + Resolution: Min + + + + + + + 1 + + + 5 + + + 3 + + + Qt::Horizontal + + + + + + + Max + + + + + + + + + + + Select + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 3 + + + + + + + + + + + Scaling Factor + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 1.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Process all selected range maps and save them as separated ply + + + Export as PLY + + + + + + + Cancel + + + + + + + + + + + + 0 + 0 + + + + 3 + + + + + + + + + + + + okButton + clicked() + v3dImportDialog + accept() + + + 554 + 682 + + + 342 + 405 + + + + + cancelButton + clicked() + v3dImportDialog + reject() + + + 637 + 682 + + + 425 + 433 + + + + + removeSmallCCCheckBox + toggled(bool) + maxCCDiagSpinBox + setEnabled(bool) + + + 348 + 584 + + + 637 + 584 + + + + + diff --git a/src/plugins_experimental/edit_epoch/ui_v3dImportDialog.h b/src/plugins_experimental/edit_epoch/ui_v3dImportDialog.h new file mode 100644 index 000000000..b9cef0530 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/ui_v3dImportDialog.h @@ -0,0 +1,555 @@ +/******************************************************************************** +** Form generated from reading UI file 'v3dImportDialog.ui' +** +** Created: Tue 31. Jan 16:30:15 2012 +** by: Qt User Interface Compiler version 4.7.2 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_V3DIMPORTDIALOG_H +#define UI_V3DIMPORTDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_v3dImportDialog +{ +public: + QHBoxLayout *hboxLayout; + QVBoxLayout *vboxLayout; + QLabel *infoLabel; + QLabel *previewLabel; + QHBoxLayout *hboxLayout1; + QLabel *label; + QSpacerItem *spacerItem; + QLabel *imgSizeLabel; + QSpinBox *subsampleSpinBox; + QHBoxLayout *hboxLayout2; + QLabel *label_2; + QSpacerItem *spacerItem1; + QSpinBox *minCountSpinBox; + QVBoxLayout *vboxLayout1; + QSlider *minCountSlider; + QLabel *rangeLabel; + QHBoxLayout *hboxLayout3; + QLabel *label_3; + QSpacerItem *spacerItem2; + QDoubleSpinBox *qualitySpinBox; + QHBoxLayout *hboxLayout4; + QLabel *label_5; + QSpacerItem *spacerItem3; + QDoubleSpinBox *smoothSpinBox; + QHBoxLayout *hboxLayout5; + QCheckBox *removeSmallCCCheckBox; + QDoubleSpinBox *maxCCDiagSpinBox; + QSpacerItem *spacerItem4; + QCheckBox *holeCheckBox; + QSpinBox *holeSpinBox; + QGridLayout *gridLayout; + QSlider *dilationSizeSlider; + QSpinBox *erosionNumPassSpinBox; + QLabel *lblDilationSize; + QLabel *lblErosionSizeValue; + QSpinBox *dilationNumPassSpinBox; + QLabel *lblDilationSteps; + QSlider *erosionSizeSlider; + QLabel *lblDilationSizeValue; + QLabel *lblErosionSteps; + QLabel *label_8; + QLabel *lblErosionSize; + QCheckBox *dilationCheckBox; + QCheckBox *erosionCheckBox; + QHBoxLayout *hboxLayout6; + QSpacerItem *spacerItem5; + QCheckBox *fastMergeCheckBox; + QLabel *label_6; + QSlider *mergeResolutionSpinBox; + QLabel *label_7; + QHBoxLayout *hboxLayout7; + QPushButton *selectButton; + QSpacerItem *spacerItem6; + QSpinBox *subsampleSequenceSpinBox; + QHBoxLayout *hboxLayout8; + QLabel *label_10; + QSpacerItem *spacerItem7; + QLineEdit *scaleLineEdit; + QHBoxLayout *hboxLayout9; + QSpacerItem *spacerItem8; + QPushButton *okButton; + QPushButton *plyButton; + QPushButton *cancelButton; + QTableWidget *imageTableWidget; + + void setupUi(QDialog *v3dImportDialog) + { + if (v3dImportDialog->objectName().isEmpty()) + v3dImportDialog->setObjectName(QString::fromUtf8("v3dImportDialog")); + v3dImportDialog->resize(792, 606); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(v3dImportDialog->sizePolicy().hasHeightForWidth()); + v3dImportDialog->setSizePolicy(sizePolicy); + hboxLayout = new QHBoxLayout(v3dImportDialog); + hboxLayout->setObjectName(QString::fromUtf8("hboxLayout")); + vboxLayout = new QVBoxLayout(); + vboxLayout->setObjectName(QString::fromUtf8("vboxLayout")); + infoLabel = new QLabel(v3dImportDialog); + infoLabel->setObjectName(QString::fromUtf8("infoLabel")); + + vboxLayout->addWidget(infoLabel); + + previewLabel = new QLabel(v3dImportDialog); + previewLabel->setObjectName(QString::fromUtf8("previewLabel")); + QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHeightForWidth(previewLabel->sizePolicy().hasHeightForWidth()); + previewLabel->setSizePolicy(sizePolicy1); + + vboxLayout->addWidget(previewLabel); + + hboxLayout1 = new QHBoxLayout(); + hboxLayout1->setObjectName(QString::fromUtf8("hboxLayout1")); + label = new QLabel(v3dImportDialog); + label->setObjectName(QString::fromUtf8("label")); + + hboxLayout1->addWidget(label); + + spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout1->addItem(spacerItem); + + imgSizeLabel = new QLabel(v3dImportDialog); + imgSizeLabel->setObjectName(QString::fromUtf8("imgSizeLabel")); + + hboxLayout1->addWidget(imgSizeLabel); + + subsampleSpinBox = new QSpinBox(v3dImportDialog); + subsampleSpinBox->setObjectName(QString::fromUtf8("subsampleSpinBox")); + + hboxLayout1->addWidget(subsampleSpinBox); + + + vboxLayout->addLayout(hboxLayout1); + + hboxLayout2 = new QHBoxLayout(); + hboxLayout2->setObjectName(QString::fromUtf8("hboxLayout2")); + label_2 = new QLabel(v3dImportDialog); + label_2->setObjectName(QString::fromUtf8("label_2")); + + hboxLayout2->addWidget(label_2); + + spacerItem1 = new QSpacerItem(91, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout2->addItem(spacerItem1); + + minCountSpinBox = new QSpinBox(v3dImportDialog); + minCountSpinBox->setObjectName(QString::fromUtf8("minCountSpinBox")); + + hboxLayout2->addWidget(minCountSpinBox); + + vboxLayout1 = new QVBoxLayout(); + vboxLayout1->setSpacing(0); + vboxLayout1->setObjectName(QString::fromUtf8("vboxLayout1")); + minCountSlider = new QSlider(v3dImportDialog); + minCountSlider->setObjectName(QString::fromUtf8("minCountSlider")); + QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Fixed); + sizePolicy2.setHorizontalStretch(0); + sizePolicy2.setVerticalStretch(0); + sizePolicy2.setHeightForWidth(minCountSlider->sizePolicy().hasHeightForWidth()); + minCountSlider->setSizePolicy(sizePolicy2); + minCountSlider->setMaximum(10); + minCountSlider->setOrientation(Qt::Horizontal); + + vboxLayout1->addWidget(minCountSlider); + + rangeLabel = new QLabel(v3dImportDialog); + rangeLabel->setObjectName(QString::fromUtf8("rangeLabel")); + + vboxLayout1->addWidget(rangeLabel); + + + hboxLayout2->addLayout(vboxLayout1); + + + vboxLayout->addLayout(hboxLayout2); + + hboxLayout3 = new QHBoxLayout(); + hboxLayout3->setObjectName(QString::fromUtf8("hboxLayout3")); + label_3 = new QLabel(v3dImportDialog); + label_3->setObjectName(QString::fromUtf8("label_3")); + + hboxLayout3->addWidget(label_3); + + spacerItem2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout3->addItem(spacerItem2); + + qualitySpinBox = new QDoubleSpinBox(v3dImportDialog); + qualitySpinBox->setObjectName(QString::fromUtf8("qualitySpinBox")); + qualitySpinBox->setDecimals(1); + qualitySpinBox->setMaximum(90); + qualitySpinBox->setSingleStep(5); + qualitySpinBox->setValue(75); + + hboxLayout3->addWidget(qualitySpinBox); + + + vboxLayout->addLayout(hboxLayout3); + + hboxLayout4 = new QHBoxLayout(); + hboxLayout4->setObjectName(QString::fromUtf8("hboxLayout4")); + label_5 = new QLabel(v3dImportDialog); + label_5->setObjectName(QString::fromUtf8("label_5")); + + hboxLayout4->addWidget(label_5); + + spacerItem3 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout4->addItem(spacerItem3); + + smoothSpinBox = new QDoubleSpinBox(v3dImportDialog); + smoothSpinBox->setObjectName(QString::fromUtf8("smoothSpinBox")); + smoothSpinBox->setDecimals(0); + smoothSpinBox->setMaximum(20); + smoothSpinBox->setValue(3); + + hboxLayout4->addWidget(smoothSpinBox); + + + vboxLayout->addLayout(hboxLayout4); + + hboxLayout5 = new QHBoxLayout(); + hboxLayout5->setObjectName(QString::fromUtf8("hboxLayout5")); + removeSmallCCCheckBox = new QCheckBox(v3dImportDialog); + removeSmallCCCheckBox->setObjectName(QString::fromUtf8("removeSmallCCCheckBox")); + removeSmallCCCheckBox->setLayoutDirection(Qt::RightToLeft); + removeSmallCCCheckBox->setChecked(true); + + hboxLayout5->addWidget(removeSmallCCCheckBox); + + maxCCDiagSpinBox = new QDoubleSpinBox(v3dImportDialog); + maxCCDiagSpinBox->setObjectName(QString::fromUtf8("maxCCDiagSpinBox")); + QSizePolicy sizePolicy3(QSizePolicy::Preferred, QSizePolicy::Fixed); + sizePolicy3.setHorizontalStretch(0); + sizePolicy3.setVerticalStretch(0); + sizePolicy3.setHeightForWidth(maxCCDiagSpinBox->sizePolicy().hasHeightForWidth()); + maxCCDiagSpinBox->setSizePolicy(sizePolicy3); + maxCCDiagSpinBox->setDecimals(0); + maxCCDiagSpinBox->setMaximum(25); + maxCCDiagSpinBox->setSingleStep(5); + maxCCDiagSpinBox->setValue(5); + + hboxLayout5->addWidget(maxCCDiagSpinBox); + + spacerItem4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout5->addItem(spacerItem4); + + holeCheckBox = new QCheckBox(v3dImportDialog); + holeCheckBox->setObjectName(QString::fromUtf8("holeCheckBox")); + holeCheckBox->setEnabled(true); + holeCheckBox->setLayoutDirection(Qt::RightToLeft); + + hboxLayout5->addWidget(holeCheckBox); + + holeSpinBox = new QSpinBox(v3dImportDialog); + holeSpinBox->setObjectName(QString::fromUtf8("holeSpinBox")); + holeSpinBox->setSingleStep(5); + holeSpinBox->setValue(10); + + hboxLayout5->addWidget(holeSpinBox); + + + vboxLayout->addLayout(hboxLayout5); + + gridLayout = new QGridLayout(); + gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + dilationSizeSlider = new QSlider(v3dImportDialog); + dilationSizeSlider->setObjectName(QString::fromUtf8("dilationSizeSlider")); + dilationSizeSlider->setMinimum(1); + dilationSizeSlider->setMaximum(6); + dilationSizeSlider->setSingleStep(1); + dilationSizeSlider->setPageStep(5); + dilationSizeSlider->setValue(2); + dilationSizeSlider->setOrientation(Qt::Horizontal); + + gridLayout->addWidget(dilationSizeSlider, 0, 5, 1, 1); + + erosionNumPassSpinBox = new QSpinBox(v3dImportDialog); + erosionNumPassSpinBox->setObjectName(QString::fromUtf8("erosionNumPassSpinBox")); + erosionNumPassSpinBox->setMinimum(1); + erosionNumPassSpinBox->setMaximum(10); + erosionNumPassSpinBox->setValue(3); + + gridLayout->addWidget(erosionNumPassSpinBox, 1, 3, 1, 1); + + lblDilationSize = new QLabel(v3dImportDialog); + lblDilationSize->setObjectName(QString::fromUtf8("lblDilationSize")); + + gridLayout->addWidget(lblDilationSize, 0, 4, 1, 1); + + lblErosionSizeValue = new QLabel(v3dImportDialog); + lblErosionSizeValue->setObjectName(QString::fromUtf8("lblErosionSizeValue")); + + gridLayout->addWidget(lblErosionSizeValue, 1, 6, 1, 1); + + dilationNumPassSpinBox = new QSpinBox(v3dImportDialog); + dilationNumPassSpinBox->setObjectName(QString::fromUtf8("dilationNumPassSpinBox")); + dilationNumPassSpinBox->setMinimum(1); + dilationNumPassSpinBox->setMaximum(5); + + gridLayout->addWidget(dilationNumPassSpinBox, 0, 3, 1, 1); + + lblDilationSteps = new QLabel(v3dImportDialog); + lblDilationSteps->setObjectName(QString::fromUtf8("lblDilationSteps")); + + gridLayout->addWidget(lblDilationSteps, 0, 2, 1, 1); + + erosionSizeSlider = new QSlider(v3dImportDialog); + erosionSizeSlider->setObjectName(QString::fromUtf8("erosionSizeSlider")); + erosionSizeSlider->setMinimum(1); + erosionSizeSlider->setMaximum(6); + erosionSizeSlider->setSingleStep(1); + erosionSizeSlider->setPageStep(5); + erosionSizeSlider->setValue(2); + erosionSizeSlider->setOrientation(Qt::Horizontal); + + gridLayout->addWidget(erosionSizeSlider, 1, 5, 1, 1); + + lblDilationSizeValue = new QLabel(v3dImportDialog); + lblDilationSizeValue->setObjectName(QString::fromUtf8("lblDilationSizeValue")); + + gridLayout->addWidget(lblDilationSizeValue, 0, 6, 1, 1); + + lblErosionSteps = new QLabel(v3dImportDialog); + lblErosionSteps->setObjectName(QString::fromUtf8("lblErosionSteps")); + + gridLayout->addWidget(lblErosionSteps, 1, 2, 1, 1); + + label_8 = new QLabel(v3dImportDialog); + label_8->setObjectName(QString::fromUtf8("label_8")); + + gridLayout->addWidget(label_8, 0, 0, 1, 1); + + lblErosionSize = new QLabel(v3dImportDialog); + lblErosionSize->setObjectName(QString::fromUtf8("lblErosionSize")); + + gridLayout->addWidget(lblErosionSize, 1, 4, 1, 1); + + dilationCheckBox = new QCheckBox(v3dImportDialog); + dilationCheckBox->setObjectName(QString::fromUtf8("dilationCheckBox")); + dilationCheckBox->setChecked(true); + + gridLayout->addWidget(dilationCheckBox, 0, 1, 1, 1); + + erosionCheckBox = new QCheckBox(v3dImportDialog); + erosionCheckBox->setObjectName(QString::fromUtf8("erosionCheckBox")); + erosionCheckBox->setChecked(true); + + gridLayout->addWidget(erosionCheckBox, 1, 1, 1, 1); + + + vboxLayout->addLayout(gridLayout); + + hboxLayout6 = new QHBoxLayout(); + hboxLayout6->setObjectName(QString::fromUtf8("hboxLayout6")); + spacerItem5 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout6->addItem(spacerItem5); + + fastMergeCheckBox = new QCheckBox(v3dImportDialog); + fastMergeCheckBox->setObjectName(QString::fromUtf8("fastMergeCheckBox")); + fastMergeCheckBox->setLayoutDirection(Qt::RightToLeft); + + hboxLayout6->addWidget(fastMergeCheckBox); + + label_6 = new QLabel(v3dImportDialog); + label_6->setObjectName(QString::fromUtf8("label_6")); + + hboxLayout6->addWidget(label_6); + + mergeResolutionSpinBox = new QSlider(v3dImportDialog); + mergeResolutionSpinBox->setObjectName(QString::fromUtf8("mergeResolutionSpinBox")); + mergeResolutionSpinBox->setMinimum(1); + mergeResolutionSpinBox->setMaximum(5); + mergeResolutionSpinBox->setValue(3); + mergeResolutionSpinBox->setOrientation(Qt::Horizontal); + + hboxLayout6->addWidget(mergeResolutionSpinBox); + + label_7 = new QLabel(v3dImportDialog); + label_7->setObjectName(QString::fromUtf8("label_7")); + + hboxLayout6->addWidget(label_7); + + + vboxLayout->addLayout(hboxLayout6); + + hboxLayout7 = new QHBoxLayout(); + hboxLayout7->setObjectName(QString::fromUtf8("hboxLayout7")); + selectButton = new QPushButton(v3dImportDialog); + selectButton->setObjectName(QString::fromUtf8("selectButton")); + + hboxLayout7->addWidget(selectButton); + + spacerItem6 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout7->addItem(spacerItem6); + + subsampleSequenceSpinBox = new QSpinBox(v3dImportDialog); + subsampleSequenceSpinBox->setObjectName(QString::fromUtf8("subsampleSequenceSpinBox")); + subsampleSequenceSpinBox->setValue(3); + + hboxLayout7->addWidget(subsampleSequenceSpinBox); + + + vboxLayout->addLayout(hboxLayout7); + + hboxLayout8 = new QHBoxLayout(); + hboxLayout8->setObjectName(QString::fromUtf8("hboxLayout8")); + label_10 = new QLabel(v3dImportDialog); + label_10->setObjectName(QString::fromUtf8("label_10")); + + hboxLayout8->addWidget(label_10); + + spacerItem7 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout8->addItem(spacerItem7); + + scaleLineEdit = new QLineEdit(v3dImportDialog); + scaleLineEdit->setObjectName(QString::fromUtf8("scaleLineEdit")); + scaleLineEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + + hboxLayout8->addWidget(scaleLineEdit); + + + vboxLayout->addLayout(hboxLayout8); + + hboxLayout9 = new QHBoxLayout(); + hboxLayout9->setObjectName(QString::fromUtf8("hboxLayout9")); + spacerItem8 = new QSpacerItem(131, 31, QSizePolicy::Expanding, QSizePolicy::Minimum); + + hboxLayout9->addItem(spacerItem8); + + okButton = new QPushButton(v3dImportDialog); + okButton->setObjectName(QString::fromUtf8("okButton")); + + hboxLayout9->addWidget(okButton); + + plyButton = new QPushButton(v3dImportDialog); + plyButton->setObjectName(QString::fromUtf8("plyButton")); + + hboxLayout9->addWidget(plyButton); + + cancelButton = new QPushButton(v3dImportDialog); + cancelButton->setObjectName(QString::fromUtf8("cancelButton")); + + hboxLayout9->addWidget(cancelButton); + + + vboxLayout->addLayout(hboxLayout9); + + + hboxLayout->addLayout(vboxLayout); + + imageTableWidget = new QTableWidget(v3dImportDialog); + if (imageTableWidget->columnCount() < 3) + imageTableWidget->setColumnCount(3); + imageTableWidget->setObjectName(QString::fromUtf8("imageTableWidget")); + QSizePolicy sizePolicy4(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); + sizePolicy4.setHorizontalStretch(0); + sizePolicy4.setVerticalStretch(0); + sizePolicy4.setHeightForWidth(imageTableWidget->sizePolicy().hasHeightForWidth()); + imageTableWidget->setSizePolicy(sizePolicy4); + imageTableWidget->setColumnCount(3); + + hboxLayout->addWidget(imageTableWidget); + + + retranslateUi(v3dImportDialog); + QObject::connect(okButton, SIGNAL(clicked()), v3dImportDialog, SLOT(accept())); + QObject::connect(cancelButton, SIGNAL(clicked()), v3dImportDialog, SLOT(reject())); + QObject::connect(removeSmallCCCheckBox, SIGNAL(toggled(bool)), maxCCDiagSpinBox, SLOT(setEnabled(bool))); + + QMetaObject::connectSlotsByName(v3dImportDialog); + } // setupUi + + void retranslateUi(QDialog *v3dImportDialog) + { + v3dImportDialog->setWindowTitle(QApplication::translate("v3dImportDialog", "V3D Import Settings", 0, QApplication::UnicodeUTF8)); + infoLabel->setText(QApplication::translate("v3dImportDialog", "TextLabel", 0, QApplication::UnicodeUTF8)); + previewLabel->setText(QApplication::translate("v3dImportDialog", "TextLabel", 0, QApplication::UnicodeUTF8)); + label->setText(QApplication::translate("v3dImportDialog", "SubSample", 0, QApplication::UnicodeUTF8)); + imgSizeLabel->setText(QApplication::translate("v3dImportDialog", "TextLabel", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + subsampleSpinBox->setToolTip(QApplication::translate("v3dImportDialog", "

Set the subsample factor:

1 the image is not resized

2 image is halved (one point every 4)

3 image is reduced to one third (one point every 9)

", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + label_2->setText(QApplication::translate("v3dImportDialog", "Minimum Count", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + minCountSpinBox->setToolTip(QApplication::translate("v3dImportDialog", "

Set the minimum number of match for a sample to be accepted

3 means that only samples that had been found a correspondence with other 2 images or more are considered

", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + rangeLabel->setText(QApplication::translate("v3dImportDialog", "TextLabel", 0, QApplication::UnicodeUTF8)); + label_3->setText(QApplication::translate("v3dImportDialog", "Minimum Angle", 0, QApplication::UnicodeUTF8)); + label_5->setText(QApplication::translate("v3dImportDialog", "Feature Aware Smoothing", 0, QApplication::UnicodeUTF8)); + removeSmallCCCheckBox->setText(QApplication::translate("v3dImportDialog", "Remove pieces less than", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + maxCCDiagSpinBox->setToolTip(QApplication::translate("v3dImportDialog", "When enabled, all the floating pieces smaller than the indicated percentage are deleted. Unit is the diagonal of the bounding box of the object", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + holeCheckBox->setText(QApplication::translate("v3dImportDialog", "Close Holes less than", 0, QApplication::UnicodeUTF8)); + lblDilationSize->setText(QApplication::translate("v3dImportDialog", "Size:", 0, QApplication::UnicodeUTF8)); + lblErosionSizeValue->setText(QApplication::translate("v3dImportDialog", "5 x 5", 0, QApplication::UnicodeUTF8)); + lblDilationSteps->setText(QApplication::translate("v3dImportDialog", "Num. passes:", 0, QApplication::UnicodeUTF8)); + lblDilationSizeValue->setText(QApplication::translate("v3dImportDialog", "5 x 5", 0, QApplication::UnicodeUTF8)); + lblErosionSteps->setText(QApplication::translate("v3dImportDialog", "Num. passes:", 0, QApplication::UnicodeUTF8)); + label_8->setText(QApplication::translate("v3dImportDialog", "Depth Filter", 0, QApplication::UnicodeUTF8)); + lblErosionSize->setText(QApplication::translate("v3dImportDialog", "Size:", 0, QApplication::UnicodeUTF8)); + dilationCheckBox->setText(QApplication::translate("v3dImportDialog", "Dilation", 0, QApplication::UnicodeUTF8)); + erosionCheckBox->setText(QApplication::translate("v3dImportDialog", "Erosion", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + fastMergeCheckBox->setToolTip(QApplication::translate("v3dImportDialog", "

Perform a fast, fixed resolution merging of all the range maps. If unchecked all the rangemaps are simply put in the same space without merging them.

", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + fastMergeCheckBox->setText(QApplication::translate("v3dImportDialog", "Fast merge", 0, QApplication::UnicodeUTF8)); + label_6->setText(QApplication::translate("v3dImportDialog", "Resolution: Min", 0, QApplication::UnicodeUTF8)); + label_7->setText(QApplication::translate("v3dImportDialog", "Max", 0, QApplication::UnicodeUTF8)); + selectButton->setText(QApplication::translate("v3dImportDialog", "Select", 0, QApplication::UnicodeUTF8)); + label_10->setText(QApplication::translate("v3dImportDialog", "Scaling Factor", 0, QApplication::UnicodeUTF8)); + scaleLineEdit->setInputMask(QString()); + scaleLineEdit->setText(QApplication::translate("v3dImportDialog", "1.0", 0, QApplication::UnicodeUTF8)); + okButton->setText(QApplication::translate("v3dImportDialog", "OK", 0, QApplication::UnicodeUTF8)); +#ifndef QT_NO_TOOLTIP + plyButton->setToolTip(QApplication::translate("v3dImportDialog", "Process all selected range maps and save them as separated ply", 0, QApplication::UnicodeUTF8)); +#endif // QT_NO_TOOLTIP + plyButton->setText(QApplication::translate("v3dImportDialog", "Export as PLY", 0, QApplication::UnicodeUTF8)); + cancelButton->setText(QApplication::translate("v3dImportDialog", "Cancel", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class v3dImportDialog: public Ui_v3dImportDialog {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_V3DIMPORTDIALOG_H diff --git a/src/plugins_experimental/edit_epoch/v3dImportDialog.cpp b/src/plugins_experimental/edit_epoch/v3dImportDialog.cpp new file mode 100644 index 000000000..3acea1c37 --- /dev/null +++ b/src/plugins_experimental/edit_epoch/v3dImportDialog.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* 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 +#include +#include + +#include "v3dImportDialog.h" +#include "maskImageWidget.h" +using namespace vcg; + +// small helper function for generating a color ramp pixmap to be used in the import dialog. + +QPixmap generateColorRamp() +{ + const int width=100; + const int height=15; + Color4b ramp; + QImage newImage(width,height,QImage::Format_RGB32); + + for(int x=0;xcreated) + { + er=_er; + return; + } + + er=_er; + erCreated=er->created; + infoLabel->setText(er->name + " - " + er->author + " - " + er->created); + + imageTableWidget->clear(); + imageTableWidget->setRowCount(er->modelList.size()); + imageTableWidget->setColumnCount(4); + //imageTableWidget->setColumnWidth (1,64); + imageTableWidget->setSelectionBehavior (QAbstractItemView::SelectRows); + imageTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + imageTableWidget->setMinimumWidth(64*8); + + rangeLabel->setPixmap(generateColorRamp()); + rangeLabel->setMaximumHeight(10); + rangeLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + rangeLabel->setScaledContents(true); + + minCountSlider->setMaximumHeight(12); + + int i; + for(i=0; imodelList.size() ;++i) + { + //cb(i*100/er->modelList.size(),"Reading images"); + + QString ThumbImgName=EpochModel::ThumbName(er->modelList[i].textureName); + QString ThumbCntName=EpochModel::ThumbName(er->modelList[i].countName); + + imageTableWidget->setRowHeight (i,64); + QTableWidgetItem *emptyHeaderItem = new QTableWidgetItem(i*2); + QTableWidgetItem *texNameHeaderItem = new QTableWidgetItem(er->modelList[i].textureName,i); + imageTableWidget->setItem(i, 0, texNameHeaderItem); + imageTableWidget->setItem(i, 1, emptyHeaderItem); + QLabel *imageLabel = new QLabel(imageTableWidget); + if(!QFile::exists(ThumbImgName)) + { + QPixmap(er->modelList[i].textureName).scaledToHeight(64).save(ThumbImgName,"jpg"); + if(!QFile::exists(ThumbImgName)) + QMessageBox::warning(this,"Error in Thumb creation", + QString("Unable to create '%1' from '%2'").arg(ThumbImgName),er->modelList[i].textureName); + } + + imageLabel->setPixmap(QPixmap(EpochModel::ThumbName(er->modelList[i].textureName))); + imageTableWidget->setCellWidget(i,1,imageLabel); + if(QFile::exists(er->modelList[i].maskName)) + { + QTableWidgetItem *emptyHeaderItem = new QTableWidgetItem(i*4); + imageTableWidget->setItem(i, 2, emptyHeaderItem); + QLabel *maskLabel = new QLabel(imageTableWidget); + maskLabel->setPixmap(QPixmap(er->modelList[i].maskName).scaledToHeight(64)); + imageTableWidget->setCellWidget(i,2,maskLabel); + } + else + { + QTableWidgetItem *maskHeaderItem = new QTableWidgetItem(QString("double click for\nediting the mask"),i*3); + imageTableWidget->setItem(i, 2, maskHeaderItem); + } + + if(!QFile::exists(ThumbCntName)) + { + CharImage chi; + bool ret=chi.Open(er->modelList[i].countName.toAscii()); + if(!ret) QMessageBox::warning(this,"Error in Thumb creation",QString("Unable to create '%1' from '%2'").arg(ThumbCntName,er->modelList[i].textureName)); + + CharImage::colorizedScaledToHeight(64,chi).save(ThumbCntName,"jpg"); + if(!QFile::exists(ThumbCntName)) + QMessageBox::warning(this,"Error in Thumb creation",QString("Unable to create '%1' from '%2'").arg(ThumbCntName,er->modelList[i].textureName)); + } + QLabel *countLabel = new QLabel(imageTableWidget); + countLabel->setPixmap(QPixmap(ThumbCntName)); + QPixmap tmp(ThumbCntName); + if(tmp.isNull()) + QMessageBox::warning(this,"Error in Thumb creation",QString("Null Pixmap '%1'").arg(ThumbCntName)); + imageTableWidget->setCellWidget(i,3,countLabel); + } + +//cb(100,"Completed Image Reading."); + +show(); // necessary to make the size of the image preview correct. +imageTableWidget->setItemSelected(imageTableWidget->item(0,0),true); +imageTableWidget->setItemSelected(imageTableWidget->item(0,1),true); +imageTableWidget->setItemSelected(imageTableWidget->item(0,2),true); +//on_imageTableWidget_itemSelectionChanged(); + +} + +void v3dImportDialog::on_imageTableWidget_itemSelectionChanged() +{ + if(imageTableWidget->selectedItems().size()==3) + { + int row= imageTableWidget->row(imageTableWidget->selectedItems().first()); + QPixmap tmp(er->modelList[row].textureName); + imgSize=tmp.size(); + previewLabel->setPixmap(tmp.scaled(previewLabel->size(),Qt::KeepAspectRatio) ); + on_subsampleSpinBox_valueChanged(subsampleSpinBox->value()); + } +} +void v3dImportDialog::on_plyButton_clicked() +{ + exportToPLY = true; + accept(); +} +void v3dImportDialog::on_selectButton_clicked() +{ + int itemNum=imageTableWidget->rowCount(); + int modVal=subsampleSequenceSpinBox->value(); + if(modVal==0) return; + + for(int i=0;isetRangeSelected(QTableWidgetSelectionRange(i,0,i,2),true); +} + +void v3dImportDialog::on_imageTableWidget_itemClicked(QTableWidgetItem * item ) +{ + int row= imageTableWidget->row(item); + previewLabel->setPixmap( + QPixmap(er->modelList[row].textureName).scaled(previewLabel->size(),Qt::KeepAspectRatio) ); + +} + +void v3dImportDialog::on_imageTableWidget_itemDoubleClicked(QTableWidgetItem * item ) +{ + int row= imageTableWidget->row(item); + int col= imageTableWidget->column(item); + if(col!=2) return; + qDebug("DoubleClicked on image %s",qPrintable(er->modelList[row].textureName)); + QImage ttt(er->modelList[row].textureName); + qDebug("'%s' %i x %i",qPrintable(er->modelList[row].textureName),ttt.width(),ttt.height()); + //ui::maskImageWidget masker(QImage(er->modelList[row].textureName)); + ui::maskImageWidget masker(ttt); + if (QFile::exists(er->modelList[row].maskName)) + masker.loadMask(er->modelList[row].maskName); + + QImage mymask; + if (masker.exec() == QDialog::Accepted) mymask = masker.getMask(); + if (!mymask.isNull()) + { + mymask.save(er->modelList[row].maskName,"png"); + QLabel *imageLabel = new QLabel(imageTableWidget); + imageLabel->setPixmap(QPixmap(er->modelList[row].maskName).scaledToHeight(64)); + imageTableWidget->itemAt(row,2)->setText(""); + imageTableWidget->setCellWidget(row,2,imageLabel); + } +} + + + +void v3dImportDialog::on_minCountSpinBox_valueChanged(int val) +{ + if(minCountSlider->value()!=val) minCountSlider->setValue(val); +} + +void v3dImportDialog::on_minCountSlider_valueChanged(int val) +{ + if(minCountSpinBox->value()!=val) minCountSpinBox->setValue(val); +} + +void v3dImportDialog::on_subsampleSpinBox_valueChanged(int) +{ + int ss=subsampleSpinBox->value(); + if(ss==0) + { + subsampleSpinBox->setValue(1); + return; + } + imgSizeLabel->setText(QString("(%1 x %2) -> (%3 x %4)").arg(imgSize.width()).arg(imgSize.height()).arg(imgSize.width()/ss).arg(imgSize.height()/ss) ); +} + +void v3dImportDialog::on_mergeResolutionSpinBox_valueChanged(int) +{ + fastMergeCheckBox->setChecked(true); // if someone touch the slider check the fast merging box +} + +void v3dImportDialog::dilationSizeChanged(int size) +{ + int winsize = size * 2 + 1; + QString str = QString("%1 x %2").arg(winsize).arg(winsize); + lblDilationSizeValue->setText(str); +} + +void v3dImportDialog::erosionSizeChanged(int size) +{ + int winsize = size * 2 + 1; + QString str = QString("%1 x %2").arg(winsize).arg(winsize); + lblErosionSizeValue->setText(str); +} diff --git a/src/plugins_experimental/edit_epoch/v3dImportDialog.h b/src/plugins_experimental/edit_epoch/v3dImportDialog.h new file mode 100644 index 000000000..72cd7efbd --- /dev/null +++ b/src/plugins_experimental/edit_epoch/v3dImportDialog.h @@ -0,0 +1,81 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef V3DIMPORTER_DIALOG_H +#define V3DIMPORTER_DIALOG_H + +// for options on decimator +#include +#include +#include "ui_v3dImportDialog.h" +#include "epoch_reconstruction.h" + +class v3dImportDialog : public QDialog, public Ui::v3dImportDialog { + +Q_OBJECT + +public: + v3dImportDialog() : QDialog() + { + setupUi( this ); + subsampleSpinBox->setValue(2); + minCountSpinBox->setValue(3); + + // connections + connect(dilationSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(dilationSizeChanged(int))); + connect(erosionSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(erosionSizeChanged(int))); + + er=0; + exportToPLY=false; + + fileName = QFileDialog::getOpenFileName(this->parentWidget(), tr("Select v3D File"), ".", "*.v3d"); + } + +public: + void setEpochReconstruction(EpochReconstruction *_er); + bool exportToPLY; /// when true all the selected range maps are exported as separated ply + QString fileName; + +public slots: +void on_selectButton_clicked(); +void on_imageTableWidget_itemClicked(QTableWidgetItem * item ); +void on_imageTableWidget_itemSelectionChanged(); +void on_imageTableWidget_itemDoubleClicked(QTableWidgetItem * item ); +void on_plyButton_clicked(); +private: +EpochReconstruction *er; +QString erCreated; + +QSize imgSize; + + +private slots: + void on_mergeResolutionSpinBox_valueChanged(int); + void on_subsampleSpinBox_valueChanged(int); + void on_minCountSlider_valueChanged(int); + void on_minCountSpinBox_valueChanged(int); + void dilationSizeChanged(int); + void erosionSizeChanged(int); +}; + +#endif