#include #include #include #include #include "openbr/core/opencvutils.h" #include using namespace cv; namespace br { struct Miner { Template src; Template scaledSrc; Size windowSize; Point offset, point; float scale, scaleFactor, stepFactor; Miner(const Template &t, const Size &windowSize, const Point &offset) : src(t), windowSize(windowSize), offset(offset), point(offset) { scale = 1.0F; scaleFactor = 1.4142135623730950488016887242097F; stepFactor = 0.5F; scale = max(((float)windowSize.width + point.x) / ((float)src.m().cols), ((float)windowSize.height + point.y) / ((float)src.m().rows)); Size size((int)(scale*src.m().cols + 0.5F), (int)(scale*src.m().rows + 0.5F)); scaledSrc = resize(src, size); } Template resize(const Template &src, const Size &size) { Template dst(src.file); for (int i=0; i stages; TemplateList posImages, negImages; TemplateList posSamples, negSamples; QList negIndices, posIndices; int negIndex, posIndex, samplingRound; QMutex samplingMutex, miningMutex; void init() { negIndex = posIndex = samplingRound = 0; } bool getPositive(Template &img) { if (posIndex >= posImages.size()) return false; img = posImages[posIndices[posIndex++]]; return true; } Template getNegative(Point &offset) { Template negative; const Size size = windowSize(); // Grab negative from list int count = negImages.size(); for (int i = 0; i < count; i++) { negative = negImages[negIndices[negIndex++]]; samplingRound += negIndex / count; samplingRound = samplingRound % (size.width * size.height); negIndex %= count; offset.x = qMin( (int)samplingRound % size.width, negative.m().cols - size.width); offset.y = qMin( (int)samplingRound / size.width, negative.m().rows - size.height); if (!negative.m().empty() && negative.m().type() == CV_8U && offset.x >= 0 && offset.y >= 0) break; } return negative; } uint64 mine() { uint64 passedNegatives = 0; forever { Template negative; Point offset; QMutexLocker samplingLocker(&samplingMutex); negative = getNegative(offset); samplingLocker.unlock(); Miner miner(negative, windowSize(), offset); forever { bool newImg; Template sample = miner.mine(&newImg); if (!newImg) { if (negSamples.size() >= numNegs) return passedNegatives; float confidence; if (classify(sample, true, &confidence) != 0) { QMutexLocker miningLocker(&miningMutex); if (negSamples.size() >= numNegs) return passedNegatives; negSamples.append(sample); printf("Negative samples: %d\r", negSamples.size()); } passedNegatives++; } else break; } } } void train(const TemplateList &data) { foreach (const Template &t, data) t.file.get("Label") == 1.0f ? posImages.append(t) : negImages.append(t); qDebug() << "Total images:" << data.size() << "\nTotal positive images:" << posImages.size() << "\nTotal negative images:" << negImages.size(); posIndices = Common::RandSample(posImages.size(), posImages.size(), true); negIndices = Common::RandSample(negImages.size(), negImages.size(), true); stages.reserve(numStages); for (int i = 0; i < numStages; i++) { qDebug() << "===== TRAINING" << i << "stage ====="; qDebug() << "train(posSamples + negSamples); qDebug() << "END>"; } } float classify(const Template &src, bool process, float *confidence) const { float stageConf = 0.0f; const int stopStage = maxStage == -1 ? numStages : maxStage; int stageIndex = 0; foreach (const Classifier *stage, stages) { if (stageIndex++ == stopStage) break; float result = stage->classify(src, process, &stageConf); if (confidence) *confidence += stageConf; if (result == 0.0f) return 0.0f; } return 1.0f; } int numFeatures() const { return stages.first()->numFeatures(); } Template preprocess(const Template &src) const { return stages.first()->preprocess(src); } Size windowSize(int *dx = NULL, int *dy = NULL) const { return stages.first()->windowSize(dx, dy); } void load(QDataStream &stream) { int numStages; stream >> numStages; for (int i = 0; i < numStages; i++) { Classifier *nextStage = Classifier::make(stageDescription, NULL); nextStage->load(stream); stages.append(nextStage); } } void store(QDataStream &stream) const { stream << stages.size(); foreach (const Classifier *stage, stages) stage->store(stream); } private: float getSamples() { posSamples.clear(); posSamples.reserve(numPos); negSamples.clear(); negSamples.reserve(numNegs); posIndex = 0; float confidence; while (posSamples.size() < numPos) { Template pos; if (!getPositive(pos)) qFatal("Cannot get another positive sample!"); if (classify(pos, true, &confidence) > 0.0f) { printf("POS current samples: %d\r", posSamples.size()); posSamples.append(pos); } } qDebug() << "POS count : consumed " << posSamples.size() << ":" << posIndex; QFutureSynchronizer futures; for (int i=0; i > results = futures.futures(); for (int i=0; i