void Arc3DModel::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; } } }
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; }
void Arc3DModel::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"); }