1 #include <stdio.h>
2 #include <vcg/complex/complex.h>
3 #include <vcg/complex/algorithms/update/flag.h>
4 #include <vcg/complex/algorithms/clean.h>
5 
6 using namespace std;
7 using namespace vcg;
8 
9 //A class that implements a feature based on RGB color
10 template<class MESH_TYPE, int dim>
11 class FeatureRGB
12 {
13     public:
14 
15     class Parameters
16     {
17         public:
18 
19         enum RGBAType {RED, GREEN, BLUE, ALPHA};
20 
21         vector<RGBAType> featureDesc;
22 
add(RGBAType cType)23         bool add(RGBAType cType){
24             if(featureDesc.size()>=dim) return false;
25             featureDesc.push_back(cType);
26             return true;
27         }
28     };
29 
30     typedef MESH_TYPE MeshType;
31     typedef FeatureRGB<MeshType,dim> FeatureType;
32     typedef typename FeatureType::Parameters ParamType;
33     typedef typename MeshType::ScalarType ScalarType;
34     typedef typename MeshType::VertexType VertexType;
35     typedef typename MeshType::VertexIterator VertexIterator;
36     typedef typename MeshType::template PerVertexAttributeHandle<FeatureType> PVAttributeHandle;
37 
38     Point3<ScalarType> pos;
39     Point3<ScalarType> normal;
40     float description[dim];
41 
42     FeatureRGB();
43     FeatureRGB(VertexType& v);
44     static char* getName();
45     static int getRequirements();
46     static float getNullValue();
47     static bool isNullValue(float);
48     static int getFeatureDimension();
49     static bool CheckPersistency(FeatureType f);
50     static void SetupParameters(ParamType& param);
51     static bool HasBeenComputed(MeshType& m);
52     static bool ComputeFeature( MeshType&, ParamType& param, CallBackPos *cb=NULL);
53     static bool Subset(int, MeshType&, vector<FeatureType*>&, int, CallBackPos *cb=NULL);
54 
55     private:
56     static MESH_TYPE* CreateSamplingMesh();
57     static int SetupSamplingStructures(MeshType& m, typename MeshType::template PerVertexAttributeHandle<FeatureType>& fh, MeshType* samplingMesh, vector<FeatureType*>* vecFeatures);
58 };
59 
FeatureRGB()60 template<class MESH_TYPE, int dim> inline FeatureRGB<MESH_TYPE,dim>::FeatureRGB(){}
61 
62 template<class MESH_TYPE, int dim>
FeatureRGB(VertexType & v)63 inline FeatureRGB<MESH_TYPE,dim>::FeatureRGB(VertexType& v):pos(v.P()),normal(v.N())
64 {
65     normal.Normalize();
66     for(int i=0; i<dim; i++) FeatureRGB::getNullValue();
67 }
68 
getName()69 template<class MESH_TYPE, int dim> inline char* FeatureRGB<MESH_TYPE,dim>::getName()
70 {
71     return "FeatureRGB";
72 }
73 
getRequirements()74 template<class MESH_TYPE, int dim> inline int FeatureRGB<MESH_TYPE,dim>::getRequirements()
75 {
76     return (MeshModel::MM_VERTCOLOR);
77 }
78 
isNullValue(float val)79 template<class MESH_TYPE, int dim> inline bool FeatureRGB<MESH_TYPE,dim>::isNullValue(float val)
80 {
81     return (val==FeatureType::getNullValue());
82 }
83 
getNullValue()84 template<class MESH_TYPE, int dim> inline float FeatureRGB<MESH_TYPE,dim>::getNullValue()
85 {
86     return -1.0f;
87 }
88 
getFeatureDimension()89 template<class MESH_TYPE, int dim> inline int FeatureRGB<MESH_TYPE,dim>::getFeatureDimension()
90 {
91     return dim;
92 }
93 
94 //check persistence beetween scales: return true if description is valid for all scales, false otherwise
CheckPersistency(FeatureType f)95 template<class MESH_TYPE, int dim> bool FeatureRGB<MESH_TYPE,dim>::CheckPersistency(FeatureType f)
96 {
97     for(int i = 0; i<FeatureType::getFeatureDimension(); i++)
98     {
99         if( FeatureType::isNullValue(f.description[i]) ) return false;
100     }
101     return true;
102 }
103 
SetupParameters(ParamType & param)104 template<class MESH_TYPE, int dim> void FeatureRGB<MESH_TYPE,dim>::SetupParameters(ParamType& param)
105 {
106     param.add(FeatureType::Parameters::RED);
107     param.add(FeatureType::Parameters::GREEN);
108     param.add(FeatureType::Parameters::BLUE);
109     assert(param.featureDesc.size()==getFeatureDimension());
110 }
111 
HasBeenComputed(MeshType & m)112 template<class MESH_TYPE, int dim> bool FeatureRGB<MESH_TYPE,dim>::HasBeenComputed(MeshType &m)
113 {
114     //checks if the attribute exist
115     return tri::HasPerVertexAttribute(m,std::string(FeatureType::getName()));
116 }
117 
ComputeFeature(MeshType & m,ParamType & param,CallBackPos * cb)118 template<class MESH_TYPE, int dim> bool FeatureRGB<MESH_TYPE,dim>::ComputeFeature(MeshType &m, ParamType& param, CallBackPos *cb)
119 {
120     //clear the mesh to avoid wrong values during computations
121     //tri::Clean<MeshType>::RemoveUnreferencedVertex(m);
122 
123     //variables needed for progress bar callback
124     float progBar = 0.0f;
125     float offset = 100.0f/m.VertexNumber();
126     if(cb) cb(0,"Computing features...");
127 
128     PVAttributeHandle fh = FeatureAlignment<MeshType, FeatureType>::GetFeatureAttribute(m, true);
129     if(!tri::Allocator<MeshType>::IsValidHandle(m,fh)) return false;
130 
131     //for each vertex, creates a feature and set its values.
132     VertexIterator vi;
133     for(vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
134     {
135         fh[vi] = FeatureType(*vi);
136 
137         //copy vertex color into feature values
138         for(unsigned int i=0; i<FeatureType::getFeatureDimension(); i++)
139             fh[vi].description[i] = float((*vi).C()[param.featureDesc[i]]);
140 
141         //advance progress bar
142         progBar+=offset;
143         if(cb) cb(int(progBar),"Computing features...");
144     }
145     return true;
146 }
147 
148 //create a mesh and add a per vertex attribute to hold feature values
149 template<class MESH_TYPE, int dim>
CreateSamplingMesh()150 MESH_TYPE* FeatureRGB<MESH_TYPE,dim>::CreateSamplingMesh()
151 {
152     MeshType* m = new MeshType();
153     PVAttributeHandle fh = FeatureAlignment<MeshType, FeatureType>::GetFeatureAttribute(*m, true);
154     if(!tri::Allocator<MeshType>::IsValidHandle(*m,fh)){
155         if(m) delete m;
156         return NULL;
157     }
158     return m;
159 }
160 
161 template<class MESH_TYPE, int dim>
SetupSamplingStructures(MeshType & m,typename MeshType::template PerVertexAttributeHandle<FeatureType> & fh,MeshType * samplingMesh,vector<FeatureType * > * vecFeatures)162 int FeatureRGB<MESH_TYPE,dim>::SetupSamplingStructures(MeshType& m, typename MeshType::template PerVertexAttributeHandle<FeatureType>& fh, MeshType* samplingMesh, vector<FeatureType*>* vecFeatures)
163 {
164     int countFeatures = 0;
165     PVAttributeHandle pmfh;
166     if(samplingMesh){
167         pmfh = FeatureAlignment<MeshType, FeatureType>::GetFeatureAttribute(*samplingMesh);
168         if(!tri::Allocator<MeshType>::IsValidHandle(*samplingMesh,pmfh)) return 0;
169     }
170 
171     //fill the vector with all persistent features.
172     for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi){
173         //check persistence beetween scales: if feature is persistent, add a pointer in vecFeatures
174         if( FeatureType::CheckPersistency(fh[vi]) ){
175             countFeatures++;  //increment counter of valid features
176             if(vecFeatures) vecFeatures->push_back(&(fh[vi]));
177             if(samplingMesh){
178                 tri::Allocator<MeshType>::AddVertices(*samplingMesh, 1);
179                 samplingMesh->vert.back().ImportLocal(*vi);
180                 pmfh[samplingMesh->vert.back()] = fh[vi];
181             }
182         }
183     }
184 
185     return countFeatures;
186 }
187 
188 template<class MESH_TYPE, int dim>
Subset(int k,MeshType & m,vector<FeatureType * > & vecSubset,int sampType,CallBackPos * cb)189 bool FeatureRGB<MESH_TYPE,dim>::Subset(int k, MeshType &m, vector<FeatureType*> &vecSubset, int sampType, CallBackPos *cb)
190 {
191     //variables needed for progress bar callback
192     float progBar = 0.0f;
193     float offset = 100.0f/(m.VertexNumber() + k);
194 
195     //if attribute doesn't exist, return; else we can get a handle to the attribute
196     PVAttributeHandle fh = FeatureAlignment<MeshType, FeatureType>::GetFeatureAttribute(m);
197     if(!tri::Allocator<MeshType>::IsValidHandle(m,fh)) return false;
198 
199     //create a vector to hold valid features that later will be sampled
200     vector<FeatureType*>* vecFeatures = NULL;
201     MeshType* poissonMesh = NULL;
202     if(sampType==0) vecFeatures = new vector<FeatureType*>();
203     else poissonMesh = CreateSamplingMesh();
204 
205     //fill the vector with all persistent features.
206     int countFeatures = SetupSamplingStructures(m, fh, poissonMesh, vecFeatures);
207     if(countFeatures<k) k = countFeatures;  //we can't extract more of what we got!
208 
209     //perform different kinds of sampling
210     FeatureType** sampler = NULL;
211     switch(sampType){
212         case 0:{ //uniform sampling: uses vecFeatures
213             sampler = FeatureAlignment<MeshType, FeatureType>::FeatureUniform(*vecFeatures, &k);
214             break;
215         }
216         case 1:{ //poisson disk sampling: uses poissonMesh
217             sampler = FeatureAlignment<MeshType, FeatureType>::FeaturePoisson(*poissonMesh, &k);
218             break;
219         }
220         default: assert(0);
221     }
222 
223     //store features into the returned vector
224     for(int i=0; i<k; ++i){
225         vecSubset.push_back(sampler[i]);
226         if(cb){ progBar+=offset; cb(int(progBar),"Extracting features..."); }
227     }
228 
229     if(vecFeatures) delete vecFeatures;   //clear useless data
230     if(poissonMesh) delete poissonMesh;
231     if(sampler) delete[] sampler;
232 
233     return true;
234 }
235