Commit caa661c922a52438647cc8d8f1e85a05c8384d03

Authored by Charles Otto
1 parent 4887d291

Add a simplified interface for Stream

Now, Stream takes a single transform argument. The old interface remains,
renamed to DirectStream.
If that transform is a pipe, Stream will split its child transforms
appropriately, and set up a DirectStream. Adjacent non-timeVarying transforms
are grouped in pipes, time varying transforms all get separate stages.

The default behavior isn't necessarily ideal if e.g. a lot of light time
varying stages are present, in that case its possible the additional
synchronization costs will outweight gains from paraellelism (due to having
more separate single thread stages). In these cases DirectStream may be
preferable, however current algorithms seem largely unaffected.
openbr/plugins/algorithms.cpp
... ... @@ -46,12 +46,13 @@ class AlgorithmsInitializer : public Initializer
46 46 Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)");
47 47  
48 48 // Video
49   - Globals->abbreviations.insert("DisplayVideo", "Stream([FPSLimit(30)+Show(false,[FrameNumber])+Discard])");
50   - Globals->abbreviations.insert("PerFrameDetection", "Stream([SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true),Show(false,[FrameNumber])+Discard])");
51   - Globals->abbreviations.insert("AgeGenderDemo", "Stream([SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract,RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard])");
52   - Globals->abbreviations.insert("HOG", "Stream([DropFrames(5)+Cvt(Gray)+KeyPointDetector(SIFT)+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat])+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
53   - Globals->abbreviations.insert("HOF", "Stream([DropFrames(5)+KeyPointDetector(SIFT),AggregateFrames(2),OpticalFlow+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat])+Contract+CatRows+KMeans(500)+Hist(500)");
54   - Globals->abbreviations.insert("HOGHOF", "Stream([DropFrames(5)+Cvt(Gray),KeyPointDetector(SIFT),AggregateFrames(2),(OpticalFlow+Gradient+Bin(0,360,8)+ROI+Hist(8))/(First+Gradient+Bin(0,360,8)+ROI+Hist(8)),CatCols])+Contract+CatRows+KMeans(500)+Hist(500)");
  49 + Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)");
  50 + Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)");
  51 + Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)");
  52 +
  53 + Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+KeyPointDetector(SIFT)+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
  54 + Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+KeyPointDetector(SIFT)+AggregateFrames(2)+OpticalFlow+ROI+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)");
  55 + Globals->abbreviations.insert("HOGHOF", "Stream(DropFrames(5)+Cvt(Gray),KeyPointDetector(SIFT)+AggregateFrames(2)+(OpticalFlow+Gradient+Bin(0,360,8)+ROI+Hist(8))/(First+Gradient+Bin(0,360,8)+ROI+Hist(8))+CatCols)+Contract+CatRows+KMeans(500)+Hist(500)");
55 56  
56 57 // Generic Image Processing
57 58 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
... ...
openbr/plugins/stream.cpp
... ... @@ -649,7 +649,7 @@ public:
649 649 class ProcessingStage
650 650 {
651 651 public:
652   - friend class StreamTransform;
  652 + friend class DirectStreamTransform;
653 653 public:
654 654 ProcessingStage(int nThreads = 1)
655 655 {
... ... @@ -1015,13 +1015,16 @@ public:
1015 1015 };
1016 1016  
1017 1017  
1018   -class StreamTransform : public CompositeTransform
  1018 +
  1019 +class DirectStreamTransform : public CompositeTransform
1019 1020 {
1020 1021 Q_OBJECT
1021 1022 public:
1022 1023 Q_PROPERTY(int activeFrames READ get_activeFrames WRITE set_activeFrames RESET reset_activeFrames)
1023 1024 BR_PROPERTY(int, activeFrames, 100)
1024 1025  
  1026 + friend class StreamTransfrom;
  1027 +
1025 1028 void train(const TemplateList & data)
1026 1029 {
1027 1030 if (!trainable) {
... ... @@ -1115,6 +1118,10 @@ public:
1115 1118 {
1116 1119 if (transforms.isEmpty()) return;
1117 1120  
  1121 + for (int i=0; i < processingStages.size();i++)
  1122 + delete processingStages[i];
  1123 + processingStages.clear();
  1124 +
1118 1125 // call CompositeTransform::init so that trainable is set
1119 1126 // correctly.
1120 1127 CompositeTransform::init();
... ... @@ -1190,12 +1197,13 @@ public:
1190 1197 collectionStage->nextStage = readStage;
1191 1198 }
1192 1199  
1193   - ~StreamTransform()
  1200 + ~DirectStreamTransform()
1194 1201 {
1195 1202 // Delete all the stages
1196 1203 for (int i = 0; i < processingStages.size(); i++) {
1197 1204 delete processingStages[i];
1198 1205 }
  1206 + processingStages.clear();
1199 1207 }
1200 1208  
1201 1209 protected:
... ... @@ -1237,12 +1245,149 @@ protected:
1237 1245 }
1238 1246 };
1239 1247  
1240   -QHash<QObject *, QThreadPool *> StreamTransform::pools;
1241   -QMutex StreamTransform::poolsAccess;
  1248 +QHash<QObject *, QThreadPool *> DirectStreamTransform::pools;
  1249 +QMutex DirectStreamTransform::poolsAccess;
  1250 +
  1251 +BR_REGISTER(Transform, DirectStreamTransform)
  1252 +
  1253 +;
  1254 +
  1255 +class StreamTransform : public TimeVaryingTransform
  1256 +{
  1257 + Q_OBJECT
  1258 +
  1259 +public:
  1260 + StreamTransform() : TimeVaryingTransform(false)
  1261 + {
  1262 + }
  1263 +
  1264 + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform STORED false)
  1265 + Q_PROPERTY(int activeFrames READ get_activeFrames WRITE set_activeFrames RESET reset_activeFrames)
  1266 + BR_PROPERTY(br::Transform *, transform, NULL)
  1267 + BR_PROPERTY(int, activeFrames, 100)
  1268 +
  1269 + bool timeVarying() const { return true; }
  1270 +
  1271 + void project(const Template &src, Template &dst) const
  1272 + {
  1273 + basis.project(src,dst);
  1274 + }
  1275 +
  1276 + void projectUpdate(const Template &src, Template &dst)
  1277 + {
  1278 + basis.projectUpdate(src,dst);
  1279 + }
  1280 + void projectUpdate(const TemplateList & src, TemplateList & dst)
  1281 + {
  1282 + basis.projectUpdate(src,dst);
  1283 + }
  1284 +
  1285 +
  1286 + void train(const TemplateList & data)
  1287 + {
  1288 + basis.train(data);
  1289 + }
  1290 +
  1291 + virtual void finalize(TemplateList & output)
  1292 + {
  1293 + (void) output;
  1294 + // Nothing in particular to do here, stream calls finalize
  1295 + // on all child transforms as part of projectUpdate
  1296 + }
  1297 +
  1298 + // reinterpret transform, set up the actual stream. We can only reinterpret pipes
  1299 + void init()
  1300 + {
  1301 + if (!transform)
  1302 + return;
  1303 +
  1304 + basis.setParent(this->parent());
  1305 + basis.transforms.clear();
  1306 + basis.activeFrames = this->activeFrames;
  1307 +
  1308 + // We need at least a CompositeTransform * to acess transform's children.
  1309 + CompositeTransform * downcast = dynamic_cast<CompositeTransform *> (transform);
  1310 +
  1311 + // If this isn't even a composite transform, or it's not a pipe, just set up
  1312 + // basis with 1 stage.
  1313 + if (!downcast || QString(transform->metaObject()->className()) != "br::PipeTransform")
  1314 + {
  1315 + basis.transforms.append(transform);
  1316 + basis.init();
  1317 + return;
  1318 + }
  1319 + if (downcast->transforms.empty())
  1320 + {
  1321 + qWarning("Trying to set up empty stream");
  1322 + basis.init();
  1323 + return;
  1324 + }
  1325 +
  1326 + // OK now we will regroup downcast's children
  1327 + QList<QList<Transform *> > sets;
  1328 + sets.append(QList<Transform *> ());
  1329 + sets.last().append(downcast->transforms[0]);
  1330 + if (downcast->transforms[0]->timeVarying())
  1331 + sets.append(QList<Transform *> ());
  1332 +
  1333 + for (int i=1;i < downcast->transforms.size(); i++) {
  1334 + // If this is time varying it becomse its own stage
  1335 + if (downcast->transforms[i]->timeVarying()) {
  1336 + // If a set was already active, we add another one
  1337 + if (!sets.last().empty()) {
  1338 + sets.append(QList<Transform *>());
  1339 + }
  1340 + // add the item
  1341 + sets.last().append(downcast->transforms[i]);
  1342 + // Add another set to indicate separation.
  1343 + sets.append(QList<Transform *>());
  1344 + }
  1345 + // otherwise, we can combine non time-varying stages
  1346 + else {
  1347 + sets.last().append(downcast->transforms[i]);
  1348 + }
  1349 +
  1350 + }
  1351 + if (sets.last().empty())
  1352 + sets.removeLast();
  1353 +
  1354 + QList<Transform *> transform_set;
  1355 + transform_set.reserve(sets.size());
  1356 + for (int i=0; i < sets.size(); i++) {
  1357 + // If this is a single transform set, we add that to the list
  1358 + if (sets[i].size() == 1 ) {
  1359 + transform_set.append(sets[i].at(0));
  1360 + }
  1361 + //otherwise we build a pipe
  1362 + else {
  1363 + CompositeTransform * pipe = dynamic_cast<CompositeTransform *>(Transform::make("Pipe([])", this));
  1364 + pipe->transforms = sets[i];
  1365 + pipe->init();
  1366 + transform_set.append(pipe);
  1367 + }
  1368 + }
  1369 +
  1370 + basis.transforms = transform_set;
  1371 + basis.init();
  1372 + }
  1373 +
  1374 + Transform * smartCopy()
  1375 + {
  1376 + // We just want the DirectStream to begin with, so just return a copy of that.
  1377 + DirectStreamTransform * res = (DirectStreamTransform *) basis.smartCopy();
  1378 + res->activeFrames = this->activeFrames;
  1379 + return res;
  1380 + }
  1381 +
  1382 +
  1383 +private:
  1384 + DirectStreamTransform basis;
  1385 +};
1242 1386  
1243 1387 BR_REGISTER(Transform, StreamTransform)
1244 1388  
1245 1389  
  1390 +
1246 1391 } // namespace br
1247 1392  
1248 1393 #include "stream.moc"
... ...