/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2012 The MITRE Corporation * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "openbr_internal.h" #include "openbr/core/opencvutils.h" #include "openbr/core/qtutils.h" using namespace cv; namespace br { /*! * \ingroup transforms * \brief Applies br::Format to br::Template::file::name and appends results. * \author Josh Klontz \cite jklontz */ class OpenTransform : public UntrainableMetaTransform { Q_OBJECT void project(const Template &src, Template &dst) const { if (!src.isEmpty()) { dst = src; return; } if (Globals->verbose) qDebug("Opening %s", qPrintable(src.file.flat())); dst.file = src.file; foreach (const File &file, src.file.split()) { QScopedPointer format(Factory::make(file)); Template t = format->read(); if (t.isEmpty()) qWarning("Can't open %s from %s", qPrintable(file.flat()), qPrintable(QDir::currentPath())); dst.append(t); dst.file.append(t.file.localMetadata()); } dst.file.set("FTO", dst.isEmpty()); } }; BR_REGISTER(Transform, OpenTransform) /*! * \ingroup transforms * \brief Prints the template's file to stdout or stderr. * \author Josh Klontz \cite jklontz */ class PrintTransform : public UntrainableMetaTransform { Q_OBJECT Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error) Q_PROPERTY(bool data READ get_data WRITE set_data RESET reset_data) BR_PROPERTY(bool, error, true) BR_PROPERTY(bool, data, false) void project(const Template &src, Template &dst) const { dst = src; const QString nameString = src.file.flat(); const QString dataString = data ? OpenCVUtils::matrixToString(src)+"\n" : QString(); QStringList matricies; foreach (const Mat &m, src) matricies.append(QString::number(m.rows) + "x" + QString::number(m.cols) + "_" + OpenCVUtils::typeToString(m)); fprintf(error ? stderr : stdout, "%s\n %s\n%s", qPrintable(nameString), qPrintable(matricies.join(",")), qPrintable(dataString)); } }; BR_REGISTER(Transform, PrintTransform) /*! * \ingroup transforms * \brief Checks the template for NaN values. * \author Josh Klontz \cite jklontz */ class CheckTransform : public UntrainableMetaTransform { Q_OBJECT static int count; int index; public: CheckTransform() : index(count++) {} void project(const Template &src, Template &dst) const { dst = src; foreach (const Mat &m, src) { Mat fm; m.convertTo(fm, CV_32F); const int elements = fm.rows * fm.cols * fm.channels(); const float *data = (const float*)fm.data; for (int i=0; i(inputProperty)); if (!match.hasMatch()) qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.get(inputProperty))); dst.file.set(outputProperty, match.captured(match.lastCapturedIndex())); } }; BR_REGISTER(Transform, RegexPropertyTransform) /*! * \ingroup transforms * \brief Store the last matrix of the input template as a metadata key with input property name. * \author Charles Otto \cite caotto */ class SaveMatTransform : public UntrainableMetaTransform { Q_OBJECT Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) BR_PROPERTY(QString, propName, "") void project(const Template &src, Template &dst) const { dst = src; dst.file.set(propName, QVariant::fromValue(dst.m())); } }; BR_REGISTER(Transform, SaveMatTransform) /*! * \ingroup transforms * \brief Set the last matrix of the input template to a matrix stored as metadata with input propName. * * Also removes the property from the templates metadata after restoring it. * * \author Charles Otto \cite caotto */ class RestoreMatTransform : public UntrainableMetaTransform { Q_OBJECT Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) BR_PROPERTY(QString, propName, "") void project(const Template &src, Template &dst) const { dst = src; if (dst.file.contains(propName)) { dst.clear(); dst.m() = dst.file.get(propName); dst.file.remove(propName); } } }; BR_REGISTER(Transform, RestoreMatTransform) /*! * \ingroup transforms * \brief Incrementally output templates received to a gallery, based on the current filename * When a template is received in projectUpdate for the first time since a finalize, open a new gallery based on the * template's filename, and the galleryFormat property. * Templates received in projectUpdate will be output to the gallery with a filename combining their original filename and * their FrameNumber property, with the file extension specified by the fileFormat property. * \author Charles Otto \cite caotto */ class IncrementalOutputTransform : public TimeVaryingTransform { Q_OBJECT Q_PROPERTY(QString galleryFormat READ get_galleryFormat WRITE set_galleryFormat RESET reset_galleryFormat STORED false) Q_PROPERTY(QString fileFormat READ get_fileFormat WRITE set_fileFormat RESET reset_fileFormat STORED false) BR_PROPERTY(QString, galleryFormat, "") BR_PROPERTY(QString, fileFormat, ".png") bool galleryUp; void projectUpdate(const TemplateList &src, TemplateList &dst) { if (src.empty()) return; if (!galleryUp) { QFileInfo finfo(src[0].file.name); QString galleryName = finfo.baseName() + galleryFormat; writer = QSharedPointer (Factory::make(galleryName)); galleryUp = true; } dst = src; int idx =0; foreach(const Template & t, src) { if (t.empty()) continue; // Build the output filename for this template QFileInfo finfo(t.file.name); QString outputName = finfo.baseName() +"_" + t.file.get("FrameNumber") + "_" + QString::number(idx)+ fileFormat; idx++; Template out = t; out.file.name = outputName; writer->write(out); } } void train(const TemplateList& data) { (void) data; } // Drop the current gallery. void finalize(TemplateList & data) { (void) data; galleryUp = false; } QSharedPointer writer; public: IncrementalOutputTransform() : TimeVaryingTransform(false,false) {galleryUp = false;} }; BR_REGISTER(Transform, IncrementalOutputTransform) class EventTransform : public UntrainableMetaTransform { Q_OBJECT Q_PROPERTY(QString eventName READ get_eventName WRITE set_eventName RESET reset_eventName STORED false) BR_PROPERTY(QString, eventName, "") TemplateEvent event; void project(const Template &src, Template &dst) const { dst = src; event.pulseSignal(dst); } TemplateEvent * getEvent(const QString & name) { return name == eventName ? &event : NULL; } }; BR_REGISTER(Transform, EventTransform) class GalleryOutputTransform : public TimeVaryingTransform { Q_OBJECT Q_PROPERTY(QString outputString READ get_outputString WRITE set_outputString RESET reset_outputString STORED false) BR_PROPERTY(QString, outputString, "") void projectUpdate(const TemplateList &src, TemplateList &dst) { if (src.empty()) return; dst = src; writer->writeBlock(dst); } void train(const TemplateList& data) { (void) data; } ; void init() { writer = QSharedPointer(Gallery::make(outputString)); } QSharedPointer writer; public: GalleryOutputTransform() : TimeVaryingTransform(false,false) {} }; BR_REGISTER(Transform, GalleryOutputTransform) class ProgressCounterTransform : public TimeVaryingTransform { Q_OBJECT Q_PROPERTY(int totalTemplates READ get_totalTemplates WRITE set_totalTemplates RESET reset_totalTemplates STORED false) BR_PROPERTY(int, totalTemplates, 1) void projectUpdate(const TemplateList &src, TemplateList &dst) { dst = src; qint64 elapsed = timer.elapsed(); // updated every second if (elapsed > 1000) { Globals->printStatus(); timer.start(); } Globals->currentStep++; return; } void train(const TemplateList& data) { (void) data; } void finalize(TemplateList & data) { (void) data; float p = br_progress(); qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); } void init() { timer.start(); } public: ProgressCounterTransform() : TimeVaryingTransform(false,false) {} QElapsedTimer timer; }; BR_REGISTER(Transform, ProgressCounterTransform) class OutputTransform : public TimeVaryingTransform { Q_OBJECT Q_PROPERTY(QString outputString READ get_outputString WRITE set_outputString RESET reset_outputString STORED false) // names of mem galleries containing filelists we need. Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false) Q_PROPERTY(QString queryName READ get_queryName WRITE set_queryName RESET reset_queryName STORED false) Q_PROPERTY(bool transposeMode READ get_transposeMode WRITE set_transposeMode RESET reset_transposeMode STORED false) BR_PROPERTY(QString, outputString, "") BR_PROPERTY(QString, targetName, "") BR_PROPERTY(QString, queryName, "") BR_PROPERTY(bool,transposeMode, false) ; void projectUpdate(const TemplateList &src, TemplateList &dst) { dst = src; if (src.empty()) return; // we received a template, which is the next row/column in order foreach(const Template & t, dst) { for (int i=0; i < t.m().cols; i++) { output->setRelative(t.m().at(0, i), currentRow, currentCol); // row-major input if (!transposeMode) currentCol++; // col-major input else currentRow++; } // filled in a row, advance to the next, reset column position if (!transposeMode) { currentRow++; currentCol = 0; } // filled in a column, advance, reset row else { currentCol++; currentRow = 0; } } bool blockDone = false; // In direct mode, we don't buffer rows if (!transposeMode) { currentBlockRow++; blockDone = true; } // in transpose mode, we buffer 100 cols before writing the block else if (currentCol == bufferedSize) { currentBlockCol++; blockDone = true; } else return; if (blockDone) { // set the next block, only necessary if we haven't buffered the current item output->setBlock(currentBlockRow, currentBlockCol); currentRow = 0; currentCol = 0; } } void train(const TemplateList& data) { (void) data; } void init() { if (targetName.isEmpty() || queryName.isEmpty() || outputString.isEmpty()) return; FileList targetFiles = FileList::fromGallery(targetName); FileList queryFiles = FileList::fromGallery(queryName); currentBlockRow = 0; currentBlockCol = 0; currentRow = 0; currentCol = 0; bufferedSize = 100; if (transposeMode) { // buffer 100 cols at a time fragmentsPerRow = bufferedSize; // a single col contains comparisons to all query files fragmentsPerCol = queryFiles.size(); } else { // a single row contains comparisons to all target files fragmentsPerRow = targetFiles.size(); // we output rows one at a time fragmentsPerCol = 1; } output = QSharedPointer(Output::make(outputString, targetFiles, queryFiles)); output->blockRows = fragmentsPerCol; output->blockCols = fragmentsPerRow; output->initialize(targetFiles, queryFiles); output->setBlock(currentBlockRow, currentBlockCol); } QSharedPointer output; int bufferedSize; int currentRow; int currentCol; int currentBlockRow; int currentBlockCol; int fragmentsPerRow; int fragmentsPerCol; public: OutputTransform() : TimeVaryingTransform(false,false) {} }; BR_REGISTER(Transform, OutputTransform) } #include "misc.moc"