/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2012 The MITRE Corporation * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "core/distance_sse.h" using namespace cv; namespace br { /*! * \ingroup distances * \brief Standard distance metrics * \author Josh Klontz \cite jklontz */ class DistDistance : public Distance { Q_OBJECT Q_ENUMS(Metric) Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false) public: /*!< */ enum Metric { Correlation, ChiSquared, Intersection, Bhattacharyya, INF, L1, L2, Cosine }; private: BR_PROPERTY(Metric, metric, L2) float compare(const Template &a, const Template &b) const { if ((a.m().size != b.m().size) || (a.m().type() != b.m().type())) return -std::numeric_limits::max(); float result = std::numeric_limits::max(); switch (metric) { case Correlation: result = -compareHist(a, b, CV_COMP_CORREL); break; case ChiSquared: result = compareHist(a, b, CV_COMP_CHISQR); break; case Intersection: result = compareHist(a, b, CV_COMP_INTERSECT); break; case Bhattacharyya: result = compareHist(a, b, CV_COMP_BHATTACHARYYA); break; case INF: result = norm(a, b, NORM_INF); break; case L1: result = norm(a, b, NORM_L1); break; case L2: result = norm(a, b, NORM_L2); break; case Cosine: result = cosine(a, b); break; default: qFatal("Invalid metric"); } if (result != result) qFatal("NaN result."); return -log(result+1); } static float cosine(const Mat &a, const Mat &b) { float dot = 0; float magA = 0; float magB = 0; for (int row=0; row(row,col); const float query = b.at(row,col); dot += target * query; magA += target * target; magB += query * query; } } return dot / (sqrt(magA)*sqrt(magB)); } }; BR_REGISTER(Distance, DistDistance) /*! * \ingroup distances * \brief DistDistance wrapper. * \author Josh Klontz \cite jklontz */ class DefaultDistance : public Distance { Q_OBJECT Distance *distance; void init() { distance = Distance::make("Dist("+file.suffix()+")"); } float compare(const Template &a, const Template &b) const { return distance->compare(a, b); } }; BR_REGISTER(Distance, DefaultDistance) /*! * \ingroup distances * \brief Distances in series. * \author Josh Klontz \cite jklontz * * The templates are compared using each br::Distance in order. * If the result of the comparison with any given distance is -INT_MAX then this result is returned early. * Otherwise the returned result is the value of comparing the templates using the last br::Distance. */ class PipeDistance : public Distance { Q_OBJECT Q_PROPERTY(QList distances READ get_distances WRITE set_distances RESET reset_distances) BR_PROPERTY(QList, distances, QList()) void train(const TemplateList &data) { QList< QFuture > futures; foreach (br::Distance *distance, distances) if (Globals->parallelism) futures.append(QtConcurrent::run(distance, &Distance::train, data)); else distance->train(data); Globals->trackFutures(futures); } float compare(const Template &a, const Template &b) const { float result = -std::numeric_limits::max(); foreach (br::Distance *distance, distances) { result = distance->compare(a, b); if (result == -std::numeric_limits::max()) return result; } return result; } }; BR_REGISTER(Distance, PipeDistance) /*! * \ingroup distances * \brief Fast 8-bit L1 distance * \author Josh Klontz \cite jklontz */ class ByteL1Distance : public Distance { Q_OBJECT float compare(const Template &a, const Template &b) const { return l1(a.m().data, b.m().data, a.m().total()); } }; BR_REGISTER(Distance, ByteL1Distance) /*! * \ingroup distances * \brief Fast 4-bit L1 distance * \author Josh Klontz \cite jklontz */ class HalfByteL1Distance : public Distance { Q_OBJECT float compare(const Template &a, const Template &b) const { return packed_l1(a.m().data, b.m().data, a.m().total()); } }; BR_REGISTER(Distance, HalfByteL1Distance) /*! * \ingroup distances * \brief Returns \c true if the templates are identical, \c false otherwise. * \author Josh Klontz \cite jklontz */ class IdenticalDistance : public Distance { Q_OBJECT float compare(const Template &a, const Template &b) const { const Mat &am = a.m(); const Mat &bm = b.m(); const size_t size = am.total() * am.elemSize(); if (size != bm.total() * bm.elemSize()) return 0; for (size_t i=0; i