Commit c6a5dfecbf2a03795fc25f6c334202e285f6d385

Authored by Charles Otto
1 parent a2489d31

In enroll, apply Stream's staging logic to the base algorithm

When setting up the stream in enroll, use the Stream interface's staging logic
on the input algorithm. Making this happen is slightly complex when we don't
particularly have header files, but on the plus side algorithms incorporating
something like Show (e.g. ShowFaceDetection) will not be used as a single
threaded stage in the process.
openbr/core/core.cpp
@@ -131,18 +131,33 @@ struct AlgorithmCore @@ -131,18 +131,33 @@ struct AlgorithmCore
131 131
132 TemplateList i(TemplateList::fromGallery(input)); 132 TemplateList i(TemplateList::fromGallery(input));
133 133
134 - QString shellDescription = "DirectStream([Identity,ProgressCounter("+QString::number(i.length())+")+GalleryOutput("+gallery.flat()+")+Discard],readMode=DistributeFrames)"; 134 + // Trust me, this makes complete sense.
  135 + // We're just going to make a pipe with a placeholder first transform
  136 + QString pipeDesc = "Identity+ProgressCounter("+QString::number(i.length())+")+GalleryOutput("+gallery.flat()+")+Discard";
  137 + QScopedPointer<Transform> basePipe(Transform::make(pipeDesc,NULL));
135 138
136 - // Make a stream with a placeholder first transform, and our progress counter/gallery output.  
137 - QScopedPointer<Transform> enrollJob(Transform::make(shellDescription, NULL));  
138 -  
139 - CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(enrollJob.data()); 139 + CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data());
140 if (downcast == NULL) 140 if (downcast == NULL)
141 qFatal("downcast failed?"); 141 qFatal("downcast failed?");
142 142
  143 + // replace that placeholder with the current algorithm
143 downcast->transforms[0] = this->transform.data(); 144 downcast->transforms[0] = this->transform.data();
  145 +
  146 + // call init on the pipe to collapse the algorithm (if its top level is a pipe)
144 downcast->init(); 147 downcast->init();
145 - downcast->projectUpdate(i,i); 148 +
  149 + // Next, we make a Stream (with placeholder transform)
  150 + QString streamDesc = "Stream(Identity, readMode=DistributeFrames)";
  151 + QScopedPointer<Transform> baseStream(Transform::make(streamDesc, NULL));
  152 + WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data());
  153 +
  154 + // replace that placeholder with the pipe we built
  155 + wrapper->transform = downcast;
  156 +
  157 + // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward.
  158 + wrapper->init();
  159 +
  160 + wrapper->projectUpdate(i,i);
146 161
147 return i.files(); 162 return i.files();
148 } 163 }
openbr/plugins/algorithms.cpp
@@ -38,7 +38,7 @@ class AlgorithmsInitializer : public Initializer @@ -38,7 +38,7 @@ class AlgorithmsInitializer : public Initializer
38 Globals->abbreviations.insert("MedianFace", "Open!Cascade(FrontalFace)+ASEFEyes+Affine(256,256,0.37,0.45)+Center(Median)"); 38 Globals->abbreviations.insert("MedianFace", "Open!Cascade(FrontalFace)+ASEFEyes+Affine(256,256,0.37,0.45)+Center(Median)");
39 Globals->abbreviations.insert("BlurredFaceDetection", "Open+LimitSize(1024)+SkinMask/(Cvt(Gray)+GradientMask)+And+Morph(Erode,16)+LargestConvexArea"); 39 Globals->abbreviations.insert("BlurredFaceDetection", "Open+LimitSize(1024)+SkinMask/(Cvt(Gray)+GradientMask)+And+Morph(Erode,16)+LargestConvexArea");
40 Globals->abbreviations.insert("DrawFaceDetection", "Open+Cascade(FrontalFace)!ASEFEyes+Draw"); 40 Globals->abbreviations.insert("DrawFaceDetection", "Open+Cascade(FrontalFace)!ASEFEyes+Draw");
41 - Globals->abbreviations.insert("ShowFaceDetection", "DrawFaceDetection!Show[distribute=false]"); 41 + Globals->abbreviations.insert("ShowFaceDetection", "DrawFaceDetection!Show");
42 Globals->abbreviations.insert("OpenBR", "FaceRecognition"); 42 Globals->abbreviations.insert("OpenBR", "FaceRecognition");
43 Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); 43 Globals->abbreviations.insert("GenderEstimation", "GenderClassification");
44 Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); 44 Globals->abbreviations.insert("AgeEstimation", "AgeRegression");
openbr/plugins/openbr_internal.h
@@ -154,6 +154,53 @@ protected: @@ -154,6 +154,53 @@ protected:
154 } 154 }
155 }; 155 };
156 156
  157 +/*!
  158 + * \brief Interface for transforms that act as decorators of another transform
  159 + */
  160 +class BR_EXPORT WrapperTransform : public TimeVaryingTransform
  161 +{
  162 + Q_OBJECT
  163 +public:
  164 + WrapperTransform(bool independent = true) : TimeVaryingTransform(independent)
  165 + {
  166 + }
  167 +
  168 + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)
  169 + BR_PROPERTY(br::Transform *, transform, NULL)
  170 +
  171 + bool timeVarying() const { return transform->timeVarying(); }
  172 +
  173 + void project(const Template &src, Template &dst) const
  174 + {
  175 + transform->project(src,dst);
  176 + }
  177 +
  178 + void projectUpdate(const Template &src, Template &dst)
  179 + {
  180 + transform->projectUpdate(src,dst);
  181 + }
  182 + void projectUpdate(const TemplateList & src, TemplateList & dst)
  183 + {
  184 + transform->projectUpdate(src,dst);
  185 + }
  186 +
  187 + void train(const QList<TemplateList> & data)
  188 + {
  189 + transform->train(data);
  190 + }
  191 +
  192 + virtual void finalize(TemplateList & output)
  193 + {
  194 + transform->finalize(output);
  195 + }
  196 +
  197 + void init()
  198 + {
  199 + if (transform)
  200 + this->trainable = transform->trainable;
  201 + }
  202 +
  203 +};
157 204
158 /*! 205 /*!
159 * \brief A MetaTransform that aggregates some sub-transforms 206 * \brief A MetaTransform that aggregates some sub-transforms
openbr/plugins/stream.cpp
@@ -1013,21 +1013,20 @@ QMutex DirectStreamTransform::poolsAccess; @@ -1013,21 +1013,20 @@ QMutex DirectStreamTransform::poolsAccess;
1013 1013
1014 BR_REGISTER(Transform, DirectStreamTransform) 1014 BR_REGISTER(Transform, DirectStreamTransform)
1015 1015
1016 -;  
1017 -  
1018 -class StreamTransform : public TimeVaryingTransform 1016 +class StreamTransform : public WrapperTransform
1019 { 1017 {
1020 Q_OBJECT 1018 Q_OBJECT
1021 1019
1022 public: 1020 public:
1023 - StreamTransform() : TimeVaryingTransform(false) 1021 + StreamTransform() : WrapperTransform(false)
1024 { 1022 {
1025 } 1023 }
1026 1024
1027 - Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false)  
1028 Q_PROPERTY(int activeFrames READ get_activeFrames WRITE set_activeFrames RESET reset_activeFrames) 1025 Q_PROPERTY(int activeFrames READ get_activeFrames WRITE set_activeFrames RESET reset_activeFrames)
1029 - BR_PROPERTY(br::Transform *, transform, NULL) 1026 + Q_PROPERTY(br::DirectStreamTransform::StreamModes readMode READ get_readMode WRITE set_readMode RESET reset_readMode)
  1027 +
1030 BR_PROPERTY(int, activeFrames, 100) 1028 BR_PROPERTY(int, activeFrames, 100)
  1029 + BR_PROPERTY(br::DirectStreamTransform::StreamModes, readMode, br::DirectStreamTransform::Auto)
1031 1030
1032 bool timeVarying() const { return true; } 1031 bool timeVarying() const { return true; }
1033 1032
@@ -1068,6 +1067,7 @@ public: @@ -1068,6 +1067,7 @@ public:
1068 basis.setParent(this->parent()); 1067 basis.setParent(this->parent());
1069 basis.transforms.clear(); 1068 basis.transforms.clear();
1070 basis.activeFrames = this->activeFrames; 1069 basis.activeFrames = this->activeFrames;
  1070 + basis.readMode = this->readMode;
1071 1071
1072 // We need at least a CompositeTransform * to acess transform's children. 1072 // We need at least a CompositeTransform * to acess transform's children.
1073 CompositeTransform * downcast = dynamic_cast<CompositeTransform *> (transform); 1073 CompositeTransform * downcast = dynamic_cast<CompositeTransform *> (transform);
@@ -1468,6 +1468,7 @@ void DirectStreamTransform::init() @@ -1468,6 +1468,7 @@ void DirectStreamTransform::init()
1468 1468
1469 // Are our children time varying or not? This decides whether 1469 // Are our children time varying or not? This decides whether
1470 // we run them in single threaded or multi threaded stages 1470 // we run them in single threaded or multi threaded stages
  1471 + stage_variance.clear();
1471 stage_variance.reserve(transforms.size()); 1472 stage_variance.reserve(transforms.size());
1472 foreach (const br::Transform *transform, transforms) { 1473 foreach (const br::Transform *transform, transforms) {
1473 stage_variance.append(transform->timeVarying()); 1474 stage_variance.append(transform->timeVarying());