Commit f1f3728b72f9d6853b90595eb94b75e9952a430f

Authored by Scott Klum
2 parents 8a204192 b9d6ddae

Merge branch 'fbi_ebts'

Showing 1 changed file with 86 additions and 1 deletions
openbr/plugins/format.cpp
... ... @@ -16,6 +16,7 @@
16 16  
17 17 #include <QDate>
18 18 #include <QSize>
  19 +#include <QChar>
19 20 #ifndef BR_EMBEDDED
20 21 #include <QtXml>
21 22 #endif // BR_EMBEDDED
... ... @@ -720,7 +721,7 @@ BR_REGISTER(Format, xmlFormat)
720 721 /*!
721 722 * \ingroup formats
722 723 * \brief Reads in scores or ground truth from a text table.
723   - * \author Josh Klontz
  724 + * \author Josh Klontz \cite jklontz
724 725 *
725 726 * Example of the format:
726 727 * \code
... ... @@ -769,6 +770,90 @@ class scoresFormat : public Format
769 770  
770 771 BR_REGISTER(Format, scoresFormat)
771 772  
  773 +/*!
  774 + * \ingroup formats
  775 + * \brief Reads FBI EBTS transactions.
  776 + * \author Scott Klum \cite sklum
  777 + * https://www.fbibiospecs.org/ebts.html
  778 + * \note This will fail if a binary blob contains any of the fields attempt to locate within the file
  779 + */
  780 +class ebtsFormat : public Format
  781 +{
  782 + Q_OBJECT
  783 +
  784 + QString textFieldValue(const QByteArray &byteArray, const QString &fieldNumber, int from = 0) const
  785 + {
  786 + // Find the field, skip the number bytes, and account for the semicolon
  787 + int fieldPosition = byteArray.indexOf(fieldNumber, from) + fieldNumber.size() + 1;
  788 + int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition);
  789 +
  790 + return byteArray.mid(fieldPosition,sepPosition-fieldPosition);
  791 + }
  792 +
  793 + Template read() const
  794 + {
  795 + QByteArray byteArray;
  796 + QtUtils::readFile(file, byteArray);
  797 +
  798 + Template t;
  799 +
  800 + Mat m;
  801 +
  802 + // Demographics
  803 + {
  804 + QString name = textFieldValue(byteArray, "2.018");
  805 + QStringList names = name.split(',');
  806 + t.file.set("FIRSTNAME", names.at(1));
  807 + t.file.set("LASTNAME", names.at(0));
  808 + t.file.set("DOB", textFieldValue(byteArray, "2.022").toInt());
  809 + t.file.set("GENDER", textFieldValue(byteArray, "2.024"));
  810 + t.file.set("RACE", textFieldValue(byteArray, "2.025"));
  811 + }
  812 +
  813 + // Mugshot (first in file used)
  814 + // Todo: Check for face designation
  815 + {
  816 + const QString imageRecord = "10.001:";
  817 + const QString imageDataRecord = "10.999:";
  818 +
  819 + int fieldPosition = byteArray.indexOf(imageRecord);
  820 +
  821 + if (fieldPosition != -1) {
  822 + int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition);
  823 + int dataPosition = byteArray.indexOf(imageDataRecord,sepPosition);
  824 +
  825 + int recordBytes = byteArray.mid(fieldPosition,sepPosition-fieldPosition).toInt();
  826 + int headerBytes = byteArray.mid(fieldPosition,dataPosition-fieldPosition).size() + imageDataRecord.size();
  827 +
  828 + QByteArray data = byteArray.mid(dataPosition+imageRecord.size(),recordBytes-headerBytes);
  829 +
  830 + m = imdecode(Mat(3, data.size(), CV_8UC3, data.data()), CV_LOAD_IMAGE_COLOR);
  831 + if (!m.data) qWarning("ebtsFormat::read failed to decode image data.");
  832 + t.m() = m;
  833 + } else qWarning("ebtsFormat::cannot find image data within file.");
  834 +
  835 + }
  836 +
  837 + if (t.file.contains("DOB")) {
  838 + const QDate dob = QDate::fromString(t.file.get<QString>("DOB"), "yyyyMMdd");
  839 + const QDate current = QDate::currentDate();
  840 + int age = current.year() - dob.year();
  841 + if (current.month() < dob.month()) age--;
  842 + t.file.set("Age", age);
  843 + }
  844 +
  845 + return t;
  846 + }
  847 +
  848 + void write(const Template &t) const
  849 + {
  850 + (void) t;
  851 + qFatal("Writing EBTS files is not supported.");
  852 + }
  853 +};
  854 +
  855 +BR_REGISTER(Format, ebtsFormat)
  856 +
772 857 } // namespace br
773 858  
774 859 #include "format.moc"
... ...