/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __OPENBR_PLUGIN_H #define __OPENBR_PLUGIN_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BR_EXCEPTIONS # define try if (true) # define catch(X) if (false) #endif // BR_EXCEPTIONS /*! * \defgroup cpp_plugin_sdk C++ Plugin SDK * \brief Plugin API for developing new algorithms. * * \code * #include * \endcode * * \par Development * Plugins should be developed in sdk/plugins/. * See this folder for numerous examples of existing plugins to follow when writing your own. * Plugins may optionally include a .cmake file to control build configuration. * * \par Documentation * Plugin documentation should include at least three lines providing the plugin abstraction, a brief explanation, and author. * If multiple authors are specified, the last author is assumed to be the current maintainer of the plugin. * Plugin authors are encouraged to \\cite relevant papers by adding them to share/openbr/openbr.bib. * * \section examples Examples * - \ref cpp_compare_faces * \subsection cpp_compare_faces Compare Faces * \ref cli_compare_faces "Command Line Interface Equivalent" * \snippet app/examples/compare_faces.cpp compare_faces */ namespace br { /*! * \addtogroup cpp_plugin_sdk * @{ */ /*! * Helper macro for use with Q_PROPERTY. * * \b Example:
* Note the symmetry between \c BR_PROPERTY and \c Q_PROPERTY. * \snippet sdk/plugins/misc.cpp example_transform */ #define BR_PROPERTY(TYPE,NAME,DEFAULT) \ TYPE NAME; \ TYPE get_##NAME() const { return NAME; } \ void set_##NAME(TYPE the_##NAME) { NAME = the_##NAME; } \ void reset_##NAME() { NAME = DEFAULT; } /*! * \brief A file path with associated metadata. * * The br::File is one of the workhorse classes in OpenBR. * It is typically used to store the path to a file on disk with associated metadata. * The ability to associate a hashtable of metadata with the file helps keep the API simple and stable while providing customizable behavior when appropriate. * * When querying the value of a metadata key, the value will first try to be resolved using the file's private metadata table. * If the key does not exist in the local hashtable then it will be resolved using the properities in the global br::Context. * This has the desirable effect that file metadata may optionally set globally using br::Context::set to operate on all files. * * Files have a simple grammar that allow them to be converted to and from strings. * If a string ends with a \c ] or \c ) then the text within the final \c [] or \c () are parsed as comma sperated metadata fields. * Fields within \c [] are expected to have the format [key1=value1, key2=value2, ..., keyN=valueN]. * Fields within \c () are expected to have the format (value1, value2, ..., valueN) with the keys determined from the order of \c Q_PROPERTY. * The rest of the string is assigned to #name. * * Metadata keys fall into one of two categories: * - \c camelCaseKeys are inputs that specify how to process the file. * - \c Capitalized_Underscored_Keys are outputs computed from processing the file. * * Below are some of the most commonly occuring standardized keys: * * Key | Value | Description * --- | ---- | ----------- * path | QString | Resolve complete file paths from file names * enrollAll | bool | Enroll zero or more templates per file * separator | QString | Seperate #name into multiple files * Input_Index | int | Index of a template in a template list * Label | float | Classification/Regression class * Confidence | float | Classification/Regression quality * FTE | bool | Failure to enroll * FTO | bool | Failure to open * *_X | float | Position * *_Y | float | Position * *_Width | float | Size * *_Height | float | Size * *_Radius | float | Size * Theta | float | Pose * Roll | float | Pose * Pitch | float | Pose * Yaw | float | Pose * Landmarks | QList | Landmark list * ROIs | QList | Region Of Interest (ROI) list * Age | QString | Age used for demographic filtering * _* | * | Reserved for internal use */ struct BR_EXPORT File { QString name; /*!< \brief Path to a file on disk. */ File() {} File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */ File(const QString &file, const QVariant &label) { init(file); insert("Label", label); } /*!< \brief Construct a file from a string and assign a label. */ File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */ operator QString() const { return name; } /*!< \brief Returns #name. */ QString flat() const; /*!< \brief A stringified version of the file with metadata. */ QString hash() const; /*!< \brief A hash of the file. */ inline void clear() { name.clear(); m_metadata.clear(); } /*!< \brief Clears the file's name and metadata. */ inline QList localKeys() const { return m_metadata.keys(); } /*!< \brief Returns the private metadata keys. */ inline QHash localMetadata() const { return m_metadata; } /*!< \brief Returns the private metadata. */ inline void insert(const QString &key, const QVariant &value) { set(key, value); } /*!< \brief Equivalent to set(). */ void append(const QHash &localMetadata); /*!< \brief Add new metadata fields. */ void append(const File &other); /*!< \brief Append another file using \c separator. */ QList split() const; /*!< \brief Split the file using \c separator. */ QList split(const QString &separator) const; /*!< \brief Split the file. */ inline void insertParameter(int index, const QVariant &value) { insert("_Arg" + QString::number(index), value); } /*!< \brief Insert a keyless value. */ inline bool containsParameter(int index) const { return m_metadata.contains("_Arg" + QString::number(index)); } /*!< \brief Check for the existence of a keyless value. */ inline QVariant parameter(int index) const { return m_metadata.value("_Arg" + QString::number(index)); } /*!< \brief Retrieve a keyless value. */ inline bool operator==(const char* other) const { return name == other; } /*!< \brief Compare name to c-style string. */ inline bool operator==(const File &other) const { return (name == other.name) && (m_metadata == other.m_metadata); } /*!< \brief Compare name and metadata for equality. */ inline bool operator!=(const File &other) const { return !(*this == other); } /*!< \brief Compare name and metadata for inequality. */ inline bool operator<(const File &other) const { return name < other.name; } /*!< \brief Compare name. */ inline bool operator<=(const File &other) const { return name <= other.name; } /*!< \brief Compare name. */ inline bool operator>(const File &other) const { return name > other.name; } /*!< \brief Compare name. */ inline bool operator>=(const File &other) const { return name >= other.name; } /*!< \brief Compare name. */ inline File &operator+=(const QHash &other) { append(other); return *this; } /*!< \brief Add new metadata fields. */ inline File &operator+=(const File &other) { append(other); return *this; } /*!< \brief Append another file using \c separator. */ inline bool isNull() const { return name.isEmpty() && m_metadata.isEmpty(); } /*!< \brief Returns \c true if name and metadata are empty, \c false otherwise. */ inline bool isTerminal() const { return name == "terminal"; } /*!< \brief Returns \c true if #name is "terminal", \c false otherwise. */ inline bool exists() const { return QFileInfo(name).exists(); } /*!< \brief Returns \c true if the file exists on disk, \c false otherwise. */ inline QString fileName() const { return QFileInfo(name).fileName(); } /*!< \brief Returns the file's base name and extension. */ inline QString baseName() const { const QString baseName = QFileInfo(name).baseName(); return baseName.isEmpty() ? QDir(name).dirName() : baseName; } /*!< \brief Returns the file's base name. */ inline QString suffix() const { return QFileInfo(name).suffix(); } /*!< \brief Returns the file's extension. */ bool contains(const QString &key) const; /*!< \brief Returns \c true if the key has an associated value, \c false otherwise. */ QVariant value(const QString &key) const; /*!< \brief Returns the value for the specified key. */ static QString subject(int label); /*!< \brief Looks up the subject for the provided label. */ inline QString subject() const { return subject(label()); } /*!< \brief Looks up the subject from the file's label. */ inline bool failed() const { return getBool("FTE") || getBool("FTO"); } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */ void remove(const QString &key); /*!< \brief Remove the metadata key. */ void set(const QString &key, const QVariant &value); /*!< \brief Insert or overwrite the metadata key with the specified value. */ QVariant get(const QString &key) const; /*!< \brief Returns a QVariant for the key, throwing an error if the key does not exist. */ QVariant get(const QString &key, const QVariant &value) const; /*!< \brief Returns a QVariant for the key, returning \em defaultValue if the key does not exist. */ float label() const; /*!< \brief Convenience function for retrieving the file's \c Label. */ inline void setLabel(float label) { insert("Label", label); } /*!< \brief Convenience function for setting the file's \c Label. */ bool getBool(const QString &key) const; /*!< \brief Returns a boolean value for the key. */ void setBool(const QString &key, bool value = true); /*!< \brief Sets a boolean value for the key. */ int getInt(const QString &key) const; /*!< \brief Returns an int value for the key, throwing an error if the key does not exist. */ int getInt(const QString &key, int defaultValue) const; /*!< \brief Returns an int value for the key, returning \em defaultValue if the key does not exist. */ float getFloat(const QString &key) const; /*!< \brief Returns a float value for the key, throwing an error if the key does not exist. */ float getFloat(const QString &key, float defaultValue) const; /*!< \brief Returns a float value for the key, returning \em defaultValue if the key does not exist. */ QString getString(const QString &key) const; /*!< \brief Returns a string value for the key, throwing an error if the key does not exist. */ QString getString(const QString &key, const QString &defaultValue) const; /*!< \brief Returns a string value for the key, returning \em defaultValue if the key does not exist. */ QList landmarks() const; /*!< \brief Returns the file's landmark list. */ void appendLandmark(const QPointF &landmark); /*!< \brief Adds a landmark to the file's landmark list. */ void appendLandmarks(const QList &landmarks); /*!< \brief Adds landmarks to the file's landmark list. */ inline void clearLandmarks() { m_metadata["Landmarks"] = QList(); } /*!< \brief Clears the file's landmark list. */ void setLandmarks(const QList &landmarks); /*!< \brief Assigns the file's landmark list. */ QList ROIs() const; /*!< \brief Returns the file's ROI list. */ void appendROI(const QRectF &ROI); /*!< \brief Adds a ROI to the file's ROI list. */ void appendROIs(const QList &ROIs); /*!< \brief Adds ROIs to the file's ROI list. */ inline void clearROIs() { m_metadata["ROIs"] = QList(); } /*!< \brief Clears the file's landmark list. */ void setROIs(const QList &ROIs); /*!< \brief Assigns the file's landmark list. */ private: QHash m_metadata; BR_EXPORT friend QDataStream &operator<<(QDataStream &stream, const File &file); /*!< */ BR_EXPORT friend QDataStream &operator>>(QDataStream &stream, File &file); /*!< */ void init(const QString &file); }; BR_EXPORT QDebug operator<<(QDebug dbg, const File &file); /*!< \brief Prints br::File::flat() to \c stderr. */ BR_EXPORT QDataStream &operator<<(QDataStream &stream, const File &file); /*!< \brief Serializes the file to a stream. */ BR_EXPORT QDataStream &operator>>(QDataStream &stream, File &file); /*!< \brief Deserializes the file from a stream. */ /*! * \brief A list of files. * * Convenience class for working with a list of files. */ struct BR_EXPORT FileList : public QList { FileList() {} FileList(int n); /*!< \brief Initialize the list with \em n empty files. */ FileList(const QStringList &files); /*!< \brief Initialize the file list from a string list. */ FileList(const QList &files) { append(files); } /*!< \brief Initialize the file list from another file list. */ QStringList flat() const; /*!< \brief Returns br::File::flat() for each file in the list. */ QStringList names() const; /*!< \brief Returns #br::File::name for each file in the list. */ void sort(const QString& key); /*!< \brief Sort the list based on metadata. */ QList labels() const; /*!< \brief Returns br::File::label() for each file in the list. */ int failures() const; /*!< \brief Returns the number of files with br::File::failed(). */ }; /*! * \brief A list of matrices associated with a file. * * The br::Template is one of the workhorse classes in OpenBR. * A template represents a biometric at various stages of enrollment and can be modified br::Transform and compared to other templates with br::Distance. * * While there exist many cases (ex. video enrollment, multiple face detects, per-patch subspace learning, ...) where the template will contain more than one matrix, * in most cases templates have exactly one matrix in their list representing a single image at various stages of enrollment. * In the cases where exactly one image is expected, the template provides the function m() as an idiom for treating it as a single matrix. * Casting operators are also provided to pass the template into image processing functions expecting matrices. * * Metadata related to the template that is computed during enrollment (ex. bounding boxes, eye locations, quality metrics, ...) should be assigned to the template's #file member. */ struct Template : public QList { File file; /*!< \brief The file from which the template is constructed. */ Template() {} Template(const File &_file) : file(_file) {} /*!< \brief Initialize #file. */ Template(const File &_file, const cv::Mat &mat) : file(_file) { append(mat); } /*!< \brief Initialize #file and append a matrix. */ Template(const cv::Mat &mat) { append(mat); } /*!< \brief Append a matrix. */ inline const cv::Mat &m() const { static const cv::Mat NullMatrix; return isEmpty() ? qFatal("Template::m() empty template."), NullMatrix : last(); } /*!< \brief Idiom to treat the template as a matrix. */ inline cv::Mat &m() { return isEmpty() ? append(cv::Mat()), last() : last(); } /*!< \brief Idiom to treat the template as a matrix. */ inline cv::Mat &operator=(const cv::Mat &other) { return m() = other; } /*!< \brief Idiom to treat the template as a matrix. */ inline operator const cv::Mat&() const { return m(); } /*!< \brief Idiom to treat the template as a matrix. */ inline operator cv::Mat&() { return m(); } /*!< \brief Idiom to treat the template as a matrix. */ inline operator cv::_InputArray() const { return m(); } /*!< \brief Idiom to treat the template as a matrix. */ inline operator cv::_OutputArray() { return m(); } /*!< \brief Idiom to treat the template as a matrix. */ inline bool isNull() const { return isEmpty() || !m().data; } /*!< \brief Returns \c true if the template is empty or has no matrix data, \c false otherwise. */ inline void merge(const Template &other) { append(other); file.append(other.file); } /*!< \brief Append the contents of another template. */ /*! * \brief Returns the total number of bytes in all the matrices. */ size_t bytes() const { size_t bytes = 0; foreach (const cv::Mat &m, *this) bytes += m.total() * m.elemSize(); return bytes; } /*! * \brief Copies all the matrices and returns a new template. */ Template clone() const { Template other(file); foreach (const cv::Mat &m, *this) other += m.clone(); return other; } }; /*! * \brief A list of templates. * * Convenience class for working with a list of templates. */ struct TemplateList : public QList