00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef TIGS_FEATUREEXTRACTOR_C_DEFINED
00039 #define TIGS_FEATUREEXTRACTOR_C_DEFINED
00040
00041 #include "TIGS/FeatureExtractor.H"
00042
00043 #include "Component/ModelOptionDef.H"
00044 #include "Image/CutPaste.H"
00045 #include "Image/MathOps.H"
00046 #include "Raster/Raster.H"
00047 #include "TIGS/TigsOpts.H"
00048 #include "Util/log.H"
00049 #include "rutz/error_context.h"
00050 #include "rutz/sfmt.h"
00051 #include "rutz/trace.h"
00052
00053
00054 static const ModelOptionDef OPT_CacheSavePrefix =
00055 { MODOPT_ARG_STRING, "CacheSavePrefix", &MOC_TIGS, OPTEXP_CORE,
00056 "Filename stem name for feature-extractor caches",
00057 "cache-save-prefix", '\0', "<string>", "" };
00058
00059 namespace
00060 {
00061 template <class T>
00062 Image<T> asRow(const Image<T>& in)
00063 {
00064 GVX_TRACE(__PRETTY_FUNCTION__);
00065 return Image<T>(in.getArrayPtr(), in.getSize(), 1);
00066 }
00067 }
00068
00069 FeatureExtractor::FeatureExtractor(OptionManager& mgr,
00070 const std::string& name)
00071 :
00072 ModelComponent(mgr, name, name),
00073 itsCacheSavePrefix(&OPT_CacheSavePrefix, this),
00074 itsName(name),
00075 itsCache(),
00076 itsNumHits(0),
00077 itsCheckFrequency(100),
00078 itsPrevTime(SimTime::ZERO())
00079 {}
00080
00081 FeatureExtractor::~FeatureExtractor() {}
00082
00083 void FeatureExtractor::start2()
00084 {
00085 this->load(itsCacheSavePrefix.getVal().c_str());
00086 }
00087
00088 void FeatureExtractor::stop1()
00089 {
00090 this->save(itsCacheSavePrefix.getVal().c_str());
00091 }
00092
00093 Image<float> FeatureExtractor::extract(const TigsInputFrame& fin)
00094 {
00095 GVX_TRACE(__PRETTY_FUNCTION__);
00096
00097 GVX_ERR_CONTEXT(rutz::sfmt("extracting features in FeatureExtractor %s",
00098 itsName.c_str()));
00099
00100 const bool isnewtime = (fin.t() > itsPrevTime);
00101 itsPrevTime = fin.t();
00102
00103 if (!this->isCacheable())
00104 return doExtract(fin);
00105
00106 const Digest<16> digest = fin.getHash();;
00107
00108 typedef std::map<Digest<16>, Image<float> > CacheType;
00109
00110 CacheType::iterator itr = itsCache.find(digest);
00111
00112 if (itr != itsCache.end())
00113 {
00114 LINFO("cache hit in %s on md5 digest %s",
00115 itsName.c_str(), digest.asString().c_str());
00116
00117 ++itsNumHits;
00118
00119
00120 if (isnewtime
00121 &&
00122 !fin.isGhost()
00123 &&
00124 (itsNumHits == 1 ||
00125 (itsCheckFrequency > 0
00126 && itsNumHits % itsCheckFrequency == 0)))
00127 {
00128 const Image<float> f = doExtract(fin);
00129
00130 const Image<float> actual = asRow(f);
00131 const Image<float> expected = asRow((*itr).second);
00132
00133 if (!(actual == expected))
00134 {
00135 LINFO("RMSerr(actual,expected)=%g", RMSerr(actual,expected));
00136 LINFO("corrcoef(actual,expected)=%g", corrcoef(actual,expected));
00137
00138 LFATAL("cache integrity check failed "
00139 "in %s after %d hits",
00140 itsName.c_str(), itsNumHits);
00141 }
00142 else
00143 LINFO("cache integrity check OK in %s after %d hits",
00144 itsName.c_str(), itsNumHits);
00145 }
00146
00147 return (*itr).second;
00148 }
00149
00150
00151 const Image<float> f = doExtract(fin);
00152 itsCache.insert(CacheType::value_type(digest, f));
00153 return f;
00154 }
00155
00156 void FeatureExtractor::save(const char* pfx) const
00157 {
00158 GVX_TRACE(__PRETTY_FUNCTION__);
00159 if (!this->isCacheable())
00160 {
00161 LINFO("%s not cacheable; save() skipped", itsName.c_str());
00162 return;
00163 }
00164
00165 if (itsCache.size() == 0)
00166 {
00167 LINFO("%s has no cache entries; save() skipped", itsName.c_str());
00168 return;
00169 }
00170
00171 const std::string dfile = sformat("%s-%s-digests.pgm",
00172 pfx, itsName.c_str());
00173 const std::string ffile = sformat("%s-%s-features.pfm",
00174 pfx, itsName.c_str());
00175
00176 if (Raster::fileExists(dfile))
00177 {
00178 LINFO("%s cache file %s already exists; save() skipped",
00179 itsName.c_str(), dfile.c_str());
00180 return;
00181 }
00182
00183 if (Raster::fileExists(ffile))
00184 {
00185 LINFO("%s cache file %s already exists; save() skipped",
00186 itsName.c_str(), ffile.c_str());
00187 return;
00188 }
00189
00190 ASSERT(itsCache.size() > 0);
00191
00192 Image<byte> digests(16, itsCache.size(), NO_INIT);
00193 Image<float> features((*(itsCache.begin())).second.getSize(),
00194 itsCache.size(), NO_INIT);
00195
00196 typedef std::map<Digest<16>, Image<float> > CacheType;
00197
00198 int row = 0;
00199
00200 for (CacheType::const_iterator
00201 itr = itsCache.begin(), stop = itsCache.end();
00202 itr != stop; ++itr)
00203 {
00204 inplacePaste(digests, (*itr).first.asImage(),
00205 Point2D<int>(0, row));
00206
00207 inplacePaste(features, asRow((*itr).second),
00208 Point2D<int>(0, row));
00209
00210 ++row;
00211 }
00212
00213 ASSERT(size_t(row) == itsCache.size());
00214
00215 Raster::WriteGray(digests, dfile, RASFMT_PNM);
00216 Raster::WriteFloat(features, FLOAT_NORM_PRESERVE, ffile, RASFMT_PFM);
00217
00218 LINFO("saved %d cache entries to %s", row, dfile.c_str());
00219 LINFO("saved %d cache entries to %s", row, ffile.c_str());
00220 }
00221
00222 void FeatureExtractor::load(const char* pfx)
00223 {
00224 GVX_TRACE(__PRETTY_FUNCTION__);
00225 if (!this->isCacheable())
00226 {
00227 LINFO("%s not cacheable; load() skipped", itsName.c_str());
00228 return;
00229 }
00230
00231 const std::string dfile = sformat("%s-%s-digests.pgm",
00232 pfx, itsName.c_str());
00233 const std::string ffile = sformat("%s-%s-features.pfm",
00234 pfx, itsName.c_str());
00235
00236 if (!Raster::fileExists(dfile))
00237 {
00238 LINFO("%s cache file %s not found; load() skipped",
00239 itsName.c_str(), dfile.c_str());
00240 return;
00241 }
00242
00243 if (!Raster::fileExists(ffile))
00244 {
00245 LINFO("%s cache file %s not found; load() skipped",
00246 itsName.c_str(), ffile.c_str());
00247 return;
00248 }
00249
00250 const Image<byte> digests = Raster::ReadGray(dfile, RASFMT_PNM);
00251 const Image<float> features = Raster::ReadFloat(ffile, RASFMT_PFM);
00252
00253 ASSERT(digests.getHeight() == features.getHeight());
00254
00255 const int nrows = digests.getHeight();
00256
00257 typedef std::map<Digest<16>, Image<float> > CacheType;
00258
00259 itsCache.clear();
00260
00261 LINFO("digests=%dx%d", digests.getWidth(), digests.getHeight());
00262
00263 for (int i = 0; i < nrows; ++i)
00264 {
00265 Digest<16> d = Digest<16>::asDigest(&digests[Point2D<int>(0, i)],
00266 digests.getWidth());
00267
00268 Image<float> f(&features[Point2D<int>(0, i)],
00269 features.getWidth(), 1);
00270
00271 itsCache.insert(CacheType::value_type(d, f));
00272 }
00273
00274 ASSERT(itsCache.size() == size_t(nrows));
00275
00276 LINFO("loaded %d cache entries from %s", nrows, dfile.c_str());
00277 LINFO("loaded %d cache entries from %s", nrows, ffile.c_str());
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287 #endif // TIGS_FEATUREEXTRACTOR_C_DEFINED