Point3m Arc3DModel::TraCorrection(CMeshO &m, int subsampleFactor, int minCount, int smoothSteps)
{
    FloatImage depthImgf;
    CharImage countImgc;
    depthImgf.Open(depthName.toUtf8().data());
    countImgc.Open(countName.toUtf8().data());

    QImage TextureImg;
    TextureImg.load(textureName);

    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");

    float depthThr = ComputeDepthJumpThr(depthSubf,0.8f);
    for(int ii=0;ii<smoothSteps;++ii)
        Laplacian2(depthSubf,countSubf,minCount,FeatureMask,depthThr);

    vcg::tri::Grid<CMeshO>(m,depthSubf.w,depthSubf.h,depthImgf.w,depthImgf.h,&*depthSubf.v.begin());

    // 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).
    ComputeDepthJumpThr(depthSubf,0.95f);

    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.toUtf8().data());

        CMeshO::VertexIterator vi;
        Matrix33d Rinv= Inverse(cam.R);
        Point3m correction(0.0,0.0,0.0);
        int numSamp=0;

        for(vi=m.vert.begin();vi!=m.vert.end();++vi)if(!(*vi).IsD())
        {
            Point3m in=(*vi).P();
            Point3d out;
            correction+=cam.DepthTo3DPoint(in[0], in[1], in[2], out);
            numSamp++;

        }
        if (numSamp!=0)
            correction/=(double)numSamp;

        return correction;

}
/* 
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::setArc3DReconstruction(Arc3DReconstruction *_er)
{
  // if the epoch reconstruction has not changed do nothing
  if(erCreated == _er->created) 
  {
    er=_er;
    return;
  }
  
  er=_er;
  erCreated=er->created;
  ui.infoLabel->setText(er->name + " - " + er->author + " - " + er->created);
  
  ui.imageTableWidget->clear();
  ui.imageTableWidget->setRowCount(er->modelList.size());
  ui.imageTableWidget->setColumnCount(4);
  //imageTableWidget->setColumnWidth (1,64);
  ui.imageTableWidget->setSelectionBehavior (QAbstractItemView::SelectRows);
  ui.imageTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
  ui.imageTableWidget->setMinimumWidth(64*8);
  
  ui.rangeLabel->setPixmap(generateColorRamp());
  ui.rangeLabel->setMaximumHeight(10);
	ui.rangeLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
	ui.rangeLabel->setScaledContents(true);
	
  ui.minCountSlider->setMaximumHeight(12);
    
  int i;
  for(i=0; i<er->modelList.size() ;++i)
  {
        
    QString ThumbImgName=Arc3DModel::ThumbName(er->modelList[i].textureName);
    QString ThumbCntName=Arc3DModel::ThumbName(er->modelList[i].countName);

    ui.imageTableWidget->setRowHeight (i,64);
    QTableWidgetItem *emptyHeaderItem = new QTableWidgetItem(i*2);
    QTableWidgetItem *texNameHeaderItem = new QTableWidgetItem(er->modelList[i].textureName,i);
    ui.imageTableWidget->setItem(i, 0, texNameHeaderItem);
    ui.imageTableWidget->setItem(i, 1, emptyHeaderItem);
    QLabel *imageLabel = new QLabel(ui.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(Arc3DModel::ThumbName(er->modelList[i].textureName)));
    ui.imageTableWidget->setCellWidget(i,1,imageLabel);
    if(QFile::exists(er->modelList[i].maskName))
    {
      QTableWidgetItem *emptyHeaderItem = new QTableWidgetItem(i*4);
      ui.imageTableWidget->setItem(i, 2, emptyHeaderItem);
      QLabel *maskLabel = new QLabel(ui.imageTableWidget);
      maskLabel->setPixmap(QPixmap(er->modelList[i].maskName).scaledToHeight(64));
      ui.imageTableWidget->setCellWidget(i,2,maskLabel);     
    }
    else
    {
      QTableWidgetItem *maskHeaderItem = new QTableWidgetItem(QString("double click for\nediting the mask"),i*3);
      ui.imageTableWidget->setItem(i, 2, maskHeaderItem);
    }

    if(!QFile::exists(ThumbCntName))
      {
        CharImage chi;
        bool ret=chi.Open(er->modelList[i].countName.toUtf8().data());
        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(ui.imageTableWidget);
    countLabel->setPixmap(QPixmap(ThumbCntName));
    QPixmap tmp(ThumbCntName);
    if(tmp.isNull())
       QMessageBox::warning(this,"Error in Thumb creation",QString("Null Pixmap '%1'").arg(ThumbCntName));
    ui.imageTableWidget->setCellWidget(i,3,countLabel);
  }  

    
show(); // necessary to make the size of the image preview correct.
ui.imageTableWidget->setItemSelected(ui.imageTableWidget->item(0,0),true);    
ui.imageTableWidget->setItemSelected(ui.imageTableWidget->item(0,1),true);    
ui.imageTableWidget->setItemSelected(ui.imageTableWidget->item(0,2),true);    


}
bool Arc3DModel::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;
    clock();
    depthImgf.Open(depthName.toUtf8().data());
    countImgc.Open(countName.toUtf8().data());

    QImage TextureImg;
    TextureImg.load(textureName);
    clock();

    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");

    clock();

    float depthThr = ComputeDepthJumpThr(depthSubf,0.8f);
    for(int ii=0;ii<smoothSteps;++ii)
        Laplacian2(depthSubf,countSubf,minCount,FeatureMask,depthThr);

    clock();

    vcg::tri::Grid<CMeshO>(m,depthSubf.w,depthSubf.h,depthImgf.w,depthImgf.h,&*depthSubf.v.begin());

    clock();


    // 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.toUtf8().data());

        CMeshO::VertexIterator vi;
        Matrix33d Rinv= Inverse(cam.R);

        for(vi=m.vert.begin();vi!=m.vert.end();++vi)if(!(*vi).IsD())
        {
            Point3m 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]));
            vcg::Color4b tmpcol(qRed(c),qGreen(c),qBlue(c),0);
            (*vi).C().Import(tmpcol);
            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;
        }

        clock();

        CMeshO::FaceIterator fi;
        Point3m CameraPos = Point3m::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
            {
                Point3m n=vcg::TriangleNormal(*fi);
                n.Normalize();
                Point3m dir=CameraPos-vcg::Barycenter(*fi);
                dir.Normalize();
                if(dir.dot(n) < minAngleCos)
                {
                    (*fi).SetD();
                    --m.fn;
                }
            }
        }

        tri::Clean<CMeshO>::RemoveUnreferencedVertex(m);
        clock();

        Matrix44m scaleMat;
        scaleMat.SetScale(scalingFactor,scalingFactor,scalingFactor);
        vcg::tri::UpdatePosition<CMeshO>::Matrix(m, scaleMat);

        return true;
}