mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-19 19:14:42 +00:00
renamed epoch_io plugin to the standard io_epoch naming scheme
This commit is contained in:
parent
e8c0a381d1
commit
ab63abfa6e
@ -1,88 +0,0 @@
|
||||
#include <vector>
|
||||
#include <vcg/math/matrix33.h>
|
||||
#include <vcg/math/matrix44.h>
|
||||
#include <vcg/space/point3.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
|
||||
namespace vcg
|
||||
{
|
||||
class EpochCamera
|
||||
{
|
||||
public:
|
||||
Matrix33d K; // parametri intriseci camera
|
||||
Matrix33d Kinv;
|
||||
|
||||
std::vector<double> 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);
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,781 +0,0 @@
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* An extendible mesh processor o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005, 2006 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
History
|
||||
|
||||
$Log$
|
||||
Revision 1.22 2008/04/04 14:08:07 cignoni
|
||||
Solved namespace ambiguities caused by the removal of a silly 'using namespace' in meshmodel.h
|
||||
|
||||
Revision 1.21 2008/03/06 08:20:50 cignoni
|
||||
updated to the new histogram
|
||||
|
||||
Revision 1.20 2008/02/12 21:59:02 cignoni
|
||||
removed mask bug and added scaling of maps
|
||||
|
||||
Revision 1.19 2007/11/26 07:35:26 cignoni
|
||||
Yet another small cosmetic change to the interface of the io filters.
|
||||
|
||||
Revision 1.18 2007/10/12 10:09:29 corsini
|
||||
signed/unsigned warning removed
|
||||
|
||||
Revision 1.17 2007/10/12 10:06:58 corsini
|
||||
fix some warnings
|
||||
|
||||
Revision 1.16 2007/10/08 08:55:44 cignoni
|
||||
Added automatic exporting of ply and aln from the dialog
|
||||
|
||||
Revision 1.15 2007/04/16 09:25:29 cignoni
|
||||
** big change **
|
||||
Added Layers managemnt.
|
||||
Interfaces are changing again...
|
||||
|
||||
Revision 1.14 2007/03/20 16:23:08 cignoni
|
||||
Big small change in accessing mesh interface. First step toward layers
|
||||
|
||||
Revision 1.13 2007/03/20 15:52:46 cignoni
|
||||
Patched issue related to path with non ascii chars
|
||||
|
||||
Revision 1.12 2007/02/26 11:41:07 corsini
|
||||
add more control to depth filter through interface paramters
|
||||
|
||||
Revision 1.11 2007/01/24 08:33:15 cignoni
|
||||
Still experiments in filtering depth jumps
|
||||
|
||||
Revision 1.10 2007/01/23 14:31:16 corsini
|
||||
add improved depth filtering to remove artifacts
|
||||
|
||||
Revision 1.9 2007/01/23 11:38:55 cignoni
|
||||
Added depth jump control in laplacian smoothing of featureless areas of depthmap
|
||||
|
||||
Revision 1.8 2007/01/23 10:50:44 cignoni
|
||||
Better comments and variable names
|
||||
|
||||
Revision 1.7 2007/01/23 09:21:28 corsini
|
||||
add mean+erosion filter
|
||||
|
||||
Revision 1.6 2007/01/11 11:48:04 cignoni
|
||||
Reordered include
|
||||
|
||||
Revision 1.5 2006/12/06 21:25:00 cignoni
|
||||
small optimization and logging for profiling
|
||||
|
||||
Revision 1.4 2006/11/30 11:40:33 cignoni
|
||||
Updated the calls to the hole filling functions to the new interface
|
||||
|
||||
Revision 1.3 2006/11/29 00:59:16 cignoni
|
||||
Cleaned plugins interface; changed useless help class into a plain string
|
||||
|
||||
Revision 1.2 2006/11/08 15:49:42 cignoni
|
||||
Added quality to the loaded masks
|
||||
|
||||
Revision 1.1 2006/11/07 18:14:21 cignoni
|
||||
Moved from the epoch svn repository
|
||||
|
||||
Revision 1.1 2006/01/20 13:03:27 cignoni
|
||||
*** empty log message ***
|
||||
|
||||
*****************************************************************************/
|
||||
#include <Qt>
|
||||
#include <QtGui>
|
||||
#include <QtXml/QDomDocument>
|
||||
#include <QtXml/QDomElement>
|
||||
#include <QtXml/QDomNode>
|
||||
|
||||
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "epoch_io.h"
|
||||
#include "epoch_reconstruction.h"
|
||||
#include <vcg/math/matrix33.h>
|
||||
#include <vcg/math/histogram.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include <vcg/complex/trimesh/create/platonic.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include <vcg/complex/trimesh/append.h>
|
||||
#include <vcg/complex/trimesh/clustering.h>
|
||||
#include <vcg/complex/trimesh/update/normal.h>
|
||||
#include <vcg/complex/trimesh/update/position.h>
|
||||
#include <vcg/complex/trimesh/hole.h>
|
||||
#include <wrap/io_trimesh/io_mask.h>
|
||||
#include <wrap/io_trimesh/export_ply.h>
|
||||
#include "../cleanfilter/remove_small_cc.h"
|
||||
#include <meshlab/alnParser.h>
|
||||
|
||||
FILE *logFP=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<int>(depthImgf.v.size()); ++i)
|
||||
HH.Add(fabs(depthImgf.v[i]-depth.v[i-1]));
|
||||
|
||||
if(logFP) fprintf(logFP,"**** 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<float>(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(logFP) fprintf(logFP,"**** 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<unsigned int>(depthImgf.v.size()); ++i)
|
||||
HH.Add(fabs(depthImgf.v[i]-depthImgf.v[i-1]));
|
||||
|
||||
if(logFP) fprintf(logFP,"**** 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;j<maskImg.height();++j)
|
||||
for(int i=0;i<maskImg.width();++i)
|
||||
if(qRed(maskImg.pixel(i,j))>128)
|
||||
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;i<w;++i)
|
||||
for(int j=0;j<h;++j)
|
||||
{
|
||||
float maxcount=0;
|
||||
int cnt=0;
|
||||
float bestVal=0;
|
||||
for(int ki=0;ki<factor;++ki)
|
||||
for(int kj=0;kj<factor;++kj)
|
||||
{
|
||||
float q= chi.Val(i*factor+ki,j*factor+kj) - minCount+1 ;
|
||||
if(q>0)
|
||||
{
|
||||
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;y<h-1;++y)
|
||||
for(int x=1;x<w-1;++x)
|
||||
{
|
||||
float curDepth=depthImg.Val(x,y);
|
||||
int cnt=0;
|
||||
for(int j=-1;j<=1;++j)
|
||||
for(int i=-1;i<=1;++i)
|
||||
{
|
||||
int q=countImg.Val(x+i,y+j)-minCount+1;
|
||||
if(q>0 && 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<h-1;++y)
|
||||
for(int x=1;x<w-1;++x)
|
||||
{
|
||||
float q=(featureMask.Val(x,y)/255.0);
|
||||
depthImg.Val(x,y) = depthImg.Val(x,y)*q + Sum.Val(x,y)*(1-q);
|
||||
}
|
||||
}
|
||||
|
||||
// It generate a feature mask that mark the featureless area of the original photo.
|
||||
// Featureless areas are usually affected by noise and have to be smoothed more
|
||||
|
||||
void EpochModel::GenerateGradientSmoothingMask(int subsampleFactor, QImage &OriginalTexture, CharImage &mask)
|
||||
{
|
||||
CharImage gray(OriginalTexture);
|
||||
CharImage grad;
|
||||
grad.resize(gray.w,gray.h);
|
||||
int w=gray.w,h=gray.h;
|
||||
for(int x=1;x<w-1;++x)
|
||||
for(int y=1;y<h-1;++y)
|
||||
{
|
||||
int dx=abs(int(gray.Val(x,y))-int(gray.Val(x-1,y))) + abs(int(gray.Val(x,y))-int(gray.Val(x+1,y)));
|
||||
int dy=abs(int(gray.Val(x,y))-int(gray.Val(x,y-1))) + abs(int(gray.Val(x,y))-int(gray.Val(x,y+1)));
|
||||
grad.Val(x,y)=min(255,16*dx+dy);
|
||||
}
|
||||
|
||||
// create subsampled mask
|
||||
int ws=gray.w/subsampleFactor, hs=gray.h/subsampleFactor;
|
||||
mask.resize(ws,hs);
|
||||
|
||||
for(int x=0;x<ws;++x)
|
||||
for(int y=0;y<hs;++y)
|
||||
{
|
||||
unsigned char maxGrad=0;
|
||||
for(int si=0;si<subsampleFactor;++si)
|
||||
for(int sj=0;sj<subsampleFactor;++sj)
|
||||
maxGrad = max(maxGrad, grad.Val(x*subsampleFactor+sj,y*subsampleFactor+si));
|
||||
|
||||
mask.Val(x,y) = maxGrad;
|
||||
}
|
||||
|
||||
CharImage mask2;
|
||||
mask2.resize(ws, hs);
|
||||
|
||||
// average filter (11 x 11)
|
||||
int avg;
|
||||
int wsize = 5;
|
||||
for (int y = wsize; y < hs-wsize; y++)
|
||||
for (int x = wsize; x < ws-wsize; x++)
|
||||
{
|
||||
avg = 0;
|
||||
for (int yy = y - wsize; yy <= y + wsize; yy++)
|
||||
for (int xx = x - wsize; xx <= x + wsize; xx++)
|
||||
avg += mask.Val(xx, yy);
|
||||
|
||||
mask2.Val(x, y) = min(255, avg / ((2 * wsize + 1)* (2 * wsize +1)));
|
||||
}
|
||||
|
||||
mask.convertToQImage().save("tmp_testmask.jpg","jpg");
|
||||
mask2.convertToQImage().save("tmp_testmaskSmooth.jpg","jpg");
|
||||
|
||||
// erosion filter (7 x 7)
|
||||
int minimum;
|
||||
wsize = 3;
|
||||
for (int y = wsize; y < hs-wsize; y++)
|
||||
for (int x = wsize; x < ws-wsize; x++)
|
||||
{
|
||||
minimum = mask2.Val(x, y);
|
||||
for (int yy = y - wsize; yy <= y + wsize; yy++)
|
||||
for (int xx = x - wsize; xx <= x + wsize; xx++)
|
||||
if (mask2.Val(xx, yy) < minimum)
|
||||
minimum = mask2.Val(xx, yy);
|
||||
|
||||
mask.Val(x, y) = minimum;
|
||||
}
|
||||
|
||||
grad.convertToQImage().save("tmp_test.jpg","jpg");
|
||||
mask.convertToQImage().save("tmp_testmaskeroded.jpg","jpg");
|
||||
}
|
||||
|
||||
/*
|
||||
Main processing function;
|
||||
|
||||
it takes a depth map, a count map,
|
||||
- resample them to a (width/subsample,height/subsample) image
|
||||
- leave only the faces that are within a given orientation range
|
||||
- that have a count greater than minCount.
|
||||
- and smooth them with a count/quality aware laplacian filter
|
||||
*/
|
||||
|
||||
bool EpochModel::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)
|
||||
{
|
||||
FloatImage depthImgf;
|
||||
CharImage countImgc;
|
||||
int ttt0=clock();
|
||||
depthImgf.Open(depthName.toAscii());
|
||||
countImgc.Open(countName.toAscii());
|
||||
|
||||
QImage TextureImg;
|
||||
TextureImg.load(textureName);
|
||||
int ttt1=clock();
|
||||
if(logFP) fprintf(logFP,"**** Buildmesh: Opening files %i\n",ttt1-ttt0);
|
||||
|
||||
CombineHandMadeMaskAndCount(countImgc,maskName); // set count to zero for all masked points
|
||||
|
||||
FloatImage depthSubf; // the subsampled depth image
|
||||
FloatImage countSubf; // the subsampled quality image (quality == count)
|
||||
|
||||
SmartSubSample(subsampleFactor,depthImgf,countImgc,depthSubf,countSubf,minCount);
|
||||
|
||||
CharImage FeatureMask; // the subsampled image with (quality == features)
|
||||
GenerateGradientSmoothingMask(subsampleFactor, TextureImg, FeatureMask);
|
||||
|
||||
depthSubf.convertToQImage().save("tmp_depth.jpg", "jpg");
|
||||
|
||||
int ttt2=clock();
|
||||
if(logFP) fprintf(logFP,"**** Buildmesh: SubSample and Gradient %i\n",ttt2-ttt1);
|
||||
|
||||
float depthThr = ComputeDepthJumpThr(depthSubf,0.8f);
|
||||
for(int ii=0;ii<smoothSteps;++ii)
|
||||
Laplacian2(depthSubf,countSubf,minCount,FeatureMask,depthThr);
|
||||
|
||||
int ttt3=clock();
|
||||
if(logFP) fprintf(logFP,"**** Buildmesh: Smoothing %i\n",ttt3-ttt2);
|
||||
|
||||
vcg::tri::Grid<CMeshO>(m,depthSubf.w,depthSubf.h,depthImgf.w,depthImgf.h,&*depthSubf.v.begin());
|
||||
|
||||
int ttt4=clock();
|
||||
if(logFP) fprintf(logFP,"**** 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;i<vn;++i)
|
||||
if(countSubf.v[i]<minCount)
|
||||
{
|
||||
m.vert[i].SetD();
|
||||
m.vn--;
|
||||
}
|
||||
|
||||
cam.Open(cameraName.toAscii());
|
||||
CMeshO::VertexIterator vi;
|
||||
Matrix33d Rinv= Inverse(cam.R);
|
||||
|
||||
for(vi=m.vert.begin();vi!=m.vert.end();++vi)if(!(*vi).IsD())
|
||||
{
|
||||
Point3f in=(*vi).P();
|
||||
Point3d out;
|
||||
cam.DepthTo3DPoint(in[0], in[1], in[2], out);
|
||||
|
||||
(*vi).P().Import(out);
|
||||
QRgb c = TextureImg.pixel(int(in[0]), int(in[1]));
|
||||
(*vi).C().SetRGB(qRed(c),qGreen(c),qBlue(c));
|
||||
//(*vi).Q()=chi.Val(in[0], in[1]);
|
||||
//(*vi).Q()=flisubQ.Val(in[0]/subsample, in[1]/subsample);
|
||||
if(FeatureMask.Val(int(in[0]/subsampleFactor), int(in[1]/subsampleFactor))<200) (*vi).Q()=0;
|
||||
else (*vi).Q()=1;
|
||||
(*vi).Q()=float(FeatureMask.Val(in[0]/subsampleFactor, in[1]/subsampleFactor))/255.0;
|
||||
}
|
||||
|
||||
int ttt5=clock();
|
||||
if(logFP) fprintf(logFP,"**** Buildmesh: Projecting and Coloring %i\n",ttt5-ttt4);
|
||||
|
||||
CMeshO::FaceIterator fi;
|
||||
Point3f CameraPos=Point3f::Construct(cam.t);
|
||||
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
||||
{
|
||||
|
||||
if((*fi).V(0)->IsD() ||(*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ttt6=clock();
|
||||
if(logFP) fprintf(logFP,"**** Buildmesh: Deleting skewed %i\n",ttt6-ttt5);
|
||||
|
||||
// Matrix44d Rot;
|
||||
// Rot.SetRotate(M_PI,Point3d(1,0,0));
|
||||
// vcg::tri::UpdatePosition<CMeshO>::Matrix(m, Rot);
|
||||
|
||||
Matrix44f scaleMat;
|
||||
scaleMat.SetScale(scalingFactor,scalingFactor,scalingFactor);
|
||||
vcg::tri::UpdatePosition<CMeshO>::Matrix(m, scaleMat);
|
||||
|
||||
return true;
|
||||
}
|
||||
void EpochModel::AddCameraIcon(CMeshO &m)
|
||||
{
|
||||
tri::Allocator<CMeshO>::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<CMeshO>::AddFaces(m,1);
|
||||
m.face[m.face.size()-1].V(0)= &m.vert[m.vert.size()-3];
|
||||
m.face[m.face.size()-1].V(1)= &m.vert[m.vert.size()-2];
|
||||
m.face[m.face.size()-1].V(2)= &m.vert[m.vert.size()-1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool EpochModel::Init(QDomNode &node)
|
||||
{
|
||||
if(!node.hasAttributes()) return false;
|
||||
QDomNamedNodeMap attr= node.attributes();
|
||||
QString indexString = (attr.namedItem("index")).nodeValue() ;
|
||||
qDebug("reading Model with index %i ",indexString.toInt());
|
||||
for(QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling())
|
||||
{
|
||||
if(n.nodeName() == QString("camera")) cameraName = n.attributes().namedItem("filename").nodeValue();
|
||||
if(n.nodeName() == QString("texture")) textureName= n.attributes().namedItem("filename").nodeValue();
|
||||
if(n.nodeName() == QString("depth")) depthName = n.attributes().namedItem("filename").nodeValue();
|
||||
if(n.nodeName() == QString("count")) countName = n.attributes().namedItem("filename").nodeValue();
|
||||
}
|
||||
|
||||
QString tmpName=textureName.left(textureName.length()-4);
|
||||
maskName = tmpName.append(".mask.png");
|
||||
return true;
|
||||
}
|
||||
|
||||
QString EpochModel::ThumbName(QString &_imageName)
|
||||
{
|
||||
QString tmpName=_imageName.left(_imageName.length()-4);
|
||||
return tmpName.append(".thumb.jpg");
|
||||
}
|
||||
|
||||
EpochIO::EpochIO()
|
||||
{
|
||||
epochDialog = new v3dImportDialog();
|
||||
epochDialog->hide();
|
||||
}
|
||||
|
||||
EpochIO::~EpochIO()
|
||||
{
|
||||
delete epochDialog;
|
||||
}
|
||||
|
||||
bool EpochIO::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const FilterParameterSet & /*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();
|
||||
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<CMeshO, vcg::tri::AverageColorCell<CMeshO> > Grid;
|
||||
|
||||
int selectedNum=0,selectedCount=0;
|
||||
int i;
|
||||
for(i=0;i<qtw->rowCount();++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<string> savedMeshVector;
|
||||
|
||||
bool firstTime=true;
|
||||
QList<EpochModel>::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;
|
||||
int result = tri::io::ExporterPLY<CMeshO>::Save(mm,qPrintable(plyFilename),mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(clustering)
|
||||
{
|
||||
if (firstTime)
|
||||
{
|
||||
//Grid.Init(mm.bbox,100000);
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(mm);
|
||||
//Grid.Init(mm.bbox,1000.0*pow(10.0,mergeResolution),mm.bbox.Diag()/1000.0f);
|
||||
Grid.Init(mm.bbox,100000.0*pow(10.0,mergeResolution));
|
||||
firstTime=false;
|
||||
}
|
||||
Grid.Add(mm);
|
||||
}
|
||||
else
|
||||
tri::Append<CMeshO,CMeshO>::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.Extract(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<CMeshO>::Box(m.cm); // updates bounding box
|
||||
m.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK);
|
||||
RemoveSmallConnectedComponentsDiameter<CMeshO>(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<CMeshO>::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<CMeshO>::PerVertexNormalizedPerFace(m.cm);
|
||||
vcg::tri::Hole<CMeshO>::EarCuttingFill<vcg::tri::MinimumWeightEar< CMeshO> >(m.cm,maxHoleSize,false);
|
||||
}
|
||||
|
||||
if (cb != NULL) (*cb)(100, "Done");
|
||||
// vcg::tri::UpdateNormals<CMeshO>::PerVertex(m.cm); // updates normals
|
||||
|
||||
|
||||
int t3=clock();
|
||||
if(logFP) fprintf(logFP,"---------- Total Processing Time%i\n\n\n",t3-t0);
|
||||
if(logFP) fclose(logFP);
|
||||
logFP=0;
|
||||
} while(epochDialog->exportToPLY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EpochIO::save(const QString &/*formatName*/,const QString &/*fileName*/, MeshModel &/*m*/, const int /*mask*/, const FilterParameterSet &, vcg::CallBackPos * /*cb*/, QWidget *parent)
|
||||
{
|
||||
QMessageBox::warning(parent, "Unknown type", "file's extension not supported!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<MeshIOInterface::Format> EpochIO::importFormats() const
|
||||
{
|
||||
QList<Format> formatList;
|
||||
formatList << Format("Epoch Reconstructed mesh","V3D");
|
||||
return formatList;
|
||||
};
|
||||
|
||||
QIcon *EpochModel::getIcon()
|
||||
{
|
||||
QString iconName(textureName);
|
||||
iconName+=QString(".xbm");
|
||||
QIcon *ico=new QIcon();
|
||||
|
||||
|
||||
return ico;
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN(EpochIO)
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 <QObject>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
|
||||
#include <meshlab/meshmodel.h>
|
||||
#include <meshlab/interfaces.h>
|
||||
#include "v3dImportDialog.h"
|
||||
|
||||
class EpochIO : public QObject, public MeshIOInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MeshIOInterface)
|
||||
|
||||
public:
|
||||
QList<Format> importFormats() const;
|
||||
QList<Format> exportFormats() const {return QList<Format>();};
|
||||
|
||||
EpochIO();
|
||||
~EpochIO();
|
||||
v3dImportDialog *epochDialog;
|
||||
QString lastFileName;
|
||||
void GetExportMaskCapability(QString &, int &, int &) const {assert(0); return ;}
|
||||
|
||||
bool open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const FilterParameterSet & par, vcg::CallBackPos *cb=0, QWidget *parent=0);
|
||||
bool save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const FilterParameterSet &, vcg::CallBackPos *cb=0, QWidget *parent= 0);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,47 +0,0 @@
|
||||
include (../../shared.pri)
|
||||
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
|
||||
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 = epoch_io
|
||||
DESTDIR = ../../meshlab/plugins
|
||||
QT += xml
|
||||
|
||||
win32-msvc.net:LIBS += ../../../../code/lib/bzip2-1.0.3/libbz2.lib
|
||||
win32-msvc2005:LIBS += ../../../../code/lib/bzip2-1.0.4/win32/lib/bzip2.lib
|
||||
win32-g++:LIBS += ../../../../code/lib/bzip2-1.0.3/libbz2.a
|
||||
|
||||
win32-msvc2005:INCLUDEPATH -= ../../../../code/lib/bzip2-1.0.3
|
||||
win32-msvc2005:INCLUDEPATH += ../../../../code/lib/bzip2-1.0.4/win32/include
|
||||
win32-g++:INCLUDEPATH += ../../../../code/lib/bzip2-1.0.3
|
||||
|
||||
mac:LIBS += -lbz2
|
||||
unix: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
|
||||
}
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
#ifndef _EPOCH_RECONSTRUCTION_H
|
||||
#define _EPOCH_RECONSTRUCTION_H
|
||||
|
||||
#include <QtXml/QDomDocument>
|
||||
#include <QtXml/QDomElement>
|
||||
#include <QtXml/QDomNode>
|
||||
|
||||
#include <meshlab/meshmodel.h>
|
||||
|
||||
#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;
|
||||
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<EpochModel> modelList;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,104 +0,0 @@
|
||||
#include "fillImage.h"
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
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<int,int>& 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 (x<W-1 && ShouldWeCompute(x+1, y))
|
||||
pixels_to_do_.push_back(std::make_pair(x+1,y));
|
||||
if (y>0 && ShouldWeCompute(x, y-1))
|
||||
pixels_to_do_.push_back(std::make_pair(x,y-1));
|
||||
if (y<H-1 && ShouldWeCompute(x, y+1))
|
||||
pixels_to_do_.push_back(std::make_pair(x,y+1));
|
||||
}
|
||||
|
||||
void fillImage::ComputeGradient(const QImage& input, myGSImage& output)
|
||||
{
|
||||
input.save("input.jpg", "jpg");
|
||||
size_t W = input.width();
|
||||
size_t H = input.height();
|
||||
|
||||
float* temp = new float[W*H];
|
||||
for (size_t i=0; i<W*H; ++i)
|
||||
temp[i] = 0.0;
|
||||
|
||||
float dx, dy;
|
||||
float min = std::numeric_limits<float>::max();
|
||||
float max = -std::numeric_limits<float>::max();
|
||||
|
||||
for (size_t i=1; i<W; ++i)
|
||||
for (size_t j=1; j<H; ++j)
|
||||
{
|
||||
dx = qGray(input.pixel(i,j)) - qGray(input.pixel(i-1,j));
|
||||
dy = qGray(input.pixel(i,j)) - qGray(input.pixel(i,j-1));
|
||||
|
||||
dx = std::sqrt(dx*dx + dy*dy);
|
||||
temp[j*W+i] = dx;
|
||||
|
||||
if (dx > max)
|
||||
max = dx;
|
||||
if (dx < min)
|
||||
min = dx;
|
||||
}
|
||||
output = myGSImage(W, H);
|
||||
|
||||
float range = 255./(max-min);
|
||||
for (size_t i=0; i<W; ++i)
|
||||
for (size_t j=0; j<H; ++j)
|
||||
output.put(i, j, (unsigned char)((temp[j*W+i]-min)*range));
|
||||
}
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
#ifndef __IO_FILL_AREA_INC_
|
||||
#define __IO_FILL_AREA_INC_
|
||||
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
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<w; ++i)
|
||||
for (size_t j=0; j<h; ++j)
|
||||
put(i,j,a);
|
||||
}
|
||||
};
|
||||
|
||||
class fillImage
|
||||
{
|
||||
public:
|
||||
fillImage();
|
||||
virtual ~fillImage();
|
||||
void Compute(const QImage& input, int x, int y, int threshold_gradient,
|
||||
int threshold_fixed, QImage& output);
|
||||
|
||||
protected:
|
||||
|
||||
bool ShouldWeCompute(int x, int y);
|
||||
|
||||
void ComputeGradient(const QImage&, myGSImage& output);
|
||||
|
||||
void DealWithPixel(const std::pair<int,int>&, QImage& output);
|
||||
QImage input_, computed_;
|
||||
myGSImage gradient_;
|
||||
int threshold_gradient_, threshold_fixed_;
|
||||
int W,H;
|
||||
int xo, yo;
|
||||
std::deque<std::pair<int,int> > pixels_to_do_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,310 +0,0 @@
|
||||
#include "maskImageWidget.h"
|
||||
#include "maskRenderWidget.h"
|
||||
#include "fillImage.h"
|
||||
#include <QtGui/QPen>
|
||||
#include <QtGui/QBrush>
|
||||
#include <QtGui/QPolygon>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QPaintEvent>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QToolBar>
|
||||
#include <QtGui/QSpinBox>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <QtGui/QDesktopWidget>
|
||||
|
||||
#include <stack>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#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);
|
||||
}
|
||||
};
|
||||
@ -1,53 +0,0 @@
|
||||
#ifndef __IO_MASK_IMAGE_WIDGET_INC__
|
||||
#define __IO_MASK_IMAGE_WIDGET_INC__
|
||||
|
||||
|
||||
#include <QtGui/QDialog>
|
||||
|
||||
|
||||
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
|
||||
@ -1,362 +0,0 @@
|
||||
#include "maskRenderWidget.h"
|
||||
#include <QtGui/QPen>
|
||||
#include <QtGui/QBrush>
|
||||
#include <QtGui/QPolygon>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QPaintEvent>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QMessageBox>
|
||||
|
||||
#include <stack>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef WIN32
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
|
||||
namespace ui
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
template <class T>
|
||||
inline void unwind(std::stack<T> &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<QImage> 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<QRect> 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();
|
||||
}
|
||||
};
|
||||
@ -1,102 +0,0 @@
|
||||
#ifndef __IO_MASK_RENDER_WIDGET_INC__
|
||||
#define __IO_MASK_RENDER_WIDGET_INC__
|
||||
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
|
||||
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
|
||||
@ -1,86 +0,0 @@
|
||||
#include "radial_distortion.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
void RadialDistortion::SetParameters(vector<double>& 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<int>(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<double, double>::const_iterator next = lookup_.upper_bound(rn);
|
||||
map<double, double>::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<int>(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 "<<value<<endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
// using namespace std;
|
||||
//#include <vil/vil_warp.h>
|
||||
|
||||
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<double>& k, double max = 2000, int resolution = 10000);
|
||||
|
||||
std::vector<double> 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<double> k_;
|
||||
double ocx_;
|
||||
double ocy_;
|
||||
double ncx_;
|
||||
double ncy_;
|
||||
|
||||
void SetupLookupTable(double max, int resolution);
|
||||
|
||||
std::map<double, double> lookup_;
|
||||
|
||||
double max_;
|
||||
int resolution_;
|
||||
};
|
||||
@ -1,173 +0,0 @@
|
||||
|
||||
// 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<double, 3, 4> P;
|
||||
P.update(R_.transpose(), 0, 0);
|
||||
P.set_column(3, -R_.transpose() * T_);
|
||||
Psvd_ = vstSvd<double>(P);
|
||||
}
|
||||
|
||||
// from depth and 2D point to a 3D point:
|
||||
|
||||
void vstRadialEuclideanCamera::DepthTo3DPoint(const vstPoint2D &m, double depth, vstPoint3D &M) const
|
||||
{
|
||||
vnl_vector_fixed<double, 3> 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<double, 4> end(Psvd_.solve(m_temp));
|
||||
vstLine3D l(fp, vstPoint3D(end));
|
||||
vnl_vector_fixed<double, 4> 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 <vector>
|
||||
#include <map>
|
||||
// using namespace std;
|
||||
//#include <vil/vil_warp.h>
|
||||
|
||||
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<double>& k, double max = 2000, int resolution = 10000);
|
||||
|
||||
std::vector<double> 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<double> k_;
|
||||
double ocx_;
|
||||
double ocy_;
|
||||
double ncx_;
|
||||
double ncy_;
|
||||
|
||||
void SetupLookupTable(double max, int resolution);
|
||||
|
||||
std::map<double, double> lookup_;
|
||||
|
||||
double max_;
|
||||
int resolution_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
void vstUndoRadialDistortion::SetParameters(vector<double>& 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<double, double>::const_iterator next = lookup_.upper_bound(rn);
|
||||
map<double, double>::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 "<<value<<endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,192 +0,0 @@
|
||||
#include <Qt>
|
||||
#include <QPixmap>
|
||||
//#include <QtGui>
|
||||
//#include <QtXml/QDomDocument>
|
||||
//#include <QtXml/QDomElement>
|
||||
//#include <QtXml/QDomNode>
|
||||
//
|
||||
//
|
||||
//// temporaneamente prendo la versione corrente dalla cartella test
|
||||
//#include<vcg/complex/trimesh/update/bounding.h>
|
||||
//#include <wrap/io_trimesh/io_mask.h>
|
||||
//#include <vcg/complex/trimesh/create/platonic.h>
|
||||
//#include <vcg/complex/trimesh/update/bounding.h>
|
||||
//#include <vcg/complex/trimesh/update/normal.h>
|
||||
//#include <vcg/math/matrix33.h>
|
||||
//#include<vcg/complex/trimesh/append.h>
|
||||
//
|
||||
//#include <QMessageBox>
|
||||
//#include <QFileDialog>
|
||||
|
||||
//#include "epoch.h"
|
||||
//#include "radial_distortion.h"
|
||||
//#include "epoch_camera.h"
|
||||
#include <vector>
|
||||
#include "scalar_image.h"
|
||||
|
||||
#include <bzlib.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 +<endianess>+ ws +[sign]+ws + <bit-depth>+" "+<width>+" "+<height>+[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<float>::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<unsigned short> bb(w*h);
|
||||
fread(&*bb.begin(),w*h,sizeof(short),fp);
|
||||
v.resize(w*h);
|
||||
for(int i =0; i<w*h;++i)
|
||||
v[i]=ll+(lh-ll)*(float(bb[i])/65536.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* compressed_buffer = new char[compressed_size];
|
||||
fread(compressed_buffer,compressed_size,1,fp);
|
||||
// decompress!
|
||||
size_t size = w*h*sizeof(short);
|
||||
unsigned char * uncompressed_buffer = new unsigned char[size];
|
||||
unsigned int mysize = size;
|
||||
BZ2_bzBuffToBuffDecompress((char*)uncompressed_buffer, &mysize, compressed_buffer, compressed_size, 0, 0);
|
||||
if (mysize != size)
|
||||
{
|
||||
qDebug("This is very wrong. The uncompressed size is not the expected size");
|
||||
return false;
|
||||
}
|
||||
int imagesize = w*h;
|
||||
unsigned char *correct_buffer = new unsigned char[size];
|
||||
|
||||
for (int i=0; i<imagesize; ++i)
|
||||
{
|
||||
for (int j=0; j<sizeof(short); ++j)
|
||||
{
|
||||
correct_buffer[sizeof(short)*i +j] = uncompressed_buffer[imagesize*j + i];
|
||||
}
|
||||
}
|
||||
v.resize(w*h);
|
||||
for (int i=0; i<imagesize; ++i)
|
||||
{
|
||||
float a = *((unsigned short*)&correct_buffer[i*sizeof(short)]);
|
||||
v[i] = ll+(lh-ll)*(a/65536.0f);
|
||||
}
|
||||
|
||||
delete [] uncompressed_buffer;
|
||||
delete [] compressed_buffer;
|
||||
delete [] correct_buffer;
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
bool ScalarImage<unsigned char>::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 != w*h)
|
||||
{
|
||||
qDebug("This is very wrong. The uncompressed size is not the expected size");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
ScalarImage<unsigned char>::ScalarImage(QImage img)
|
||||
{
|
||||
resize(img.width(),img.height());
|
||||
|
||||
for(int y=0;y<h;++y)
|
||||
for(int x=0;x<w;++x)
|
||||
Val(x,y)=qGray(img.pixel(x,y));
|
||||
|
||||
}
|
||||
|
||||
template <class ScalarType>
|
||||
bool ScalarImage<ScalarType>::Subsample(const int factor, ScalarImage<ScalarType> &fli)
|
||||
{
|
||||
resize(fli.w/factor,fli.h/factor);
|
||||
|
||||
for(int i=0;i<h;++i)
|
||||
for(int j=0;j<w;++j)
|
||||
Val(i,j)=fli.Val(i*factor,j*factor);
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -1,127 +0,0 @@
|
||||
#ifndef VCG_SCALARIMAGE_H
|
||||
#define VCG_SCALARIMAGE_H
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <vcg/space/color4.h>
|
||||
/*
|
||||
Very simple class to store a bitmap of floating point values.
|
||||
*/
|
||||
template <class ScalarType>
|
||||
class ScalarImage
|
||||
{
|
||||
public:
|
||||
std::vector<ScalarType> 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<w);
|
||||
assert(y>=0 && y<h);
|
||||
return v[y*w+x];
|
||||
};
|
||||
|
||||
ScalarType Val(int x,int y) const {
|
||||
assert(x>=0 && x<w);
|
||||
assert(y>=0 && y<h);
|
||||
return v[y*w+x];
|
||||
};
|
||||
|
||||
void operator = ( const ScalarImage & img )
|
||||
{
|
||||
w=img.w;
|
||||
h=img.h;
|
||||
v=img.v;
|
||||
}
|
||||
|
||||
ScalarType MinVal() { return *std::min_element(v.begin(),v.end()); }
|
||||
ScalarType MaxVal() { return *std::max_element(v.begin(),v.end()); }
|
||||
|
||||
inline QImage convertToQImage()
|
||||
{
|
||||
QImage img(w,h,QImage::Format_RGB32);
|
||||
|
||||
float maxV = MaxVal();
|
||||
float minV = MinVal();
|
||||
|
||||
float scale = 1.0f / (maxV-minV);
|
||||
for (int y = 0; y < h; y++)
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
float value = (Val(x, y) - minV) * scale;
|
||||
value *= 255.0f;
|
||||
img.setPixel(x,y,qRgb(value,value,value));
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
void Erode(ScalarImage &Eroded, const int wsize=1) const
|
||||
{
|
||||
Eroded.resize(w,h);
|
||||
// erosion filter (3 x 3)
|
||||
int minimum;
|
||||
for (int y = wsize; y < h-wsize; y++)
|
||||
for (int x = wsize; x < w-wsize; x++)
|
||||
{
|
||||
minimum = Val(x, y);
|
||||
for (int yy = y - wsize; yy <= y + wsize; yy++)
|
||||
for (int xx = x - wsize; xx <= x + wsize; xx++)
|
||||
if (Val(xx, yy) < minimum)
|
||||
minimum = Val(xx, yy);
|
||||
|
||||
Eroded.Val(x, y) = minimum;
|
||||
}
|
||||
}
|
||||
|
||||
void Dilate(ScalarImage &Dilated, int wsize=1)
|
||||
{
|
||||
Dilated.resize(w,h);
|
||||
// dilation filter (3 x 3)
|
||||
int maximum;
|
||||
for (int y = wsize; y < h-wsize; y++)
|
||||
for (int x = wsize; x < w-wsize; x++)
|
||||
{
|
||||
maximum = Val(x, y);
|
||||
for (int yy = y - wsize; yy <= y + wsize; yy++)
|
||||
for (int xx = x - wsize; xx <= x + wsize; xx++)
|
||||
if (Val(xx, yy) > maximum)
|
||||
maximum = Val(xx, yy);
|
||||
|
||||
Dilated.Val(x, y) = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
ScalarImage(QImage img);
|
||||
ScalarImage(){};
|
||||
bool Subsample(const int factor, ScalarImage<ScalarType> &fli);
|
||||
static QPixmap colorizedScaledToHeight(const int desiredH, ScalarImage<ScalarType> &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<newImage.height();++i)
|
||||
for(int j=0;j<newImage.width();++j)
|
||||
{
|
||||
float sum=0;
|
||||
for(int si=0;si<factor;++si)
|
||||
for(int sj=0;sj<factor;++sj)
|
||||
sum+= fli.Val(j*factor+sj,i*factor+si);
|
||||
sum/=factor*factor;
|
||||
sum=std::min(sum,colormax);
|
||||
vcg::Color4b avgcolor; avgcolor.ColorRamp(0,colormax,sum);
|
||||
newImage.setPixel(j,i,qRgb(avgcolor.V(0),avgcolor.V(1),avgcolor.V(2)));
|
||||
}
|
||||
return QPixmap::fromImage(newImage);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
typedef ScalarImage<float> FloatImage;
|
||||
typedef ScalarImage<unsigned char> CharImage;
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,678 +0,0 @@
|
||||
<ui version="4.0" >
|
||||
<class>v3dImportDialog</class>
|
||||
<widget class="QDialog" name="v3dImportDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>792</width>
|
||||
<height>606</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>V3D Import Settings</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="infoLabel" >
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="previewLabel" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>SubSample</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="imgSizeLabel" >
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="subsampleSpinBox" >
|
||||
<property name="toolTip" >
|
||||
<string><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></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>Minimum Count</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>91</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="minCountSpinBox" >
|
||||
<property name="toolTip" >
|
||||
<string><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></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="minCountSlider" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="rangeLabel" >
|
||||
<property name="text" >
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>Minimum Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="qualitySpinBox" >
|
||||
<property name="decimals" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep" >
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<double>75.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>Feature Aware Smoothing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="smoothSpinBox" >
|
||||
<property name="decimals" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<double>20.000000000000000</double>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<double>3.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QCheckBox" name="removeSmallCCCheckBox" >
|
||||
<property name="layoutDirection" >
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Remove pieces less than</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="maxCCDiagSpinBox" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>When enabled, all the floating pieces smaller than the indicated percentage are deleted. Unit is the diagonal of the bounding box of the object</string>
|
||||
</property>
|
||||
<property name="decimals" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<double>25.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep" >
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="holeCheckBox" >
|
||||
<property name="enabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="layoutDirection" >
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Close Holes less than</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="holeSpinBox" >
|
||||
<property name="singleStep" >
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="5" >
|
||||
<widget class="QSlider" name="dilationSizeSlider" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="singleStep" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="pageStep" >
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QSpinBox" name="erosionNumPassSpinBox" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QLabel" name="lblDilationSize" >
|
||||
<property name="text" >
|
||||
<string>Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="6" >
|
||||
<widget class="QLabel" name="lblErosionSizeValue" >
|
||||
<property name="text" >
|
||||
<string>5 x 5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QSpinBox" name="dilationNumPassSpinBox" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="lblDilationSteps" >
|
||||
<property name="text" >
|
||||
<string>Num. passes:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5" >
|
||||
<widget class="QSlider" name="erosionSizeSlider" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="singleStep" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="pageStep" >
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6" >
|
||||
<widget class="QLabel" name="lblDilationSizeValue" >
|
||||
<property name="text" >
|
||||
<string>5 x 5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLabel" name="lblErosionSteps" >
|
||||
<property name="text" >
|
||||
<string>Num. passes:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_8" >
|
||||
<property name="text" >
|
||||
<string>Depth Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4" >
|
||||
<widget class="QLabel" name="lblErosionSize" >
|
||||
<property name="text" >
|
||||
<string>Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QCheckBox" name="dilationCheckBox" >
|
||||
<property name="text" >
|
||||
<string>Dilation</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QCheckBox" name="erosionCheckBox" >
|
||||
<property name="text" >
|
||||
<string>Erosion</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="fastMergeCheckBox" >
|
||||
<property name="toolTip" >
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="layoutDirection" >
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Fast merge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6" >
|
||||
<property name="text" >
|
||||
<string>Resolution: Min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="mergeResolutionSpinBox" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<string>Max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QPushButton" name="selectButton" >
|
||||
<property name="text" >
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="subsampleSequenceSpinBox" >
|
||||
<property name="value" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10" >
|
||||
<property name="text" >
|
||||
<string>Scaling Factor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="scaleLineEdit" >
|
||||
<property name="inputMask" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>1.0</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>131</width>
|
||||
<height>31</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="okButton" >
|
||||
<property name="text" >
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="plyButton" >
|
||||
<property name="toolTip" >
|
||||
<string>Process all selected range maps and save them as separated ply</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Export as PLY</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton" >
|
||||
<property name="text" >
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="imageTableWidget" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="MinimumExpanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="columnCount" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
<column/>
|
||||
<column/>
|
||||
<column/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>v3dImportDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>554</x>
|
||||
<y>682</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>342</x>
|
||||
<y>405</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cancelButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>v3dImportDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>637</x>
|
||||
<y>682</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>425</x>
|
||||
<y>433</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>removeSmallCCCheckBox</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>maxCCDiagSpinBox</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>348</x>
|
||||
<y>584</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>637</x>
|
||||
<y>584</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@ -1,246 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 <Qt>
|
||||
#include <QtGui>
|
||||
#include <QDialog>
|
||||
|
||||
#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;x<width;++x)
|
||||
for(int y=0;y<height;++y)
|
||||
{
|
||||
ramp.ColorRamp(0,width,x);
|
||||
newImage.setPixel(x,y,qRgb(ramp.V(0),ramp.V(1),ramp.V(2)));
|
||||
}
|
||||
|
||||
return QPixmap::fromImage(newImage);
|
||||
}
|
||||
/*
|
||||
Main function that populate the dialog, loading all the images and eventually creating the thumbs.
|
||||
called directly by the open before invoking this dialog.
|
||||
*/
|
||||
void v3dImportDialog::setEpochReconstruction(EpochReconstruction *_er,CallBackPos *cb)
|
||||
{
|
||||
// if the epoch reconstruction has not changed do nothing
|
||||
if(erCreated == _er->created)
|
||||
{
|
||||
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; i<er->modelList.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;i<itemNum;i+=modVal)
|
||||
imageTableWidget->setRangeSelected(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);
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
#ifndef V3DIMPORTER_DIALOG_H
|
||||
#define V3DIMPORTER_DIALOG_H
|
||||
|
||||
// for options on decimator
|
||||
#include <QDialog>
|
||||
#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;
|
||||
}
|
||||
|
||||
public:
|
||||
void setEpochReconstruction(EpochReconstruction *_er,vcg::CallBackPos *cb);
|
||||
bool exportToPLY; /// when true all the selected range maps are exported as separated ply
|
||||
|
||||
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
|
||||
Loading…
x
Reference in New Issue
Block a user