Commit 570e3750cb8fdb927f36c825ef8825e3da19f51f
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
5 changed files
with
168 additions
and
16 deletions
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/meta.cpp
| @@ -614,6 +614,11 @@ public: | @@ -614,6 +614,11 @@ public: | ||
| 614 | 614 | ||
| 615 | void train(const TemplateList &data) | 615 | void train(const TemplateList &data) |
| 616 | { | 616 | { |
| 617 | + if (!transform->trainable) { | ||
| 618 | + qWarning("Attempted to train untrainable transform, nothing will happen."); | ||
| 619 | + return; | ||
| 620 | + } | ||
| 621 | + | ||
| 617 | transform->train(data); | 622 | transform->train(data); |
| 618 | } | 623 | } |
| 619 | 624 | ||
| @@ -628,7 +633,6 @@ public: | @@ -628,7 +633,6 @@ public: | ||
| 628 | else dst = output[0]; | 633 | else dst = output[0]; |
| 629 | } | 634 | } |
| 630 | 635 | ||
| 631 | - | ||
| 632 | // For each input template, form a single element TemplateList, push all those | 636 | // For each input template, form a single element TemplateList, push all those |
| 633 | // lists through transform, and form dst by concatenating the results. | 637 | // lists through transform, and form dst by concatenating the results. |
| 634 | // Process the single elemnt templates in parallel if parallelism is enabled. | 638 | // Process the single elemnt templates in parallel if parallelism is enabled. |
| @@ -677,7 +681,6 @@ public: | @@ -677,7 +681,6 @@ public: | ||
| 677 | 681 | ||
| 678 | void init() | 682 | void init() |
| 679 | { | 683 | { |
| 680 | - | ||
| 681 | if (transform && transform->timeVarying()) | 684 | if (transform && transform->timeVarying()) |
| 682 | transform = new br::TimeInvariantWrapperTransform(transform); | 685 | transform = new br::TimeInvariantWrapperTransform(transform); |
| 683 | } | 686 | } |
openbr/plugins/openbr_internal.h
| @@ -122,7 +122,10 @@ public: | @@ -122,7 +122,10 @@ public: | ||
| 122 | 122 | ||
| 123 | TimeInvariantWrapperTransform(Transform * basis) : transformSource(new TransformCopier(basis)) | 123 | TimeInvariantWrapperTransform(Transform * basis) : transformSource(new TransformCopier(basis)) |
| 124 | { | 124 | { |
| 125 | + if (!basis) | ||
| 126 | + qFatal("TimeInvariantWrapper created with NULL transform"); | ||
| 125 | baseTransform = basis; | 127 | baseTransform = basis; |
| 128 | + trainable = basis->trainable; | ||
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | virtual void project(const Template &src, Template &dst) const | 131 | virtual void project(const Template &src, Template &dst) const |
| @@ -132,7 +135,6 @@ public: | @@ -132,7 +135,6 @@ public: | ||
| 132 | transformSource.release(aTransform); | 135 | transformSource.release(aTransform); |
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | - | ||
| 136 | void project(const TemplateList &src, TemplateList &dst) const | 138 | void project(const TemplateList &src, TemplateList &dst) const |
| 137 | { | 139 | { |
| 138 | Transform * aTransform = transformSource.acquire(); | 140 | Transform * aTransform = transformSource.acquire(); |
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,17 +1015,20 @@ public: | @@ -1015,17 +1015,20 @@ 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) { |
| 1028 | - qWarning("How did this happen? You're training a nontrainable transform."); | 1031 | + qWarning("Attempted to train untrainable transform, nothing will happen."); |
| 1029 | return; | 1032 | return; |
| 1030 | } | 1033 | } |
| 1031 | qFatal("Stream train is currently not implemented."); | 1034 | qFatal("Stream train is currently not implemented."); |
| @@ -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,150 @@ protected: | @@ -1237,12 +1245,150 @@ 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 | + trainable = transform->trainable; | ||
| 1304 | + | ||
| 1305 | + basis.setParent(this->parent()); | ||
| 1306 | + basis.transforms.clear(); | ||
| 1307 | + basis.activeFrames = this->activeFrames; | ||
| 1308 | + | ||
| 1309 | + // We need at least a CompositeTransform * to acess transform's children. | ||
| 1310 | + CompositeTransform * downcast = dynamic_cast<CompositeTransform *> (transform); | ||
| 1311 | + | ||
| 1312 | + // If this isn't even a composite transform, or it's not a pipe, just set up | ||
| 1313 | + // basis with 1 stage. | ||
| 1314 | + if (!downcast || QString(transform->metaObject()->className()) != "br::PipeTransform") | ||
| 1315 | + { | ||
| 1316 | + basis.transforms.append(transform); | ||
| 1317 | + basis.init(); | ||
| 1318 | + return; | ||
| 1319 | + } | ||
| 1320 | + if (downcast->transforms.empty()) | ||
| 1321 | + { | ||
| 1322 | + qWarning("Trying to set up empty stream"); | ||
| 1323 | + basis.init(); | ||
| 1324 | + return; | ||
| 1325 | + } | ||
| 1326 | + | ||
| 1327 | + // OK now we will regroup downcast's children | ||
| 1328 | + QList<QList<Transform *> > sets; | ||
| 1329 | + sets.append(QList<Transform *> ()); | ||
| 1330 | + sets.last().append(downcast->transforms[0]); | ||
| 1331 | + if (downcast->transforms[0]->timeVarying()) | ||
| 1332 | + sets.append(QList<Transform *> ()); | ||
| 1333 | + | ||
| 1334 | + for (int i=1;i < downcast->transforms.size(); i++) { | ||
| 1335 | + // If this is time varying it becomse its own stage | ||
| 1336 | + if (downcast->transforms[i]->timeVarying()) { | ||
| 1337 | + // If a set was already active, we add another one | ||
| 1338 | + if (!sets.last().empty()) { | ||
| 1339 | + sets.append(QList<Transform *>()); | ||
| 1340 | + } | ||
| 1341 | + // add the item | ||
| 1342 | + sets.last().append(downcast->transforms[i]); | ||
| 1343 | + // Add another set to indicate separation. | ||
| 1344 | + sets.append(QList<Transform *>()); | ||
| 1345 | + } | ||
| 1346 | + // otherwise, we can combine non time-varying stages | ||
| 1347 | + else { | ||
| 1348 | + sets.last().append(downcast->transforms[i]); | ||
| 1349 | + } | ||
| 1350 | + | ||
| 1351 | + } | ||
| 1352 | + if (sets.last().empty()) | ||
| 1353 | + sets.removeLast(); | ||
| 1354 | + | ||
| 1355 | + QList<Transform *> transform_set; | ||
| 1356 | + transform_set.reserve(sets.size()); | ||
| 1357 | + for (int i=0; i < sets.size(); i++) { | ||
| 1358 | + // If this is a single transform set, we add that to the list | ||
| 1359 | + if (sets[i].size() == 1 ) { | ||
| 1360 | + transform_set.append(sets[i].at(0)); | ||
| 1361 | + } | ||
| 1362 | + //otherwise we build a pipe | ||
| 1363 | + else { | ||
| 1364 | + CompositeTransform * pipe = dynamic_cast<CompositeTransform *>(Transform::make("Pipe([])", this)); | ||
| 1365 | + pipe->transforms = sets[i]; | ||
| 1366 | + pipe->init(); | ||
| 1367 | + transform_set.append(pipe); | ||
| 1368 | + } | ||
| 1369 | + } | ||
| 1370 | + | ||
| 1371 | + basis.transforms = transform_set; | ||
| 1372 | + basis.init(); | ||
| 1373 | + } | ||
| 1374 | + | ||
| 1375 | + Transform * smartCopy() | ||
| 1376 | + { | ||
| 1377 | + // We just want the DirectStream to begin with, so just return a copy of that. | ||
| 1378 | + DirectStreamTransform * res = (DirectStreamTransform *) basis.smartCopy(); | ||
| 1379 | + res->activeFrames = this->activeFrames; | ||
| 1380 | + return res; | ||
| 1381 | + } | ||
| 1382 | + | ||
| 1383 | + | ||
| 1384 | +private: | ||
| 1385 | + DirectStreamTransform basis; | ||
| 1386 | +}; | ||
| 1242 | 1387 | ||
| 1243 | BR_REGISTER(Transform, StreamTransform) | 1388 | BR_REGISTER(Transform, StreamTransform) |
| 1244 | 1389 | ||
| 1245 | 1390 | ||
| 1391 | + | ||
| 1246 | } // namespace br | 1392 | } // namespace br |
| 1247 | 1393 | ||
| 1248 | #include "stream.moc" | 1394 | #include "stream.moc" |