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,12 +46,13 @@ class AlgorithmsInitializer : public Initializer
46 Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)"); 46 Globals->abbreviations.insert("CropFace", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.25,0.35)");
47 47
48 // Video 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 // Generic Image Processing 57 // Generic Image Processing
57 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); 58 Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
openbr/plugins/stream.cpp
@@ -649,7 +649,7 @@ public: @@ -649,7 +649,7 @@ public:
649 class ProcessingStage 649 class ProcessingStage
650 { 650 {
651 public: 651 public:
652 - friend class StreamTransform; 652 + friend class DirectStreamTransform;
653 public: 653 public:
654 ProcessingStage(int nThreads = 1) 654 ProcessingStage(int nThreads = 1)
655 { 655 {
@@ -1015,13 +1015,16 @@ public: @@ -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 Q_OBJECT 1021 Q_OBJECT
1021 public: 1022 public:
1022 Q_PROPERTY(int activeFrames READ get_activeFrames WRITE set_activeFrames RESET reset_activeFrames) 1023 Q_PROPERTY(int activeFrames READ get_activeFrames WRITE set_activeFrames RESET reset_activeFrames)
1023 BR_PROPERTY(int, activeFrames, 100) 1024 BR_PROPERTY(int, activeFrames, 100)
1024 1025
  1026 + friend class StreamTransfrom;
  1027 +
1025 void train(const TemplateList & data) 1028 void train(const TemplateList & data)
1026 { 1029 {
1027 if (!trainable) { 1030 if (!trainable) {
@@ -1115,6 +1118,10 @@ public: @@ -1115,6 +1118,10 @@ public:
1115 { 1118 {
1116 if (transforms.isEmpty()) return; 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 // call CompositeTransform::init so that trainable is set 1125 // call CompositeTransform::init so that trainable is set
1119 // correctly. 1126 // correctly.
1120 CompositeTransform::init(); 1127 CompositeTransform::init();
@@ -1190,12 +1197,13 @@ public: @@ -1190,12 +1197,13 @@ public:
1190 collectionStage->nextStage = readStage; 1197 collectionStage->nextStage = readStage;
1191 } 1198 }
1192 1199
1193 - ~StreamTransform() 1200 + ~DirectStreamTransform()
1194 { 1201 {
1195 // Delete all the stages 1202 // Delete all the stages
1196 for (int i = 0; i < processingStages.size(); i++) { 1203 for (int i = 0; i < processingStages.size(); i++) {
1197 delete processingStages[i]; 1204 delete processingStages[i];
1198 } 1205 }
  1206 + processingStages.clear();
1199 } 1207 }
1200 1208
1201 protected: 1209 protected:
@@ -1237,12 +1245,149 @@ 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 BR_REGISTER(Transform, StreamTransform) 1387 BR_REGISTER(Transform, StreamTransform)
1244 1388
1245 1389
  1390 +
1246 } // namespace br 1391 } // namespace br
1247 1392
1248 #include "stream.moc" 1393 #include "stream.moc"