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