Commit 2f33ea8cce30ccffa747f44c1e71b6f4e592f453

Authored by Scott Klum
1 parent 16363df8

Generalized EBTS support

Showing 1 changed file with 108 additions and 42 deletions
openbr/plugins/format.cpp
... ... @@ -780,22 +780,26 @@ BR_REGISTER(Format, scoresFormat)
780 780 class ebtsFormat : public Format
781 781 {
782 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 783  
790   - return byteArray.mid(fieldPosition,sepPosition-fieldPosition);
791   - }
  784 + struct Field {
  785 + float type;
  786 + QList<QByteArray> data;
  787 + };
  788 +
  789 + struct Record {
  790 + int type;
  791 + quint32 bytes;
  792 + int position; // Starting position of record
792 793  
793   - int recordBytes(const QByteArray &byteArray, const float fieldNumber, int from = 0) const
  794 + QList<Field> fields;
  795 + };
  796 +
  797 + quint32 recordBytes(const QByteArray &byteArray, const float recordType, int from) const
794 798 {
795 799 bool ok;
796   - int size;
  800 + quint32 size;
797 801  
798   - if (fieldNumber == 4 || fieldNumber == 7) {
  802 + if (recordType == 4 || recordType == 7) {
799 803 // read first four bytes
800 804 ok = true;
801 805 size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData());
... ... @@ -807,16 +811,47 @@ class ebtsFormat : public Format
807 811 return ok ? size : -1;
808 812 }
809 813  
810   - QList<QByteArray> parseRecord(const QByteArray &byteArray, const int from, const int bytes) const
  814 + void parseRecord(const QByteArray &byteArray, Record &record) const
811 815 {
812   - return byteArray.mid(from,bytes).split(QChar(0x1D).toLatin1());
  816 + if (record.type == 4 || record.type == 7) {
  817 + // Just a binary blob
  818 + // Read everything after the first four bytes
  819 + // Not current supported
  820 + } else {
  821 + // Continue reading fields until we get all the data
  822 + int position = record.position;
  823 + float dataField = .999;
  824 + while (position < record.position + record.bytes) {
  825 + int index = byteArray.indexOf(QChar(0x1D), position);
  826 + Field field = parseField(byteArray.mid(position, index-position),QChar(0x1F));
  827 + if (field.type - dataField == record.type ) {
  828 + // Data begin after the field identifier and the colon
  829 + int dataBegin = byteArray.indexOf(':', position)+1;
  830 + field.data.clear();
  831 + field.data.append(byteArray.mid(dataBegin, record.bytes-(dataBegin-record.position)));
  832 +
  833 + // Data fields are always last in the record
  834 + record.fields.append(field);
  835 + break;
  836 + }
  837 + // Advance the position accounting for the separator
  838 + position += index-position+1;
  839 + record.fields.append(field);
  840 + }
  841 + }
813 842 }
814 843  
815   - QList<QByteArray> parseField(const QByteArray &byteArray, const QChar &sep) const
  844 + Field parseField(const QByteArray &byteArray, const QChar &sep) const
816 845 {
817   - QByteArray data = byteArray.split(':').last();
  846 + bool ok;
  847 + Field f;
818 848  
819   - return data.split(sep.toLatin1());
  849 + QList<QByteArray> data = byteArray.split(':');
  850 +
  851 + f.type = data.first().toFloat(&ok);
  852 + f.data = data.last().split(sep.toLatin1());
  853 +
  854 + return f;
820 855 }
821 856  
822 857 Template read() const
... ... @@ -828,40 +863,73 @@ class ebtsFormat : public Format
828 863  
829 864 Mat m;
830 865  
  866 + QList<Record> records;
  867 +
831 868 // Read the type one record (every EBTS file will have one of these)
832   - int recordOneBytes = recordBytes(byteArray,1);
833   - QList<QByteArray> recordOne = parseRecord(byteArray,0,recordOneBytes);
  869 + Record r1;
  870 + r1.type = 1;
  871 + r1.position = 0;
  872 + r1.bytes = recordBytes(byteArray,r1.type,r1.position);
  873 +
  874 + // The fields in a type 1 record are strictly defined
  875 + QList<QByteArray> data = byteArray.mid(r1.position,r1.bytes).split(QChar(0x1D).toLatin1());
  876 + foreach (const QByteArray &datum, data) {
  877 + Field f = parseField(datum,QChar(0x1F));
  878 + r1.fields.append(f);
  879 + }
834 880  
835   - // The third field (1.03/1.003) will have record identifiers for the remaining
836   - // portion of the transaction
837   - QList<QByteArray> recordOneFieldThree = parseField(recordOne.at(2),QChar(0x1F));
  881 + records.append(r1);
838 882  
839   - QList<int> recordTypes;
  883 + // Read the type two record (every EBTS file will have one of these)
  884 + Record r2;
  885 + r2.type = 2;
  886 + r2.position = r1.bytes;
  887 + r2.bytes = recordBytes(byteArray,r2.type,r2.position);
840 888  
841   - for (int i=2; i<recordOneFieldThree.size()-1; i++) /* We don't care about the first two and the final items */ {
842   - // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type
843   - QByteArray fieldNumber = recordOneFieldThree[i].mid(3);
844   - recordTypes.push_back(fieldNumber.toInt());
  889 + // The fields in a type 2 record are strictly defined
  890 + data = byteArray.mid(r2.position,r2.bytes).split(QChar(0x1D).toLatin1());
  891 + foreach (const QByteArray &datum, data) {
  892 + Field f = parseField(datum,QChar(0x1F));
  893 + r2.fields.append(f);
845 894 }
846 895  
847   - int recordTwoBytes = recordBytes(byteArray,2,recordOneBytes);
848   - QList<QByteArray> recordTwo = parseRecord(byteArray,recordOneBytes,recordTwoBytes);
849   -
850   - QList<int> recordSizes;
851   - int startingPosition = recordOneBytes + recordTwoBytes;
852   - foreach(int i, recordTypes) {
853   - // Maybe switch to position
854   - int recordSize = recordBytes(byteArray,i,startingPosition);
855   - qDebug() << i << recordSize;
856   - recordSizes.append(recordSize);
857   - startingPosition += recordSize;
  896 +
  897 + records.append(r2);
  898 +
  899 + // The third field of the first record contains informations about all the remaining records in the transaction
  900 + // We don't care about the first two and the final items
  901 + for (int i=2; i<r1.fields.at(2).data.size()-1; i++) {
  902 + // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type
  903 + QByteArray recordType = r1.fields.at(2).data[i].mid(3);
  904 + Record r;
  905 + r.type = recordType.toInt();
  906 + records.append(r);
858 907 }
859 908  
860   - // Parse the remaining records knowing that the first four bytes of types 4 and 7 are sizes
  909 + QList<int> frontalIdxs;
  910 + int position = r1.bytes + r2.bytes;
  911 + for (int i=2; i<records.size(); i++) {
  912 + records[i].position = position;
  913 + records[i].bytes = recordBytes(byteArray,records[i].type,position);
861 914  
862   - // Win at everything
  915 + parseRecord(byteArray, records[i]);
  916 + if (records[i].type == 10) frontalIdxs.append(i);
  917 + position += records[i].bytes;
  918 + }
  919 +
  920 + if (!frontalIdxs.isEmpty()) {
  921 + // We use the first type 10 record
  922 + // Its last field contains the mugshot data (and it will only have one subfield)
  923 + m = imdecode(Mat(3, records[frontalIdxs.first()].fields.last().data.first().size(), CV_8UC3, records[frontalIdxs.first()].fields.last().data.first().data()), CV_LOAD_IMAGE_COLOR);
  924 + if (!m.data) qWarning("ebtsFormat::read failed to decode image data.");
  925 + return Template(m);
  926 + } else {
  927 + qWarning("ebtsFormat::cannot find image data within file.");
  928 + return Template();
  929 + }
863 930  
864 931 // Demographics
  932 + /*
865 933 {
866 934 int recordOneSize = recordBytes(byteArray,1);
867 935 qDebug() << recordBytes(byteArray,1);
... ... @@ -906,9 +974,7 @@ class ebtsFormat : public Format
906 974 int age = current.year() - dob.year();
907 975 if (current.month() < dob.month()) age--;
908 976 t.file.set("Age", age);
909   - }
910   -
911   - return t;
  977 + }*/
912 978 }
913 979  
914 980 void write(const Template &t) const
... ...