Commit 2f33ea8cce30ccffa747f44c1e71b6f4e592f453
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,22 +780,26 @@ BR_REGISTER(Format, scoresFormat) | ||
| 780 | class ebtsFormat : public Format | 780 | class ebtsFormat : public Format |
| 781 | { | 781 | { |
| 782 | Q_OBJECT | 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 | bool ok; | 799 | bool ok; |
| 796 | - int size; | 800 | + quint32 size; |
| 797 | 801 | ||
| 798 | - if (fieldNumber == 4 || fieldNumber == 7) { | 802 | + if (recordType == 4 || recordType == 7) { |
| 799 | // read first four bytes | 803 | // read first four bytes |
| 800 | ok = true; | 804 | ok = true; |
| 801 | size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData()); | 805 | size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData()); |
| @@ -807,16 +811,47 @@ class ebtsFormat : public Format | @@ -807,16 +811,47 @@ class ebtsFormat : public Format | ||
| 807 | return ok ? size : -1; | 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 | Template read() const | 857 | Template read() const |
| @@ -828,40 +863,73 @@ class ebtsFormat : public Format | @@ -828,40 +863,73 @@ class ebtsFormat : public Format | ||
| 828 | 863 | ||
| 829 | Mat m; | 864 | Mat m; |
| 830 | 865 | ||
| 866 | + QList<Record> records; | ||
| 867 | + | ||
| 831 | // Read the type one record (every EBTS file will have one of these) | 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 | // Demographics | 931 | // Demographics |
| 932 | + /* | ||
| 865 | { | 933 | { |
| 866 | int recordOneSize = recordBytes(byteArray,1); | 934 | int recordOneSize = recordBytes(byteArray,1); |
| 867 | qDebug() << recordBytes(byteArray,1); | 935 | qDebug() << recordBytes(byteArray,1); |
| @@ -906,9 +974,7 @@ class ebtsFormat : public Format | @@ -906,9 +974,7 @@ class ebtsFormat : public Format | ||
| 906 | int age = current.year() - dob.year(); | 974 | int age = current.year() - dob.year(); |
| 907 | if (current.month() < dob.month()) age--; | 975 | if (current.month() < dob.month()) age--; |
| 908 | t.file.set("Age", age); | 976 | t.file.set("Age", age); |
| 909 | - } | ||
| 910 | - | ||
| 911 | - return t; | 977 | + }*/ |
| 912 | } | 978 | } |
| 913 | 979 | ||
| 914 | void write(const Template &t) const | 980 | void write(const Template &t) const |