Commit decda7bc5277e839d1bcf3e78754f2400878c969
1 parent
d2de26db
Revert "Merge pull request #320 from biometrics/block_compression"
This reverts commit cb35ce836903f6baa19cf577932e6d2b92f3fedb, reversing changes made to f2f88b8c72d0c86d66232c2cb26a39ab40bca4f3.
Showing
10 changed files
with
55 additions
and
269 deletions
openbr/core/common.cpp
| ... | ... | @@ -16,32 +16,21 @@ |
| 16 | 16 | |
| 17 | 17 | #include "common.h" |
| 18 | 18 | #include <QMutex> |
| 19 | -#include <RandomLib/Random.hpp> | |
| 20 | 19 | |
| 21 | 20 | using namespace std; |
| 22 | 21 | |
| 23 | -static RandomLib::Random g_rand; | |
| 24 | -static QMutex rngLock; | |
| 25 | - | |
| 26 | 22 | /**** GLOBAL ****/ |
| 27 | 23 | void Common::seedRNG() { |
| 28 | - QMutexLocker lock(&rngLock); | |
| 24 | + static QMutex seedControl; | |
| 25 | + QMutexLocker lock(&seedControl); | |
| 29 | 26 | |
| 30 | 27 | static bool seeded = false; |
| 31 | 28 | if (!seeded) { |
| 32 | 29 | srand(0); // We seed with 0 instead of time(NULL) to have reproducible randomness |
| 33 | 30 | seeded = true; |
| 34 | - g_rand.Reseed(0); | |
| 35 | 31 | } |
| 36 | 32 | } |
| 37 | 33 | |
| 38 | -double Common::randN() | |
| 39 | -{ | |
| 40 | - QMutexLocker lock(&rngLock); | |
| 41 | - | |
| 42 | - return g_rand.FloatN(); | |
| 43 | -} | |
| 44 | - | |
| 45 | 34 | QList<int> Common::RandSample(int n, int max, int min, bool unique) |
| 46 | 35 | { |
| 47 | 36 | QList<int> samples; samples.reserve(n); | ... | ... |
openbr/core/common.h
| ... | ... | @@ -220,9 +220,6 @@ double KernelDensityEstimation(const V<T> &vals, double x, double h) |
| 220 | 220 | return y / (vals.size() * h); |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | -// Return a random number, uniformly distributed over 0,1 | |
| 224 | -double randN(); | |
| 225 | - | |
| 226 | 223 | /*! |
| 227 | 224 | * \brief Returns a vector of n integers sampled in the range <min, max]. |
| 228 | 225 | * |
| ... | ... | @@ -239,14 +236,19 @@ QList<int> RandSample(int n, const QSet<int> &values, bool unique = false); |
| 239 | 236 | template <typename T> |
| 240 | 237 | QList<int> RandSample(int n, const QList<T> &weights, bool unique = false) |
| 241 | 238 | { |
| 239 | + static bool seeded = false; | |
| 240 | + if (!seeded) { | |
| 241 | + srand(time(NULL)); | |
| 242 | + seeded = true; | |
| 243 | + } | |
| 244 | + | |
| 242 | 245 | QList<T> cdf = CumSum(weights); |
| 243 | 246 | for (int i=0; i<cdf.size(); i++) // Normalize cdf |
| 244 | 247 | cdf[i] = cdf[i] / cdf.last(); |
| 245 | 248 | |
| 246 | 249 | QList<int> samples; samples.reserve(n); |
| 247 | 250 | while (samples.size() < n) { |
| 248 | - T r = randN(); | |
| 249 | - | |
| 251 | + T r = (T)rand() / (T)RAND_MAX; | |
| 250 | 252 | for (int j=0; j<weights.size(); j++) { |
| 251 | 253 | if ((r >= cdf[j]) && (r <= cdf[j+1])) { |
| 252 | 254 | if (!unique || !samples.contains(j)) | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -110,11 +110,9 @@ struct AlgorithmCore |
| 110 | 110 | |
| 111 | 111 | void store(const QString &model) const |
| 112 | 112 | { |
| 113 | - QtUtils::BlockCompression compressedWrite; | |
| 114 | - QFile outFile(model); | |
| 115 | - compressedWrite.setBasis(&outFile); | |
| 116 | - QDataStream out(&compressedWrite); | |
| 117 | - compressedWrite.open(QFile::WriteOnly); | |
| 113 | + // Create stream | |
| 114 | + QByteArray data; | |
| 115 | + QDataStream out(&data, QFile::WriteOnly); | |
| 118 | 116 | |
| 119 | 117 | // Serialize algorithm to stream |
| 120 | 118 | transform->serialize(out); |
| ... | ... | @@ -133,16 +131,18 @@ struct AlgorithmCore |
| 133 | 131 | if (mode == TransformCompare) |
| 134 | 132 | comparison->serialize(out); |
| 135 | 133 | |
| 136 | - compressedWrite.close(); | |
| 134 | + // Compress and save to file | |
| 135 | + QtUtils::writeFile(model, data, -1); | |
| 137 | 136 | } |
| 138 | 137 | |
| 139 | 138 | void load(const QString &model) |
| 140 | 139 | { |
| 141 | - QtUtils::BlockCompression compressedRead; | |
| 142 | - QFile inFile(model); | |
| 143 | - compressedRead.setBasis(&inFile); | |
| 144 | - QDataStream in(&compressedRead); | |
| 145 | - compressedRead.open(QFile::ReadOnly); | |
| 140 | + // Load from file and decompress | |
| 141 | + QByteArray data; | |
| 142 | + QtUtils::readFile(model, data, true); | |
| 143 | + | |
| 144 | + // Create stream | |
| 145 | + QDataStream in(&data, QFile::ReadOnly); | |
| 146 | 146 | |
| 147 | 147 | // Load algorithm |
| 148 | 148 | transform = QSharedPointer<Transform>(Transform::deserialize(in)); | ... | ... |
openbr/core/qtutils.cpp
| ... | ... | @@ -500,131 +500,6 @@ QString getAbsolutePath(const QString &filename) |
| 500 | 500 | return QFileInfo(filename).absoluteFilePath(); |
| 501 | 501 | } |
| 502 | 502 | |
| 503 | -BlockCompression::BlockCompression(QIODevice *_basis) | |
| 504 | -{ | |
| 505 | - blockSize = 100000000; | |
| 506 | - setBasis(_basis); | |
| 507 | -} | |
| 508 | - | |
| 509 | -BlockCompression::BlockCompression() { blockSize = 100000000; }; | |
| 510 | - | |
| 511 | - | |
| 512 | -bool BlockCompression::open(QIODevice::OpenMode mode) | |
| 513 | -{ | |
| 514 | - this->setOpenMode(mode); | |
| 515 | - bool res = basis->open(mode); | |
| 516 | - | |
| 517 | - if (!res) | |
| 518 | - return false; | |
| 519 | - | |
| 520 | - blockReader.setDevice(basis); | |
| 521 | - blockWriter.setDevice(basis); | |
| 522 | - | |
| 523 | - if (mode & QIODevice::WriteOnly) { | |
| 524 | - precompressedBlockWriter = new QBuffer; | |
| 525 | - precompressedBlockWriter->open(QIODevice::ReadWrite); | |
| 526 | - } | |
| 527 | - else if (mode & QIODevice::ReadOnly) { | |
| 528 | - QByteArray compressedBlock; | |
| 529 | - blockReader >> compressedBlock; | |
| 530 | - | |
| 531 | - decompressedBlock = qUncompress(compressedBlock); | |
| 532 | - decompressedBlockReader.setBuffer(&decompressedBlock); | |
| 533 | - decompressedBlockReader.open(QIODevice::ReadOnly); | |
| 534 | - } | |
| 535 | - | |
| 536 | - return true; | |
| 537 | -} | |
| 538 | - | |
| 539 | -void BlockCompression::close() | |
| 540 | -{ | |
| 541 | - // flush output buffer | |
| 542 | - if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter) { | |
| 543 | - QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1); | |
| 544 | - blockWriter << compressedBlock; | |
| 545 | - } | |
| 546 | - basis->close(); | |
| 547 | -} | |
| 548 | - | |
| 549 | -void BlockCompression::setBasis(QIODevice *_basis) | |
| 550 | -{ | |
| 551 | - basis = _basis; | |
| 552 | - blockReader.setDevice(basis); | |
| 553 | - blockWriter.setDevice(basis); | |
| 554 | -} | |
| 555 | - | |
| 556 | -// read from current decompressed block, if out of space, read and decompress another | |
| 557 | -// block from basis | |
| 558 | -qint64 BlockCompression::readData(char *data, qint64 remaining) | |
| 559 | -{ | |
| 560 | - qint64 read = 0; | |
| 561 | - while (remaining > 0) { | |
| 562 | - qint64 single_read = decompressedBlockReader.read(data, remaining); | |
| 563 | - if (single_read == -1) | |
| 564 | - qFatal("miss read"); | |
| 565 | - | |
| 566 | - remaining -= single_read; | |
| 567 | - read += single_read; | |
| 568 | - data += single_read; | |
| 569 | - | |
| 570 | - // need a new block | |
| 571 | - if (remaining > 0) { | |
| 572 | - QByteArray compressedBlock; | |
| 573 | - blockReader >> compressedBlock; | |
| 574 | - if (compressedBlock.size() == 0) { | |
| 575 | - return read; | |
| 576 | - } | |
| 577 | - decompressedBlock = qUncompress(compressedBlock); | |
| 578 | - | |
| 579 | - decompressedBlockReader.close(); | |
| 580 | - decompressedBlockReader.setBuffer(&decompressedBlock); | |
| 581 | - decompressedBlockReader.open(QIODevice::ReadOnly); | |
| 582 | - } | |
| 583 | - } | |
| 584 | - return blockReader.atEnd() && !basis->isReadable() ? -1 : read; | |
| 585 | -} | |
| 586 | - | |
| 587 | -bool BlockCompression::isSequential() const | |
| 588 | -{ | |
| 589 | - return true; | |
| 590 | -} | |
| 591 | - | |
| 592 | -qint64 BlockCompression::writeData(const char *data, qint64 remaining) | |
| 593 | -{ | |
| 594 | - qint64 written = 0; | |
| 595 | - | |
| 596 | - while (remaining > 0) { | |
| 597 | - // how much more can be put in this buffer? | |
| 598 | - qint64 capacity = blockSize - precompressedBlockWriter->pos(); | |
| 599 | - | |
| 600 | - // don't try to write beyond capacity | |
| 601 | - qint64 write_size = qMin(capacity, remaining); | |
| 602 | - | |
| 603 | - qint64 singleWrite = precompressedBlockWriter->write(data, write_size); | |
| 604 | - // ignore the error case here, we consdier basis's failure mode the real | |
| 605 | - // end case | |
| 606 | - if (singleWrite == -1) | |
| 607 | - singleWrite = 0; | |
| 608 | - | |
| 609 | - remaining -= singleWrite; | |
| 610 | - data += singleWrite; | |
| 611 | - written += singleWrite; | |
| 612 | - | |
| 613 | - if (remaining > 0) { | |
| 614 | - QByteArray compressedBlock = qCompress(precompressedBlockWriter->buffer(), -1); | |
| 615 | - | |
| 616 | - if (compressedBlock.size() != 0) | |
| 617 | - blockWriter << compressedBlock; | |
| 618 | - | |
| 619 | - delete precompressedBlockWriter; | |
| 620 | - precompressedBlockWriter = new QBuffer; | |
| 621 | - precompressedBlockWriter->open(QIODevice::ReadWrite); | |
| 622 | - } | |
| 623 | - } | |
| 624 | - return basis->isWritable() ? written : -1; | |
| 625 | -} | |
| 626 | - | |
| 627 | - | |
| 628 | 503 | |
| 629 | 504 | } // namespace QtUtils |
| 630 | 505 | ... | ... |
openbr/core/qtutils.h
| ... | ... | @@ -17,7 +17,6 @@ |
| 17 | 17 | #ifndef QTUTILS_QTUTILS_H |
| 18 | 18 | #define QTUTILS_QTUTILS_H |
| 19 | 19 | |
| 20 | -#include <QBuffer> | |
| 21 | 20 | #include <QByteArray> |
| 22 | 21 | #include <QDir> |
| 23 | 22 | #include <QFile> |
| ... | ... | @@ -94,38 +93,6 @@ namespace QtUtils |
| 94 | 93 | |
| 95 | 94 | /**** Rect Utilities ****/ |
| 96 | 95 | float overlap(const QRectF &r, const QRectF &s); |
| 97 | - | |
| 98 | - | |
| 99 | - class BlockCompression : public QIODevice | |
| 100 | - { | |
| 101 | - public: | |
| 102 | - BlockCompression(QIODevice *_basis); | |
| 103 | - BlockCompression(); | |
| 104 | - int blockSize; | |
| 105 | - QIODevice *basis; | |
| 106 | - | |
| 107 | - bool open(QIODevice::OpenMode mode); | |
| 108 | - | |
| 109 | - void close(); | |
| 110 | - | |
| 111 | - void setBasis(QIODevice *_basis); | |
| 112 | - | |
| 113 | - QDataStream blockReader; | |
| 114 | - QByteArray decompressedBlock; | |
| 115 | - QBuffer decompressedBlockReader; | |
| 116 | - | |
| 117 | - // read from current decompressed block, if out of space, read and decompress another | |
| 118 | - // block from basis | |
| 119 | - qint64 readData(char *data, qint64 remaining); | |
| 120 | - | |
| 121 | - bool isSequential() const; | |
| 122 | - | |
| 123 | - // write to a QByteArray, when max block sized is reached, compress and write | |
| 124 | - // it to basis | |
| 125 | - QBuffer * precompressedBlockWriter; | |
| 126 | - QDataStream blockWriter; | |
| 127 | - qint64 writeData(const char *data, qint64 remaining); | |
| 128 | - }; | |
| 129 | 96 | } |
| 130 | 97 | |
| 131 | 98 | #endif // QTUTILS_QTUTILS_H | ... | ... |
openbr/plugins/algorithms.cpp
| ... | ... | @@ -31,15 +31,15 @@ class AlgorithmsInitializer : public Initializer |
| 31 | 31 | void initialize() const |
| 32 | 32 | { |
| 33 | 33 | // Face |
| 34 | - Globals->abbreviations.insert("FaceRecognition", "FaceDetection+FaceRecognitionRegistration+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>+SetMetadata(AlgorithmID,-1):Unit(ByteL1)"); | |
| 35 | - Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+FaceClassificationRegistration+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard"); | |
| 36 | - Globals->abbreviations.insert("AgeRegression", "FaceDetection+Expand+FaceClassificationRegistration+Expand+<FaceClassificationExtraction>+<AgeRegressor>+Discard"); | |
| 34 | + Globals->abbreviations.insert("FaceRecognition", "FaceDetection+Expand+<FaceRecognitionRegistration>+Expand+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>+SetMetadata(AlgorithmID,-1):MatchProbability(ByteL1)"); | |
| 35 | + Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard"); | |
| 36 | + Globals->abbreviations.insert("AgeRegression", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<AgeRegressor>+Discard"); | |
| 37 | 37 | Globals->abbreviations.insert("FaceQuality", "Open+Expand+Cascade(FrontalFace)+ASEFEyes+Affine(64,64,0.25,0.35)+ImageQuality+Cvt(Gray)+DFFS+Discard"); |
| 38 | 38 | Globals->abbreviations.insert("MedianFace", "Open+Expand+Cascade(FrontalFace)+ASEFEyes+Affine(256,256,0.37,0.45)+Center(Median)"); |
| 39 | 39 | Globals->abbreviations.insert("BlurredFaceDetection", "Open+LimitSize(1024)+SkinMask/(Cvt(Gray)+GradientMask)+And+Morph(Erode,16)+LargestConvexArea"); |
| 40 | 40 | Globals->abbreviations.insert("DrawFaceDetection", "Open+Cascade(FrontalFace)+Expand+ASEFEyes+Draw(inPlace=true)"); |
| 41 | 41 | Globals->abbreviations.insert("ShowFaceDetection", "DrawFaceDetection+Contract+First+Show+Discard"); |
| 42 | - Globals->abbreviations.insert("DownloadFaceRecognition", "Download+Open+ROI+Cvt(Gray)+Cascade(FrontalFace)+FaceRecognitionRegistration+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>+SetMetadata(AlgorithmID,-1):Unit(ByteL1)"); | |
| 42 | + Globals->abbreviations.insert("DownloadFaceRecognition", "Download+Open+ROI+Expand+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceRecognitionRegistration>+Expand+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>+SetMetadata(AlgorithmID,-1):MatchProbability(ByteL1)"); | |
| 43 | 43 | Globals->abbreviations.insert("OpenBR", "FaceRecognition"); |
| 44 | 44 | Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); |
| 45 | 45 | Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); |
| ... | ... | @@ -50,7 +50,7 @@ class AlgorithmsInitializer : public Initializer |
| 50 | 50 | // Video |
| 51 | 51 | Globals->abbreviations.insert("DisplayVideo", "FPSLimit(30)+Show(false,[FrameNumber])+Discard"); |
| 52 | 52 | Globals->abbreviations.insert("PerFrameDetection", "SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard"); |
| 53 | - Globals->abbreviations.insert("AgeGenderDemo", "SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+FaceClassificationRegistration+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard"); | |
| 53 | + Globals->abbreviations.insert("AgeGenderDemo", "SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard"); | |
| 54 | 54 | Globals->abbreviations.insert("ShowOpticalFlowField", "SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard"); |
| 55 | 55 | Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard"); |
| 56 | 56 | Globals->abbreviations.insert("ShowMotionSegmentation", "DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard"); |
| ... | ... | @@ -92,11 +92,11 @@ class AlgorithmsInitializer : public Initializer |
| 92 | 92 | Globals->abbreviations.insert("DenseHOG", "Gradient+RectRegions(8,8,6,6)+Bin(0,360,8)+Hist(8)"); |
| 93 | 93 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); |
| 94 | 94 | Globals->abbreviations.insert("DenseSIFT2", "(Grid(5,5)+SIFTDescriptor(12)+ByRow)"); |
| 95 | - Globals->abbreviations.insert("FaceRecognitionRegistration", "ASEFEyes+Affine(88,88,0.25,0.35)"); | |
| 95 | + Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); | |
| 96 | 96 | Globals->abbreviations.insert("FaceRecognitionExtraction", "(Mask+DenseSIFT/DenseLBP+DownsampleTraining(PCA(0.95),instances=1)+Normalize(L2)+Cat)"); |
| 97 | 97 | Globals->abbreviations.insert("FaceRecognitionEmbedding", "(Dup(12)+RndSubspace(0.05,1)+DownsampleTraining(LDA(0.98),instances=-2)+Cat+DownsampleTraining(PCA(768),instances=1))"); |
| 98 | 98 | Globals->abbreviations.insert("FaceRecognitionQuantization", "(Normalize(L1)+Quantize)"); |
| 99 | - Globals->abbreviations.insert("FaceClassificationRegistration", "ASEFEyes+Affine(56,72,0.33,0.45)"); | |
| 99 | + Globals->abbreviations.insert("FaceClassificationRegistration", "(ASEFEyes+Affine(56,72,0.33,0.45)+FTE(DFFS))"); | |
| 100 | 100 | Globals->abbreviations.insert("FaceClassificationExtraction", "((Grid(7,7)+SIFTDescriptor(8)+ByRow)/DenseLBP+DownsampleTraining(PCA(0.95),instances=-1, inputVariable=Gender)+Cat)"); |
| 101 | 101 | Globals->abbreviations.insert("AgeRegressor", "DownsampleTraining(Center(Range),instances=-1, inputVariable=Age)+DownsampleTraining(SVM(RBF,EPS_SVR,inputVariable=Age),instances=100, inputVariable=Age)"); |
| 102 | 102 | Globals->abbreviations.insert("GenderClassifier", "DownsampleTraining(Center(Range),instances=-1, inputVariable=Gender)+DownsampleTraining(SVM(RBF,C_SVC,inputVariable=Gender),instances=4000, inputVariable=Gender)"); | ... | ... |
openbr/plugins/cascade.cpp
| ... | ... | @@ -252,8 +252,6 @@ class CascadeTransform : public MetaTransform |
| 252 | 252 | void init() |
| 253 | 253 | { |
| 254 | 254 | cascadeResource.setResourceMaker(new CascadeResourceMaker(model)); |
| 255 | - if (model == "Ear" || model == "Eye" || model == "FrontalFace" || model == "ProfileFace") | |
| 256 | - this->trainable = false; | |
| 257 | 255 | } |
| 258 | 256 | |
| 259 | 257 | // Train transform | ... | ... |
openbr/plugins/meta.cpp
| ... | ... | @@ -17,8 +17,6 @@ |
| 17 | 17 | #include <QFutureSynchronizer> |
| 18 | 18 | #include <QRegularExpression> |
| 19 | 19 | #include <QtConcurrentRun> |
| 20 | -#include <qbuffer.h> | |
| 21 | - | |
| 22 | 20 | #include "openbr_internal.h" |
| 23 | 21 | #include "openbr/core/common.h" |
| 24 | 22 | #include "openbr/core/opencvutils.h" |
| ... | ... | @@ -96,15 +94,17 @@ class PipeTransform : public CompositeTransform |
| 96 | 94 | |
| 97 | 95 | int i = 0; |
| 98 | 96 | while (i < transforms.size()) { |
| 97 | + fprintf(stderr, "\n%s", qPrintable(transforms[i]->objectName())); | |
| 98 | + | |
| 99 | 99 | // Conditional statement covers likely case that first transform is untrainable |
| 100 | 100 | if (transforms[i]->trainable) { |
| 101 | - qDebug() << "Training " << transforms[i]->description() << "\n..."; | |
| 101 | + fprintf(stderr, " training..."); | |
| 102 | 102 | transforms[i]->train(dataLines); |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | 105 | // if the transform is time varying, we can't project it in parallel |
| 106 | 106 | if (transforms[i]->timeVarying()) { |
| 107 | - qDebug() << "Projecting " << transforms[i]->description() << "\n..."; | |
| 107 | + fprintf(stderr, "\n%s projecting...", qPrintable(transforms[i]->objectName())); | |
| 108 | 108 | for (int j=0; j < dataLines.size();j++) { |
| 109 | 109 | TemplateList junk; |
| 110 | 110 | splitFTEs(dataLines[j], junk); |
| ... | ... | @@ -130,16 +130,7 @@ class PipeTransform : public CompositeTransform |
| 130 | 130 | !transforms[nextTrainableTransform]->timeVarying()) |
| 131 | 131 | nextTrainableTransform++; |
| 132 | 132 | |
| 133 | - // No more trainable transforms? Don't need any more projects then | |
| 134 | - if (nextTrainableTransform == transforms.size()) | |
| 135 | - break; | |
| 136 | - | |
| 137 | - fprintf(stderr, "Projecting %s", qPrintable(transforms[i]->description())); | |
| 138 | - for (int j=i+1; j < nextTrainableTransform; j++) | |
| 139 | - fprintf(stderr,"+%s", qPrintable(transforms[j]->description())); | |
| 140 | - fprintf(stderr, "\n...\n"); | |
| 141 | - fflush(stderr); | |
| 142 | - | |
| 133 | + fprintf(stderr, " projecting..."); | |
| 143 | 134 | QFutureSynchronizer<void> futures; |
| 144 | 135 | for (int j=0; j < dataLines.size(); j++) |
| 145 | 136 | futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &dataLines[j], i, nextTrainableTransform)); |
| ... | ... | @@ -519,6 +510,7 @@ class LoadStoreTransform : public MetaTransform |
| 519 | 510 | |
| 520 | 511 | public: |
| 521 | 512 | Transform *transform; |
| 513 | + QString baseName; | |
| 522 | 514 | |
| 523 | 515 | LoadStoreTransform() : transform(NULL) {} |
| 524 | 516 | |
| ... | ... | @@ -548,8 +540,8 @@ private: |
| 548 | 540 | void init() |
| 549 | 541 | { |
| 550 | 542 | if (transform != NULL) return; |
| 551 | - if (fileName.isEmpty()) fileName = QRegExp("^[_a-zA-Z0-9]+$").exactMatch(transformString) ? transformString : QtUtils::shortTextHash(transformString); | |
| 552 | - | |
| 543 | + if (fileName.isEmpty()) baseName = QRegExp("^[_a-zA-Z0-9]+$").exactMatch(transformString) ? transformString : QtUtils::shortTextHash(transformString); | |
| 544 | + else baseName = fileName; | |
| 553 | 545 | if (!tryLoad()) |
| 554 | 546 | transform = make(transformString); |
| 555 | 547 | else |
| ... | ... | @@ -561,28 +553,19 @@ private: |
| 561 | 553 | return transform->timeVarying(); |
| 562 | 554 | } |
| 563 | 555 | |
| 564 | - void train(const QList<TemplateList> &data) | |
| 556 | + void train(const TemplateList &data) | |
| 565 | 557 | { |
| 566 | 558 | if (QFileInfo(getFileName()).exists()) |
| 567 | 559 | return; |
| 568 | 560 | |
| 569 | 561 | transform->train(data); |
| 570 | 562 | |
| 571 | - qDebug("Storing %s", qPrintable(fileName)); | |
| 572 | - QtUtils::BlockCompression compressedOut; | |
| 573 | - QFile fout(fileName); | |
| 574 | - QtUtils::touchDir(fout); | |
| 575 | - compressedOut.setBasis(&fout); | |
| 576 | - | |
| 577 | - QDataStream stream(&compressedOut); | |
| 578 | - QString desc = transform->description(); | |
| 579 | - | |
| 580 | - if (!compressedOut.open(QFile::WriteOnly)) | |
| 581 | - qFatal("Failed to open %s for writing.", qPrintable(file)); | |
| 582 | - | |
| 583 | - stream << desc; | |
| 563 | + qDebug("Storing %s", qPrintable(baseName)); | |
| 564 | + QByteArray byteArray; | |
| 565 | + QDataStream stream(&byteArray, QFile::WriteOnly); | |
| 566 | + stream << transform->description(); | |
| 584 | 567 | transform->store(stream); |
| 585 | - compressedOut.close(); | |
| 568 | + QtUtils::writeFile(baseName, byteArray, -1); | |
| 586 | 569 | } |
| 587 | 570 | |
| 588 | 571 | void project(const Template &src, Template &dst) const |
| ... | ... | @@ -612,8 +595,8 @@ private: |
| 612 | 595 | |
| 613 | 596 | QString getFileName() const |
| 614 | 597 | { |
| 615 | - if (QFileInfo(fileName).exists()) return fileName; | |
| 616 | - const QString file = Globals->sdkPath + "/share/openbr/models/transforms/" + fileName; | |
| 598 | + if (QFileInfo(baseName).exists()) return baseName; | |
| 599 | + const QString file = Globals->sdkPath + "/share/openbr/models/transforms/" + baseName; | |
| 617 | 600 | return QFileInfo(file).exists() ? file : QString(); |
| 618 | 601 | } |
| 619 | 602 | |
| ... | ... | @@ -623,19 +606,12 @@ private: |
| 623 | 606 | if (file.isEmpty()) return false; |
| 624 | 607 | |
| 625 | 608 | qDebug("Loading %s", qPrintable(file)); |
| 626 | - QFile fin(file); | |
| 627 | - QtUtils::BlockCompression reader(&fin); | |
| 628 | - if (!reader.open(QIODevice::ReadOnly)) { | |
| 629 | - if (QFileInfo(file).exists()) qFatal("Unable to open %s for reading. Check file permissions.", qPrintable(file)); | |
| 630 | - else qFatal("Unable to open %s for reading. File does not exist.", qPrintable(file)); | |
| 631 | - } | |
| 632 | - | |
| 633 | - QDataStream stream(&reader); | |
| 609 | + QByteArray data; | |
| 610 | + QtUtils::readFile(file, data, true); | |
| 611 | + QDataStream stream(&data, QFile::ReadOnly); | |
| 634 | 612 | stream >> transformString; |
| 635 | - | |
| 636 | 613 | transform = Transform::make(transformString); |
| 637 | 614 | transform->load(stream); |
| 638 | - | |
| 639 | 615 | return true; |
| 640 | 616 | } |
| 641 | 617 | }; | ... | ... |
openbr/plugins/quality.cpp
| ... | ... | @@ -77,12 +77,6 @@ class ImpostorUniquenessMeasureTransform : public Transform |
| 77 | 77 | |
| 78 | 78 | BR_REGISTER(Transform, ImpostorUniquenessMeasureTransform) |
| 79 | 79 | |
| 80 | - | |
| 81 | -float KDEPointer(const QList<float> *scores, double x, double h) | |
| 82 | -{ | |
| 83 | - return Common::KernelDensityEstimation(*scores, x, h); | |
| 84 | -} | |
| 85 | - | |
| 86 | 80 | /* Kernel Density Estimator */ |
| 87 | 81 | struct KDE |
| 88 | 82 | { |
| ... | ... | @@ -91,35 +85,20 @@ struct KDE |
| 91 | 85 | QList<float> bins; |
| 92 | 86 | |
| 93 | 87 | KDE() : min(0), max(1), mean(0), stddev(1) {} |
| 94 | - | |
| 95 | - KDE(const QList<float> &scores, bool trainKDE) | |
| 88 | + KDE(const QList<float> &scores) | |
| 96 | 89 | { |
| 97 | 90 | Common::MinMax(scores, &min, &max); |
| 98 | 91 | Common::MeanStdDev(scores, &mean, &stddev); |
| 99 | - | |
| 100 | - if (!trainKDE) | |
| 101 | - return; | |
| 102 | - | |
| 103 | 92 | double h = Common::KernelDensityBandwidth(scores); |
| 104 | 93 | const int size = 255; |
| 105 | 94 | bins.reserve(size); |
| 106 | - | |
| 107 | - QFutureSynchronizer<float> futures; | |
| 108 | - | |
| 109 | - for (int i=0; i < size; i++) | |
| 110 | - futures.addFuture(QtConcurrent::run(KDEPointer, &scores, min + (max-min)*i/(size-1), h)); | |
| 111 | - futures.waitForFinished(); | |
| 112 | - | |
| 113 | - foreach(const QFuture<float> & future, futures.futures()) | |
| 114 | - bins.append(future.result()); | |
| 95 | + for (int i=0; i<size; i++) | |
| 96 | + bins.append(Common::KernelDensityEstimation(scores, min + (max-min)*i/(size-1), h)); | |
| 115 | 97 | } |
| 116 | 98 | |
| 117 | 99 | float operator()(float score, bool gaussian = true) const |
| 118 | 100 | { |
| 119 | 101 | if (gaussian) return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((score-mean)/stddev, 2)); |
| 120 | - if (bins.empty()) | |
| 121 | - return -std::numeric_limits<float>::max(); | |
| 122 | - | |
| 123 | 102 | if (score <= min) return bins.first(); |
| 124 | 103 | if (score >= max) return bins.last(); |
| 125 | 104 | const float x = (score-min)/(max-min)*bins.size(); |
| ... | ... | @@ -144,8 +123,8 @@ struct MP |
| 144 | 123 | { |
| 145 | 124 | KDE genuine, impostor; |
| 146 | 125 | MP() {} |
| 147 | - MP(const QList<float> &genuineScores, const QList<float> &impostorScores, bool trainKDE) | |
| 148 | - : genuine(genuineScores, trainKDE), impostor(impostorScores, trainKDE) {} | |
| 126 | + MP(const QList<float> &genuineScores, const QList<float> &impostorScores) | |
| 127 | + : genuine(genuineScores), impostor(impostorScores) {} | |
| 149 | 128 | float operator()(float score, bool gaussian = true) const |
| 150 | 129 | { |
| 151 | 130 | const float g = genuine(score, gaussian); |
| ... | ... | @@ -186,7 +165,7 @@ class MatchProbabilityDistance : public Distance |
| 186 | 165 | const QList<int> labels = src.indexProperty(inputVariable); |
| 187 | 166 | QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size()))); |
| 188 | 167 | distance->compare(src, src, matrixOutput.data()); |
| 189 | - | |
| 168 | + | |
| 190 | 169 | QList<float> genuineScores, impostorScores; |
| 191 | 170 | genuineScores.reserve(labels.size()); |
| 192 | 171 | impostorScores.reserve(labels.size()*labels.size()); |
| ... | ... | @@ -199,8 +178,8 @@ class MatchProbabilityDistance : public Distance |
| 199 | 178 | else impostorScores.append(score); |
| 200 | 179 | } |
| 201 | 180 | } |
| 202 | - | |
| 203 | - mp = MP(genuineScores, impostorScores, !gaussian); | |
| 181 | + | |
| 182 | + mp = MP(genuineScores, impostorScores); | |
| 204 | 183 | } |
| 205 | 184 | |
| 206 | 185 | float compare(const Template &target, const Template &query) const | ... | ... |