Commit b34029cc89b22994e6464b16479488ee7a775525
1 parent
f645840e
Incremental progress for plugins reorg
Showing
113 changed files
with
5111 additions
and
4674 deletions
openbr/plugins/ebif.cpp renamed to openbr/plugins/classification/ebif.cpp
| 1 | #include <opencv2/imgproc/imgproc.hpp> | 1 | #include <opencv2/imgproc/imgproc.hpp> |
| 2 | 2 | ||
| 3 | -#include "openbr_internal.h" | ||
| 4 | -#include "openbr/core/common.h" | ||
| 5 | -#include "openbr/core/opencvutils.h" | 3 | +#include <openbr/plugins/openbr_internal.h> |
| 4 | +#include <openbr/core/common.h> | ||
| 5 | +#include <openbr/core/opencvutils.h> | ||
| 6 | 6 | ||
| 7 | using namespace cv; | 7 | using namespace cv; |
| 8 | 8 |
openbr/plugins/cluster/collectnn.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief Collect nearest neighbors and append them to metadata. | ||
| 9 | + * \author Charles Otto \cite caotto | ||
| 10 | + */ | ||
| 11 | +class CollectNNTransform : public UntrainableMetaTransform | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + | ||
| 15 | + Q_PROPERTY(int keep READ get_keep WRITE set_keep RESET reset_keep STORED false) | ||
| 16 | + BR_PROPERTY(int, keep, 20) | ||
| 17 | + | ||
| 18 | + void project(const Template &src, Template &dst) const | ||
| 19 | + { | ||
| 20 | + dst.file = src.file; | ||
| 21 | + dst.clear(); | ||
| 22 | + dst.m() = cv::Mat(); | ||
| 23 | + Neighbors neighbors; | ||
| 24 | + for (int i=0; i < src.m().cols;i++) { | ||
| 25 | + // skip self compares | ||
| 26 | + if (i == src.file.get<int>("FrameNumber")) | ||
| 27 | + continue; | ||
| 28 | + neighbors.append(Neighbor(i, src.m().at<float>(0,i))); | ||
| 29 | + } | ||
| 30 | + int actuallyKeep = std::min(keep, neighbors.size()); | ||
| 31 | + std::partial_sort(neighbors.begin(), neighbors.begin()+actuallyKeep, neighbors.end(), compareNeighbors); | ||
| 32 | + | ||
| 33 | + Neighbors selected = neighbors.mid(0, actuallyKeep); | ||
| 34 | + dst.file.set("neighbors", QVariant::fromValue(selected)); | ||
| 35 | + } | ||
| 36 | +}; | ||
| 37 | + | ||
| 38 | +BR_REGISTER(Transform, CollectNNTransform) | ||
| 39 | + | ||
| 40 | +} // namespace br | ||
| 41 | + | ||
| 42 | +#include "collectnn.moc" |
openbr/plugins/cluster/kmeans.cpp
0 → 100644
| 1 | +#include <opencv2/flann/flann.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | +#include <openbr/core/opencvutils.h> | ||
| 5 | + | ||
| 6 | +using namespace cv; | ||
| 7 | + | ||
| 8 | +namespace br | ||
| 9 | +{ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \ingroup transforms | ||
| 13 | + * \brief Wraps OpenCV kmeans and flann. | ||
| 14 | + * \author Josh Klontz \cite jklontz | ||
| 15 | + */ | ||
| 16 | +class KMeansTransform : public Transform | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | ||
| 20 | + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | ||
| 21 | + BR_PROPERTY(int, kTrain, 256) | ||
| 22 | + BR_PROPERTY(int, kSearch, 1) | ||
| 23 | + | ||
| 24 | + Mat centers; | ||
| 25 | + mutable QScopedPointer<flann::Index> index; | ||
| 26 | + mutable QMutex mutex; | ||
| 27 | + | ||
| 28 | + void reindex() | ||
| 29 | + { | ||
| 30 | + index.reset(new flann::Index(centers, flann::LinearIndexParams())); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + void train(const TemplateList &data) | ||
| 34 | + { | ||
| 35 | + Mat bestLabels; | ||
| 36 | + const double compactness = kmeans(OpenCVUtils::toMatByRow(data.data()), kTrain, bestLabels, TermCriteria(TermCriteria::MAX_ITER, 10, 0), 3, KMEANS_PP_CENTERS, centers); | ||
| 37 | + qDebug("KMeans compactness = %f", compactness); | ||
| 38 | + reindex(); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + void project(const Template &src, Template &dst) const | ||
| 42 | + { | ||
| 43 | + QMutexLocker locker(&mutex); | ||
| 44 | + Mat dists, indicies; | ||
| 45 | + index->knnSearch(src, indicies, dists, kSearch); | ||
| 46 | + dst = indicies.reshape(1, 1); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + void load(QDataStream &stream) | ||
| 50 | + { | ||
| 51 | + stream >> centers; | ||
| 52 | + reindex(); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + void store(QDataStream &stream) const | ||
| 56 | + { | ||
| 57 | + stream << centers; | ||
| 58 | + } | ||
| 59 | +}; | ||
| 60 | + | ||
| 61 | +BR_REGISTER(Transform, KMeansTransform) | ||
| 62 | + | ||
| 63 | +} // namespace br | ||
| 64 | + | ||
| 65 | +#include "kmeans.moc" |
openbr/plugins/cluster.cpp renamed to openbr/plugins/cluster/knn.cpp
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/flann/flann.hpp> | ||
| 18 | - | ||
| 19 | -#include "openbr_internal.h" | ||
| 20 | -#include "openbr/core/common.h" | ||
| 21 | -#include "openbr/core/opencvutils.h" | ||
| 22 | -#include <fstream> | 1 | +#include <openbr/plugins/openbr_internal.h> |
| 2 | +#include <openbr/core/common.h> | ||
| 23 | 3 | ||
| 24 | using namespace cv; | 4 | using namespace cv; |
| 25 | 5 | ||
| @@ -28,58 +8,6 @@ namespace br | @@ -28,58 +8,6 @@ namespace br | ||
| 28 | 8 | ||
| 29 | /*! | 9 | /*! |
| 30 | * \ingroup transforms | 10 | * \ingroup transforms |
| 31 | - * \brief Wraps OpenCV kmeans and flann. | ||
| 32 | - * \author Josh Klontz \cite jklontz | ||
| 33 | - */ | ||
| 34 | -class KMeansTransform : public Transform | ||
| 35 | -{ | ||
| 36 | - Q_OBJECT | ||
| 37 | - Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | ||
| 38 | - Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | ||
| 39 | - BR_PROPERTY(int, kTrain, 256) | ||
| 40 | - BR_PROPERTY(int, kSearch, 1) | ||
| 41 | - | ||
| 42 | - Mat centers; | ||
| 43 | - mutable QScopedPointer<flann::Index> index; | ||
| 44 | - mutable QMutex mutex; | ||
| 45 | - | ||
| 46 | - void reindex() | ||
| 47 | - { | ||
| 48 | - index.reset(new flann::Index(centers, flann::LinearIndexParams())); | ||
| 49 | - } | ||
| 50 | - | ||
| 51 | - void train(const TemplateList &data) | ||
| 52 | - { | ||
| 53 | - Mat bestLabels; | ||
| 54 | - const double compactness = kmeans(OpenCVUtils::toMatByRow(data.data()), kTrain, bestLabels, TermCriteria(TermCriteria::MAX_ITER, 10, 0), 3, KMEANS_PP_CENTERS, centers); | ||
| 55 | - qDebug("KMeans compactness = %f", compactness); | ||
| 56 | - reindex(); | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - void project(const Template &src, Template &dst) const | ||
| 60 | - { | ||
| 61 | - QMutexLocker locker(&mutex); | ||
| 62 | - Mat dists, indicies; | ||
| 63 | - index->knnSearch(src, indicies, dists, kSearch); | ||
| 64 | - dst = indicies.reshape(1, 1); | ||
| 65 | - } | ||
| 66 | - | ||
| 67 | - void load(QDataStream &stream) | ||
| 68 | - { | ||
| 69 | - stream >> centers; | ||
| 70 | - reindex(); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - void store(QDataStream &stream) const | ||
| 74 | - { | ||
| 75 | - stream << centers; | ||
| 76 | - } | ||
| 77 | -}; | ||
| 78 | - | ||
| 79 | -BR_REGISTER(Transform, KMeansTransform) | ||
| 80 | - | ||
| 81 | -/*! | ||
| 82 | - * \ingroup transforms | ||
| 83 | * \brief K nearest neighbors classifier. | 11 | * \brief K nearest neighbors classifier. |
| 84 | * \author Josh Klontz \cite jklontz | 12 | * \author Josh Klontz \cite jklontz |
| 85 | */ | 13 | */ |
| @@ -151,148 +79,6 @@ class KNNTransform : public Transform | @@ -151,148 +79,6 @@ class KNNTransform : public Transform | ||
| 151 | 79 | ||
| 152 | BR_REGISTER(Transform, KNNTransform) | 80 | BR_REGISTER(Transform, KNNTransform) |
| 153 | 81 | ||
| 154 | -/*! | ||
| 155 | - * \ingroup transforms | ||
| 156 | - * \brief Chooses k random points to be centroids. | ||
| 157 | - * \author Austin Blanton \cite imaus10 | ||
| 158 | - * \see KMeansTransform | ||
| 159 | - */ | ||
| 160 | -class RandomCentroidsTransform : public Transform | ||
| 161 | -{ | ||
| 162 | - Q_OBJECT | ||
| 163 | - Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | ||
| 164 | - Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | ||
| 165 | - BR_PROPERTY(int, kTrain, 256) | ||
| 166 | - BR_PROPERTY(int, kSearch, 1) | ||
| 167 | - | ||
| 168 | - Mat centers; | ||
| 169 | - mutable QScopedPointer<flann::Index> index; | ||
| 170 | - mutable QMutex mutex; | ||
| 171 | - | ||
| 172 | - void reindex() | ||
| 173 | - { | ||
| 174 | - index.reset(new flann::Index(centers, flann::LinearIndexParams())); | ||
| 175 | - } | ||
| 176 | - | ||
| 177 | - void train(const TemplateList &data) | ||
| 178 | - { | ||
| 179 | - Mat flat = OpenCVUtils::toMatByRow(data.data()); | ||
| 180 | - QList<int> sample = Common::RandSample(kTrain, flat.rows, 0, true); | ||
| 181 | - foreach (const int &idx, sample) | ||
| 182 | - centers.push_back(flat.row(idx)); | ||
| 183 | - reindex(); | ||
| 184 | - } | ||
| 185 | - | ||
| 186 | - void project(const Template &src, Template &dst) const | ||
| 187 | - { | ||
| 188 | - QMutexLocker locker(&mutex); | ||
| 189 | - Mat dists, indicies; | ||
| 190 | - index->knnSearch(src, indicies, dists, kSearch); | ||
| 191 | - dst = indicies.reshape(1, 1); | ||
| 192 | - } | ||
| 193 | - | ||
| 194 | - void load(QDataStream &stream) | ||
| 195 | - { | ||
| 196 | - stream >> centers; | ||
| 197 | - reindex(); | ||
| 198 | - } | ||
| 199 | - | ||
| 200 | - void store(QDataStream &stream) const | ||
| 201 | - { | ||
| 202 | - stream << centers; | ||
| 203 | - } | ||
| 204 | -}; | ||
| 205 | - | ||
| 206 | -BR_REGISTER(Transform, RandomCentroidsTransform) | ||
| 207 | - | ||
| 208 | -class RegInitializer : public Initializer | ||
| 209 | -{ | ||
| 210 | - Q_OBJECT | ||
| 211 | - | ||
| 212 | - void initialize() const | ||
| 213 | - { | ||
| 214 | - qRegisterMetaType<br::Neighbors>(); | ||
| 215 | - } | ||
| 216 | -}; | ||
| 217 | -BR_REGISTER(Initializer, RegInitializer) | ||
| 218 | - | ||
| 219 | -class CollectNNTransform : public UntrainableMetaTransform | ||
| 220 | -{ | ||
| 221 | - Q_OBJECT | ||
| 222 | - | ||
| 223 | - Q_PROPERTY(int keep READ get_keep WRITE set_keep RESET reset_keep STORED false) | ||
| 224 | - BR_PROPERTY(int, keep, 20) | ||
| 225 | - | ||
| 226 | - void project(const Template &src, Template &dst) const | ||
| 227 | - { | ||
| 228 | - dst.file = src.file; | ||
| 229 | - dst.clear(); | ||
| 230 | - dst.m() = cv::Mat(); | ||
| 231 | - Neighbors neighbors; | ||
| 232 | - for (int i=0; i < src.m().cols;i++) { | ||
| 233 | - // skip self compares | ||
| 234 | - if (i == src.file.get<int>("FrameNumber")) | ||
| 235 | - continue; | ||
| 236 | - neighbors.append(Neighbor(i, src.m().at<float>(0,i))); | ||
| 237 | - } | ||
| 238 | - int actuallyKeep = std::min(keep, neighbors.size()); | ||
| 239 | - std::partial_sort(neighbors.begin(), neighbors.begin()+actuallyKeep, neighbors.end(), compareNeighbors); | ||
| 240 | - | ||
| 241 | - Neighbors selected = neighbors.mid(0, actuallyKeep); | ||
| 242 | - dst.file.set("neighbors", QVariant::fromValue(selected)); | ||
| 243 | - } | ||
| 244 | -}; | ||
| 245 | -BR_REGISTER(Transform, CollectNNTransform) | ||
| 246 | - | ||
| 247 | -class LogNNTransform : public TimeVaryingTransform | ||
| 248 | -{ | ||
| 249 | - Q_OBJECT | ||
| 250 | - | ||
| 251 | - Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false) | ||
| 252 | - BR_PROPERTY(QString, fileName, "") | ||
| 253 | - | ||
| 254 | - std::fstream fout; | ||
| 255 | - | ||
| 256 | - void projectUpdate(const Template &src, Template &dst) | ||
| 257 | - { | ||
| 258 | - dst = src; | ||
| 259 | - | ||
| 260 | - if (!dst.file.contains("neighbors")) { | ||
| 261 | - fout << std::endl; | ||
| 262 | - return; | ||
| 263 | - } | ||
| 264 | - | ||
| 265 | - Neighbors neighbors = dst.file.get<Neighbors>("neighbors"); | ||
| 266 | - if (neighbors.isEmpty() ) { | ||
| 267 | - fout << std::endl; | ||
| 268 | - return; | ||
| 269 | - } | ||
| 270 | - | ||
| 271 | - QString aLine; | ||
| 272 | - aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second)); | ||
| 273 | - for (int i=1; i < neighbors.size();i++) | ||
| 274 | - aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second)); | ||
| 275 | - | ||
| 276 | - fout << qPrintable(aLine) << std::endl; | ||
| 277 | - } | ||
| 278 | - | ||
| 279 | - void init() | ||
| 280 | - { | ||
| 281 | - if (!fileName.isEmpty()) | ||
| 282 | - fout.open(qPrintable(fileName), std::ios_base::out); | ||
| 283 | - } | ||
| 284 | - | ||
| 285 | - void finalize(TemplateList &output) | ||
| 286 | - { | ||
| 287 | - (void) output; | ||
| 288 | - fout.close(); | ||
| 289 | - } | ||
| 290 | - | ||
| 291 | -public: | ||
| 292 | - LogNNTransform() : TimeVaryingTransform(false, false) {} | ||
| 293 | -}; | ||
| 294 | -BR_REGISTER(Transform, LogNNTransform) | ||
| 295 | - | ||
| 296 | } // namespace br | 82 | } // namespace br |
| 297 | 83 | ||
| 298 | -#include "cluster.moc" | 84 | +#include "knn.moc" |
openbr/plugins/cluster/lognn.cpp
0 → 100644
| 1 | +#include <fstream> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Log nearest neighbors to specified file. | ||
| 11 | + * \author Charles Otto \cite caotto | ||
| 12 | + */ | ||
| 13 | +class LogNNTransform : public TimeVaryingTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false) | ||
| 18 | + BR_PROPERTY(QString, fileName, "") | ||
| 19 | + | ||
| 20 | + std::fstream fout; | ||
| 21 | + | ||
| 22 | + void projectUpdate(const Template &src, Template &dst) | ||
| 23 | + { | ||
| 24 | + dst = src; | ||
| 25 | + | ||
| 26 | + if (!dst.file.contains("neighbors")) { | ||
| 27 | + fout << std::endl; | ||
| 28 | + return; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + Neighbors neighbors = dst.file.get<Neighbors>("neighbors"); | ||
| 32 | + if (neighbors.isEmpty() ) { | ||
| 33 | + fout << std::endl; | ||
| 34 | + return; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + QString aLine; | ||
| 38 | + aLine.append(QString::number(neighbors[0].first)+":"+QString::number(neighbors[0].second)); | ||
| 39 | + for (int i=1; i < neighbors.size();i++) | ||
| 40 | + aLine.append(","+QString::number(neighbors[i].first)+":"+QString::number(neighbors[i].second)); | ||
| 41 | + | ||
| 42 | + fout << qPrintable(aLine) << std::endl; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + void init() | ||
| 46 | + { | ||
| 47 | + if (!fileName.isEmpty()) | ||
| 48 | + fout.open(qPrintable(fileName), std::ios_base::out); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + void finalize(TemplateList &output) | ||
| 52 | + { | ||
| 53 | + (void) output; | ||
| 54 | + fout.close(); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | +public: | ||
| 58 | + LogNNTransform() : TimeVaryingTransform(false, false) {} | ||
| 59 | +}; | ||
| 60 | + | ||
| 61 | +BR_REGISTER(Transform, LogNNTransform) | ||
| 62 | + | ||
| 63 | +} // namespace br | ||
| 64 | + | ||
| 65 | +#include "lognn.moc" |
openbr/plugins/cluster/randomcentroids.cpp
0 → 100644
| 1 | +#include <opencv2/flann/flann.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | +#include <openbr/core/common.h> | ||
| 5 | +#include <openbr/core/opencvutils.h> | ||
| 6 | + | ||
| 7 | +using namespace cv; | ||
| 8 | + | ||
| 9 | +namespace br | ||
| 10 | +{ | ||
| 11 | + | ||
| 12 | +/*! | ||
| 13 | + * \ingroup transforms | ||
| 14 | + * \brief Chooses k random points to be centroids. | ||
| 15 | + * \author Austin Blanton \cite imaus10 | ||
| 16 | + * \see KMeansTransform | ||
| 17 | + */ | ||
| 18 | +class RandomCentroidsTransform : public Transform | ||
| 19 | +{ | ||
| 20 | + Q_OBJECT | ||
| 21 | + Q_PROPERTY(int kTrain READ get_kTrain WRITE set_kTrain RESET reset_kTrain STORED false) | ||
| 22 | + Q_PROPERTY(int kSearch READ get_kSearch WRITE set_kSearch RESET reset_kSearch STORED false) | ||
| 23 | + BR_PROPERTY(int, kTrain, 256) | ||
| 24 | + BR_PROPERTY(int, kSearch, 1) | ||
| 25 | + | ||
| 26 | + Mat centers; | ||
| 27 | + mutable QScopedPointer<flann::Index> index; | ||
| 28 | + mutable QMutex mutex; | ||
| 29 | + | ||
| 30 | + void reindex() | ||
| 31 | + { | ||
| 32 | + index.reset(new flann::Index(centers, flann::LinearIndexParams())); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + void train(const TemplateList &data) | ||
| 36 | + { | ||
| 37 | + Mat flat = OpenCVUtils::toMatByRow(data.data()); | ||
| 38 | + QList<int> sample = Common::RandSample(kTrain, flat.rows, 0, true); | ||
| 39 | + foreach (const int &idx, sample) | ||
| 40 | + centers.push_back(flat.row(idx)); | ||
| 41 | + reindex(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + void project(const Template &src, Template &dst) const | ||
| 45 | + { | ||
| 46 | + QMutexLocker locker(&mutex); | ||
| 47 | + Mat dists, indicies; | ||
| 48 | + index->knnSearch(src, indicies, dists, kSearch); | ||
| 49 | + dst = indicies.reshape(1, 1); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + void load(QDataStream &stream) | ||
| 53 | + { | ||
| 54 | + stream >> centers; | ||
| 55 | + reindex(); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + void store(QDataStream &stream) const | ||
| 59 | + { | ||
| 60 | + stream << centers; | ||
| 61 | + } | ||
| 62 | +}; | ||
| 63 | + | ||
| 64 | +BR_REGISTER(Transform, RandomCentroidsTransform) | ||
| 65 | + | ||
| 66 | +} //namespace br | ||
| 67 | + | ||
| 68 | +#include "randomcentroids.moc" |
openbr/plugins/algorithms.cpp renamed to openbr/plugins/core/algorithms.cpp
| @@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
| 14 | * limitations under the License. * | 14 | * limitations under the License. * |
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | -#include "openbr_internal.h" | 17 | +#include <openbr/plugins/openbr_internal.h> |
| 18 | 18 | ||
| 19 | namespace br | 19 | namespace br |
| 20 | { | 20 | { |
openbr/plugins/independent.cpp renamed to openbr/plugins/core/downsample.cpp
| 1 | -#include <QFutureSynchronizer> | ||
| 2 | -#include <QtConcurrentRun> | ||
| 3 | - | ||
| 4 | -#include "openbr_internal.h" | ||
| 5 | -#include "openbr/core/common.h" | ||
| 6 | - | ||
| 7 | -using namespace cv; | 1 | +#include <openbr/plugins/openbr_internal.h> |
| 8 | 2 | ||
| 9 | namespace br | 3 | namespace br |
| 10 | { | 4 | { |
| @@ -103,10 +97,10 @@ class DownsampleTrainingTransform : public Transform | @@ -103,10 +97,10 @@ class DownsampleTrainingTransform : public Transform | ||
| 103 | 97 | ||
| 104 | void project(const Template &src, Template &dst) const | 98 | void project(const Template &src, Template &dst) const |
| 105 | { | 99 | { |
| 106 | - transform->project(src,dst); | 100 | + transform->project(src,dst); |
| 107 | } | 101 | } |
| 108 | - | ||
| 109 | - | 102 | + |
| 103 | + | ||
| 110 | void train(const TemplateList &data) | 104 | void train(const TemplateList &data) |
| 111 | { | 105 | { |
| 112 | if (!transform || !transform->trainable) | 106 | if (!transform || !transform->trainable) |
| @@ -117,274 +111,9 @@ class DownsampleTrainingTransform : public Transform | @@ -117,274 +111,9 @@ class DownsampleTrainingTransform : public Transform | ||
| 117 | transform->train(downsampled); | 111 | transform->train(downsampled); |
| 118 | } | 112 | } |
| 119 | }; | 113 | }; |
| 120 | -BR_REGISTER(Transform, DownsampleTrainingTransform) | ||
| 121 | - | ||
| 122 | -/*! | ||
| 123 | - * \ingroup transforms | ||
| 124 | - * \brief Clones the transform so that it can be applied independently. | ||
| 125 | - * \author Josh Klontz \cite jklontz | ||
| 126 | - * \em Independent transforms expect single-matrix templates. | ||
| 127 | - */ | ||
| 128 | -class IndependentTransform : public MetaTransform | ||
| 129 | -{ | ||
| 130 | - Q_OBJECT | ||
| 131 | - Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform STORED false) | ||
| 132 | - BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 133 | - | ||
| 134 | - QList<Transform*> transforms; | ||
| 135 | - | ||
| 136 | - QString description(bool expanded) const | ||
| 137 | - { | ||
| 138 | - return transform->description(expanded); | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - // can't use general setPropertyRecursive because of transforms oddness | ||
| 142 | - bool setPropertyRecursive(const QString &name, QVariant value) | ||
| 143 | - { | ||
| 144 | - if (br::Object::setExistingProperty(name, value)) | ||
| 145 | - return true; | ||
| 146 | - | ||
| 147 | - if (!transform->setPropertyRecursive(name, value)) | ||
| 148 | - return false; | ||
| 149 | - | ||
| 150 | - for (int i=0;i < transforms.size();i++) | ||
| 151 | - transforms[i]->setPropertyRecursive(name, value); | ||
| 152 | - | ||
| 153 | - return true; | ||
| 154 | - } | ||
| 155 | - | ||
| 156 | - Transform *simplify(bool &newTransform) | ||
| 157 | - { | ||
| 158 | - newTransform = false; | ||
| 159 | - bool newChild = false; | ||
| 160 | - Transform *temp = transform->simplify(newChild); | ||
| 161 | - if (temp == transform) { | ||
| 162 | - return this; | ||
| 163 | - } | ||
| 164 | - IndependentTransform* indep = new IndependentTransform(); | ||
| 165 | - indep->transform = temp; | ||
| 166 | - | ||
| 167 | - IndependentTransform *test = dynamic_cast<IndependentTransform *> (temp); | ||
| 168 | - if (test) { | ||
| 169 | - // child was independent? this changes things... | ||
| 170 | - indep->transform = test->transform; | ||
| 171 | - for (int i=0; i < transforms.size(); i++) { | ||
| 172 | - bool newThing = false; | ||
| 173 | - IndependentTransform *probe = dynamic_cast<IndependentTransform *> (transforms[i]->simplify(newThing)); | ||
| 174 | - indep->transforms.append(probe->transform); | ||
| 175 | - if (newThing) | ||
| 176 | - probe->setParent(indep); | ||
| 177 | - } | ||
| 178 | - indep->file = indep->transform->file; | ||
| 179 | - indep->trainable = indep->transform->trainable; | ||
| 180 | - indep->setObjectName(indep->transform->objectName()); | ||
| 181 | - | ||
| 182 | - return indep; | ||
| 183 | - } | ||
| 184 | - | ||
| 185 | - if (newChild) | ||
| 186 | - indep->transform->setParent(indep); | ||
| 187 | - | ||
| 188 | - for (int i=0; i < transforms.size();i++) { | ||
| 189 | - bool subTform = false; | ||
| 190 | - indep->transforms.append(transforms[i]->simplify(subTform)); | ||
| 191 | - if (subTform) | ||
| 192 | - indep->transforms[i]->setParent(indep); | ||
| 193 | - } | ||
| 194 | 114 | ||
| 195 | - indep->file = indep->transform->file; | ||
| 196 | - indep->trainable = indep->transform->trainable; | ||
| 197 | - indep->setObjectName(indep->transform->objectName()); | ||
| 198 | - | ||
| 199 | - return indep; | ||
| 200 | - } | ||
| 201 | - | ||
| 202 | - void init() | ||
| 203 | - { | ||
| 204 | - transforms.clear(); | ||
| 205 | - if (transform == NULL) | ||
| 206 | - return; | ||
| 207 | - | ||
| 208 | - transform->setParent(this); | ||
| 209 | - transforms.append(transform); | ||
| 210 | - file = transform->file; | ||
| 211 | - trainable = transform->trainable; | ||
| 212 | - setObjectName(transform->objectName()); | ||
| 213 | - } | ||
| 214 | - | ||
| 215 | - Transform *clone() const | ||
| 216 | - { | ||
| 217 | - IndependentTransform *independentTransform = new IndependentTransform(); | ||
| 218 | - independentTransform->transform = transform->clone(); | ||
| 219 | - independentTransform->init(); | ||
| 220 | - return independentTransform; | ||
| 221 | - } | ||
| 222 | - | ||
| 223 | - bool timeVarying() const { return transform->timeVarying(); } | ||
| 224 | - | ||
| 225 | - static void _train(Transform *transform, const TemplateList *data) | ||
| 226 | - { | ||
| 227 | - transform->train(*data); | ||
| 228 | - } | ||
| 229 | - | ||
| 230 | - void train(const TemplateList &data) | ||
| 231 | - { | ||
| 232 | - // Don't bother if the transform is untrainable | ||
| 233 | - if (!trainable) return; | ||
| 234 | - | ||
| 235 | - QList<TemplateList> templatesList; | ||
| 236 | - foreach (const Template &t, data) { | ||
| 237 | - if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) | ||
| 238 | - qWarning("Independent::train (%s) template %s of size %d differs from expected size %d.", qPrintable(objectName()), qPrintable(t.file.name), t.size(), templatesList.size()); | ||
| 239 | - while (templatesList.size() < t.size()) | ||
| 240 | - templatesList.append(TemplateList()); | ||
| 241 | - for (int i=0; i<t.size(); i++) | ||
| 242 | - templatesList[i].append(Template(t.file, t[i])); | ||
| 243 | - } | ||
| 244 | - | ||
| 245 | - while (transforms.size() < templatesList.size()) | ||
| 246 | - transforms.append(transform->clone()); | ||
| 247 | - | ||
| 248 | - QFutureSynchronizer<void> futures; | ||
| 249 | - for (int i=0; i<templatesList.size(); i++) | ||
| 250 | - futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | ||
| 251 | - futures.waitForFinished(); | ||
| 252 | - } | ||
| 253 | - | ||
| 254 | - void project(const Template &src, Template &dst) const | ||
| 255 | - { | ||
| 256 | - dst.file = src.file; | ||
| 257 | - QList<Mat> mats; | ||
| 258 | - for (int i=0; i<src.size(); i++) { | ||
| 259 | - transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst); | ||
| 260 | - mats.append(dst); | ||
| 261 | - dst.clear(); | ||
| 262 | - } | ||
| 263 | - dst.append(mats); | ||
| 264 | - } | ||
| 265 | - | ||
| 266 | - void projectUpdate(const Template &src, Template &dst) | ||
| 267 | - { | ||
| 268 | - dst.file = src.file; | ||
| 269 | - QList<Mat> mats; | ||
| 270 | - for (int i=0; i<src.size(); i++) { | ||
| 271 | - transforms[i%transforms.size()]->projectUpdate(Template(src.file, src[i]), dst); | ||
| 272 | - mats.append(dst); | ||
| 273 | - dst.clear(); | ||
| 274 | - } | ||
| 275 | - dst.append(mats); | ||
| 276 | - } | ||
| 277 | - | ||
| 278 | - void finalize(TemplateList &out) | ||
| 279 | - { | ||
| 280 | - if (transforms.empty()) | ||
| 281 | - return; | ||
| 282 | - | ||
| 283 | - transforms[0]->finalize(out); | ||
| 284 | - for (int i=1; i < transforms.size(); i++) { | ||
| 285 | - TemplateList temp; | ||
| 286 | - transforms[i]->finalize(temp); | ||
| 287 | - | ||
| 288 | - for (int j=0; j < out.size(); j++) | ||
| 289 | - out[j].append(temp[j]); | ||
| 290 | - } | ||
| 291 | - } | ||
| 292 | - | ||
| 293 | - void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 294 | - { | ||
| 295 | - dst.reserve(src.size()); | ||
| 296 | - foreach (const Template &t, src) { | ||
| 297 | - dst.append(Template()); | ||
| 298 | - projectUpdate(t, dst.last()); | ||
| 299 | - } | ||
| 300 | - } | ||
| 301 | - | ||
| 302 | - void store(QDataStream &stream) const | ||
| 303 | - { | ||
| 304 | - const int size = transforms.size(); | ||
| 305 | - stream << size; | ||
| 306 | - for (int i=0; i<size; i++) | ||
| 307 | - transforms[i]->store(stream); | ||
| 308 | - } | ||
| 309 | - | ||
| 310 | - void load(QDataStream &stream) | ||
| 311 | - { | ||
| 312 | - int size; | ||
| 313 | - stream >> size; | ||
| 314 | - while (transforms.size() < size) | ||
| 315 | - transforms.append(transform->clone()); | ||
| 316 | - for (int i=0; i<size; i++) | ||
| 317 | - transforms[i]->load(stream); | ||
| 318 | - } | ||
| 319 | -}; | ||
| 320 | - | ||
| 321 | -BR_REGISTER(Transform, IndependentTransform) | ||
| 322 | - | ||
| 323 | -/*! | ||
| 324 | - * \ingroup transforms | ||
| 325 | - * \brief A globally shared transform. | ||
| 326 | - * \author Josh Klontz \cite jklontz | ||
| 327 | - */ | ||
| 328 | -class SingletonTransform : public MetaTransform | ||
| 329 | -{ | ||
| 330 | - Q_OBJECT | ||
| 331 | - Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | ||
| 332 | - BR_PROPERTY(QString, description, "Identity") | ||
| 333 | - | ||
| 334 | - static QMutex mutex; | ||
| 335 | - static QHash<QString,Transform*> transforms; | ||
| 336 | - static QHash<QString,int> trainingReferenceCounts; | ||
| 337 | - static QHash<QString,TemplateList> trainingData; | ||
| 338 | - | ||
| 339 | - Transform *transform; | ||
| 340 | - | ||
| 341 | - void init() | ||
| 342 | - { | ||
| 343 | - QMutexLocker locker(&mutex); | ||
| 344 | - if (!transforms.contains(description)) { | ||
| 345 | - transforms.insert(description, make(description)); | ||
| 346 | - trainingReferenceCounts.insert(description, 0); | ||
| 347 | - } | ||
| 348 | - | ||
| 349 | - transform = transforms[description]; | ||
| 350 | - trainingReferenceCounts[description]++; | ||
| 351 | - } | ||
| 352 | - | ||
| 353 | - void train(const TemplateList &data) | ||
| 354 | - { | ||
| 355 | - QMutexLocker locker(&mutex); | ||
| 356 | - trainingData[description].append(data); | ||
| 357 | - trainingReferenceCounts[description]--; | ||
| 358 | - if (trainingReferenceCounts[description] > 0) return; | ||
| 359 | - transform->train(trainingData[description]); | ||
| 360 | - trainingData[description].clear(); | ||
| 361 | - } | ||
| 362 | - | ||
| 363 | - void project(const Template &src, Template &dst) const | ||
| 364 | - { | ||
| 365 | - transform->project(src, dst); | ||
| 366 | - } | ||
| 367 | - | ||
| 368 | - void store(QDataStream &stream) const | ||
| 369 | - { | ||
| 370 | - if (transform->parent() == this) | ||
| 371 | - transform->store(stream); | ||
| 372 | - } | ||
| 373 | - | ||
| 374 | - void load(QDataStream &stream) | ||
| 375 | - { | ||
| 376 | - if (transform->parent() == this) | ||
| 377 | - transform->load(stream); | ||
| 378 | - } | ||
| 379 | -}; | ||
| 380 | - | ||
| 381 | -QMutex SingletonTransform::mutex; | ||
| 382 | -QHash<QString,Transform*> SingletonTransform::transforms; | ||
| 383 | -QHash<QString,int> SingletonTransform::trainingReferenceCounts; | ||
| 384 | -QHash<QString,TemplateList> SingletonTransform::trainingData; | ||
| 385 | - | ||
| 386 | -BR_REGISTER(Transform, SingletonTransform) | 115 | +BR_REGISTER(Transform, DownsampleTrainingTransform) |
| 387 | 116 | ||
| 388 | } // namespace br | 117 | } // namespace br |
| 389 | 118 | ||
| 390 | -#include "independent.moc" | 119 | +#include "downsample.moc" |
openbr/plugins/core/independent.cpp
0 → 100644
| 1 | +#include <QtConcurrent> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Clones the transform so that it can be applied independently. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + * \em Independent transforms expect single-matrix templates. | ||
| 15 | + */ | ||
| 16 | +class IndependentTransform : public MetaTransform | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform STORED false) | ||
| 20 | + BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 21 | + | ||
| 22 | + QList<Transform*> transforms; | ||
| 23 | + | ||
| 24 | + QString description(bool expanded) const | ||
| 25 | + { | ||
| 26 | + return transform->description(expanded); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + // can't use general setPropertyRecursive because of transforms oddness | ||
| 30 | + bool setPropertyRecursive(const QString &name, QVariant value) | ||
| 31 | + { | ||
| 32 | + if (br::Object::setExistingProperty(name, value)) | ||
| 33 | + return true; | ||
| 34 | + | ||
| 35 | + if (!transform->setPropertyRecursive(name, value)) | ||
| 36 | + return false; | ||
| 37 | + | ||
| 38 | + for (int i=0;i < transforms.size();i++) | ||
| 39 | + transforms[i]->setPropertyRecursive(name, value); | ||
| 40 | + | ||
| 41 | + return true; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + Transform *simplify(bool &newTransform) | ||
| 45 | + { | ||
| 46 | + newTransform = false; | ||
| 47 | + bool newChild = false; | ||
| 48 | + Transform *temp = transform->simplify(newChild); | ||
| 49 | + if (temp == transform) { | ||
| 50 | + return this; | ||
| 51 | + } | ||
| 52 | + IndependentTransform* indep = new IndependentTransform(); | ||
| 53 | + indep->transform = temp; | ||
| 54 | + | ||
| 55 | + IndependentTransform *test = dynamic_cast<IndependentTransform *> (temp); | ||
| 56 | + if (test) { | ||
| 57 | + // child was independent? this changes things... | ||
| 58 | + indep->transform = test->transform; | ||
| 59 | + for (int i=0; i < transforms.size(); i++) { | ||
| 60 | + bool newThing = false; | ||
| 61 | + IndependentTransform *probe = dynamic_cast<IndependentTransform *> (transforms[i]->simplify(newThing)); | ||
| 62 | + indep->transforms.append(probe->transform); | ||
| 63 | + if (newThing) | ||
| 64 | + probe->setParent(indep); | ||
| 65 | + } | ||
| 66 | + indep->file = indep->transform->file; | ||
| 67 | + indep->trainable = indep->transform->trainable; | ||
| 68 | + indep->setObjectName(indep->transform->objectName()); | ||
| 69 | + | ||
| 70 | + return indep; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + if (newChild) | ||
| 74 | + indep->transform->setParent(indep); | ||
| 75 | + | ||
| 76 | + for (int i=0; i < transforms.size();i++) { | ||
| 77 | + bool subTform = false; | ||
| 78 | + indep->transforms.append(transforms[i]->simplify(subTform)); | ||
| 79 | + if (subTform) | ||
| 80 | + indep->transforms[i]->setParent(indep); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + indep->file = indep->transform->file; | ||
| 84 | + indep->trainable = indep->transform->trainable; | ||
| 85 | + indep->setObjectName(indep->transform->objectName()); | ||
| 86 | + | ||
| 87 | + return indep; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + void init() | ||
| 91 | + { | ||
| 92 | + transforms.clear(); | ||
| 93 | + if (transform == NULL) | ||
| 94 | + return; | ||
| 95 | + | ||
| 96 | + transform->setParent(this); | ||
| 97 | + transforms.append(transform); | ||
| 98 | + file = transform->file; | ||
| 99 | + trainable = transform->trainable; | ||
| 100 | + setObjectName(transform->objectName()); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + Transform *clone() const | ||
| 104 | + { | ||
| 105 | + IndependentTransform *independentTransform = new IndependentTransform(); | ||
| 106 | + independentTransform->transform = transform->clone(); | ||
| 107 | + independentTransform->init(); | ||
| 108 | + return independentTransform; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + bool timeVarying() const { return transform->timeVarying(); } | ||
| 112 | + | ||
| 113 | + static void _train(Transform *transform, const TemplateList *data) | ||
| 114 | + { | ||
| 115 | + transform->train(*data); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + void train(const TemplateList &data) | ||
| 119 | + { | ||
| 120 | + // Don't bother if the transform is untrainable | ||
| 121 | + if (!trainable) return; | ||
| 122 | + | ||
| 123 | + QList<TemplateList> templatesList; | ||
| 124 | + foreach (const Template &t, data) { | ||
| 125 | + if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) | ||
| 126 | + qWarning("Independent::train (%s) template %s of size %d differs from expected size %d.", qPrintable(objectName()), qPrintable(t.file.name), t.size(), templatesList.size()); | ||
| 127 | + while (templatesList.size() < t.size()) | ||
| 128 | + templatesList.append(TemplateList()); | ||
| 129 | + for (int i=0; i<t.size(); i++) | ||
| 130 | + templatesList[i].append(Template(t.file, t[i])); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + while (transforms.size() < templatesList.size()) | ||
| 134 | + transforms.append(transform->clone()); | ||
| 135 | + | ||
| 136 | + QFutureSynchronizer<void> futures; | ||
| 137 | + for (int i=0; i<templatesList.size(); i++) | ||
| 138 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | ||
| 139 | + futures.waitForFinished(); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + void project(const Template &src, Template &dst) const | ||
| 143 | + { | ||
| 144 | + dst.file = src.file; | ||
| 145 | + QList<Mat> mats; | ||
| 146 | + for (int i=0; i<src.size(); i++) { | ||
| 147 | + transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst); | ||
| 148 | + mats.append(dst); | ||
| 149 | + dst.clear(); | ||
| 150 | + } | ||
| 151 | + dst.append(mats); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + void projectUpdate(const Template &src, Template &dst) | ||
| 155 | + { | ||
| 156 | + dst.file = src.file; | ||
| 157 | + QList<Mat> mats; | ||
| 158 | + for (int i=0; i<src.size(); i++) { | ||
| 159 | + transforms[i%transforms.size()]->projectUpdate(Template(src.file, src[i]), dst); | ||
| 160 | + mats.append(dst); | ||
| 161 | + dst.clear(); | ||
| 162 | + } | ||
| 163 | + dst.append(mats); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + void finalize(TemplateList &out) | ||
| 167 | + { | ||
| 168 | + if (transforms.empty()) | ||
| 169 | + return; | ||
| 170 | + | ||
| 171 | + transforms[0]->finalize(out); | ||
| 172 | + for (int i=1; i < transforms.size(); i++) { | ||
| 173 | + TemplateList temp; | ||
| 174 | + transforms[i]->finalize(temp); | ||
| 175 | + | ||
| 176 | + for (int j=0; j < out.size(); j++) | ||
| 177 | + out[j].append(temp[j]); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 182 | + { | ||
| 183 | + dst.reserve(src.size()); | ||
| 184 | + foreach (const Template &t, src) { | ||
| 185 | + dst.append(Template()); | ||
| 186 | + projectUpdate(t, dst.last()); | ||
| 187 | + } | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + void store(QDataStream &stream) const | ||
| 191 | + { | ||
| 192 | + const int size = transforms.size(); | ||
| 193 | + stream << size; | ||
| 194 | + for (int i=0; i<size; i++) | ||
| 195 | + transforms[i]->store(stream); | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + void load(QDataStream &stream) | ||
| 199 | + { | ||
| 200 | + int size; | ||
| 201 | + stream >> size; | ||
| 202 | + while (transforms.size() < size) | ||
| 203 | + transforms.append(transform->clone()); | ||
| 204 | + for (int i=0; i<size; i++) | ||
| 205 | + transforms[i]->load(stream); | ||
| 206 | + } | ||
| 207 | +}; | ||
| 208 | + | ||
| 209 | +BR_REGISTER(Transform, IndependentTransform) | ||
| 210 | + | ||
| 211 | +} // namespace br | ||
| 212 | + | ||
| 213 | +#include "independent.moc" |
openbr/plugins/core/singleton.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief A globally shared transform. | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class SingletonTransform : public MetaTransform | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | ||
| 15 | + BR_PROPERTY(QString, description, "Identity") | ||
| 16 | + | ||
| 17 | + static QMutex mutex; | ||
| 18 | + static QHash<QString,Transform*> transforms; | ||
| 19 | + static QHash<QString,int> trainingReferenceCounts; | ||
| 20 | + static QHash<QString,TemplateList> trainingData; | ||
| 21 | + | ||
| 22 | + Transform *transform; | ||
| 23 | + | ||
| 24 | + void init() | ||
| 25 | + { | ||
| 26 | + QMutexLocker locker(&mutex); | ||
| 27 | + if (!transforms.contains(description)) { | ||
| 28 | + transforms.insert(description, make(description)); | ||
| 29 | + trainingReferenceCounts.insert(description, 0); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + transform = transforms[description]; | ||
| 33 | + trainingReferenceCounts[description]++; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + void train(const TemplateList &data) | ||
| 37 | + { | ||
| 38 | + QMutexLocker locker(&mutex); | ||
| 39 | + trainingData[description].append(data); | ||
| 40 | + trainingReferenceCounts[description]--; | ||
| 41 | + if (trainingReferenceCounts[description] > 0) return; | ||
| 42 | + transform->train(trainingData[description]); | ||
| 43 | + trainingData[description].clear(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + void project(const Template &src, Template &dst) const | ||
| 47 | + { | ||
| 48 | + transform->project(src, dst); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + void store(QDataStream &stream) const | ||
| 52 | + { | ||
| 53 | + if (transform->parent() == this) | ||
| 54 | + transform->store(stream); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + void load(QDataStream &stream) | ||
| 58 | + { | ||
| 59 | + if (transform->parent() == this) | ||
| 60 | + transform->load(stream); | ||
| 61 | + } | ||
| 62 | +}; | ||
| 63 | + | ||
| 64 | +QMutex SingletonTransform::mutex; | ||
| 65 | +QHash<QString,Transform*> SingletonTransform::transforms; | ||
| 66 | +QHash<QString,int> SingletonTransform::trainingReferenceCounts; | ||
| 67 | +QHash<QString,TemplateList> SingletonTransform::trainingData; | ||
| 68 | + | ||
| 69 | +BR_REGISTER(Transform, SingletonTransform) | ||
| 70 | + | ||
| 71 | +} // namespace br | ||
| 72 | + | ||
| 73 | +#include "singleton.moc" |
openbr/plugins/crop.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 18 | -#include "openbr_internal.h" | ||
| 19 | - | ||
| 20 | -#include "openbr/core/opencvutils.h" | ||
| 21 | - | ||
| 22 | -using namespace cv; | ||
| 23 | - | ||
| 24 | -namespace br | ||
| 25 | -{ | ||
| 26 | - | ||
| 27 | -/*! | ||
| 28 | - * \ingroup transforms | ||
| 29 | - * \brief Crops about the specified region of interest. | ||
| 30 | - * \author Josh Klontz \cite jklontz | ||
| 31 | - */ | ||
| 32 | -class CropTransform : public UntrainableTransform | ||
| 33 | -{ | ||
| 34 | - Q_OBJECT | ||
| 35 | - Q_PROPERTY(int x READ get_x WRITE set_x RESET reset_x STORED false) | ||
| 36 | - Q_PROPERTY(int y READ get_y WRITE set_y RESET reset_y STORED false) | ||
| 37 | - Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | ||
| 38 | - Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | ||
| 39 | - BR_PROPERTY(int, x, 0) | ||
| 40 | - BR_PROPERTY(int, y, 0) | ||
| 41 | - BR_PROPERTY(int, width, -1) | ||
| 42 | - BR_PROPERTY(int, height, -1) | ||
| 43 | - | ||
| 44 | - void project(const Template &src, Template &dst) const | ||
| 45 | - { | ||
| 46 | - dst = Mat(src, Rect(x, y, width < 1 ? src.m().cols-x-abs(width) : width, height < 1 ? src.m().rows-y-abs(height) : height)); | ||
| 47 | - } | ||
| 48 | -}; | ||
| 49 | - | ||
| 50 | -BR_REGISTER(Transform, CropTransform) | ||
| 51 | - | ||
| 52 | -/*! | ||
| 53 | - * \ingroup transforms | ||
| 54 | - * \brief Crops the rectangular regions of interest. | ||
| 55 | - * \author Josh Klontz \cite jklontz | ||
| 56 | - */ | ||
| 57 | -class ROITransform : public UntrainableTransform | ||
| 58 | -{ | ||
| 59 | - Q_OBJECT | ||
| 60 | - Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | ||
| 61 | - BR_PROPERTY(QString, propName, "") | ||
| 62 | - | ||
| 63 | - void project(const Template &src, Template &dst) const | ||
| 64 | - { | ||
| 65 | - if (!propName.isEmpty()) { | ||
| 66 | - QRectF rect = src.file.get<QRectF>(propName); | ||
| 67 | - dst += src.m()(OpenCVUtils::toRect(rect)); | ||
| 68 | - } else if (!src.file.rects().empty()) { | ||
| 69 | - foreach (const QRectF &rect, src.file.rects()) | ||
| 70 | - dst += src.m()(OpenCVUtils::toRect(rect)); | ||
| 71 | - } else if (src.file.contains(QStringList() << "X" << "Y" << "Width" << "Height")) { | ||
| 72 | - dst += src.m()(Rect(src.file.get<int>("X"), | ||
| 73 | - src.file.get<int>("Y"), | ||
| 74 | - src.file.get<int>("Width"), | ||
| 75 | - src.file.get<int>("Height"))); | ||
| 76 | - } else { | ||
| 77 | - dst = src; | ||
| 78 | - if (Globals->verbose) | ||
| 79 | - qWarning("No rects present in file."); | ||
| 80 | - } | ||
| 81 | - } | ||
| 82 | -}; | ||
| 83 | - | ||
| 84 | -BR_REGISTER(Transform, ROITransform) | ||
| 85 | - | ||
| 86 | -/*! | ||
| 87 | - * \ingroup transforms | ||
| 88 | - * \brief Crops the rectangular regions of interest from given points and sizes. | ||
| 89 | - * \author Austin Blanton \cite imaus10 | ||
| 90 | - */ | ||
| 91 | -class ROIFromPtsTransform : public UntrainableTransform | ||
| 92 | -{ | ||
| 93 | - Q_OBJECT | ||
| 94 | - Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | ||
| 95 | - Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | ||
| 96 | - BR_PROPERTY(int, width, 1) | ||
| 97 | - BR_PROPERTY(int, height, 1) | ||
| 98 | - | ||
| 99 | - void project(const Template &src, Template &dst) const | ||
| 100 | - { | ||
| 101 | - foreach (const QPointF &pt, src.file.points()) { | ||
| 102 | - int x = pt.x() - (width/2); | ||
| 103 | - int y = pt.y() - (height/2); | ||
| 104 | - dst += src.m()(Rect(x, y, width, height)); | ||
| 105 | - } | ||
| 106 | - } | ||
| 107 | -}; | ||
| 108 | - | ||
| 109 | -BR_REGISTER(Transform, ROIFromPtsTransform) | ||
| 110 | - | ||
| 111 | -/*! | ||
| 112 | - * \ingroup transforms | ||
| 113 | - * \brief Resize the template | ||
| 114 | - * \author Josh Klontz \cite jklontz | ||
| 115 | - * \note Method: Area should be used for shrinking an image, Cubic for slow but accurate enlargment, Bilin for fast enlargement. | ||
| 116 | - * \param preserveAspect If true, the image will be sized per specification, but | ||
| 117 | - * a border will be applied to preserve aspect ratio. | ||
| 118 | - */ | ||
| 119 | -class ResizeTransform : public UntrainableTransform | ||
| 120 | -{ | ||
| 121 | - Q_OBJECT | ||
| 122 | - Q_ENUMS(Method) | ||
| 123 | - | ||
| 124 | -public: | ||
| 125 | - /*!< */ | ||
| 126 | - enum Method { Near = INTER_NEAREST, | ||
| 127 | - Area = INTER_AREA, | ||
| 128 | - Bilin = INTER_LINEAR, | ||
| 129 | - Cubic = INTER_CUBIC, | ||
| 130 | - Lanczo = INTER_LANCZOS4}; | ||
| 131 | - | ||
| 132 | -private: | ||
| 133 | - Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | ||
| 134 | - Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | ||
| 135 | - Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) | ||
| 136 | - Q_PROPERTY(bool preserveAspect READ get_preserveAspect WRITE set_preserveAspect RESET reset_preserveAspect STORED false) | ||
| 137 | - BR_PROPERTY(int, rows, -1) | ||
| 138 | - BR_PROPERTY(int, columns, -1) | ||
| 139 | - BR_PROPERTY(Method, method, Bilin) | ||
| 140 | - BR_PROPERTY(bool, preserveAspect, false) | ||
| 141 | - | ||
| 142 | - void project(const Template &src, Template &dst) const | ||
| 143 | - { | ||
| 144 | - if (!preserveAspect) | ||
| 145 | - resize(src, dst, Size((columns == -1) ? src.m().cols*rows/src.m().rows : columns, rows), 0, 0, method); | ||
| 146 | - else { | ||
| 147 | - float inRatio = (float) src.m().rows / src.m().cols; | ||
| 148 | - float outRatio = (float) rows / columns; | ||
| 149 | - dst = Mat::zeros(rows, columns, src.m().type()); | ||
| 150 | - if (outRatio > inRatio) { | ||
| 151 | - float heightAR = src.m().rows * inRatio / outRatio; | ||
| 152 | - Mat buffer; | ||
| 153 | - resize(src, buffer, Size(columns, heightAR), 0, 0, method); | ||
| 154 | - buffer.copyTo(dst.m()(Rect(0, (rows - heightAR) / 2, columns, heightAR))); | ||
| 155 | - } else { | ||
| 156 | - float widthAR = src.m().cols / inRatio * outRatio; | ||
| 157 | - Mat buffer; | ||
| 158 | - resize(src, buffer, Size(widthAR, rows), 0, 0, method); | ||
| 159 | - buffer.copyTo(dst.m()(Rect((columns - widthAR) / 2, 0, widthAR, rows))); | ||
| 160 | - } | ||
| 161 | - } | ||
| 162 | - } | ||
| 163 | -}; | ||
| 164 | - | ||
| 165 | -BR_REGISTER(Transform, ResizeTransform) | ||
| 166 | - | ||
| 167 | -/*! | ||
| 168 | - * \ingroup transforms | ||
| 169 | - * \brief Limit the size of the template | ||
| 170 | - * \author Josh Klontz \cite jklontz | ||
| 171 | - */ | ||
| 172 | -class LimitSizeTransform : public UntrainableTransform | ||
| 173 | -{ | ||
| 174 | - Q_OBJECT | ||
| 175 | - Q_PROPERTY(int max READ get_max WRITE set_max RESET reset_max STORED false) | ||
| 176 | - BR_PROPERTY(int, max, -1) | ||
| 177 | - | ||
| 178 | - void project(const Template &src, Template &dst) const | ||
| 179 | - { | ||
| 180 | - const Mat &m = src; | ||
| 181 | - if (m.rows > m.cols) | ||
| 182 | - if (m.rows > max) resize(m, dst, Size(std::max(1, m.cols * max / m.rows), max)); | ||
| 183 | - else dst = m; | ||
| 184 | - else | ||
| 185 | - if (m.cols > max) resize(m, dst, Size(max, std::max(1, m.rows * max / m.cols))); | ||
| 186 | - else dst = m; | ||
| 187 | - } | ||
| 188 | -}; | ||
| 189 | - | ||
| 190 | -BR_REGISTER(Transform, LimitSizeTransform) | ||
| 191 | - | ||
| 192 | -/*! | ||
| 193 | - * \ingroup transforms | ||
| 194 | - * \brief Enforce a multiple of \em n columns. | ||
| 195 | - * \author Josh Klontz \cite jklontz | ||
| 196 | - */ | ||
| 197 | -class DivTransform : public UntrainableTransform | ||
| 198 | -{ | ||
| 199 | - Q_OBJECT | ||
| 200 | - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | ||
| 201 | - BR_PROPERTY(int, n, 1) | ||
| 202 | - | ||
| 203 | - void project(const Template &src, Template &dst) const | ||
| 204 | - { | ||
| 205 | - dst = Mat(src, Rect(0,0,n*(src.m().cols/n),src.m().rows)); | ||
| 206 | - } | ||
| 207 | -}; | ||
| 208 | - | ||
| 209 | -BR_REGISTER(Transform, DivTransform) | ||
| 210 | - | ||
| 211 | -/*! | ||
| 212 | - * \ingroup transforms | ||
| 213 | - * \brief Crop out black borders | ||
| 214 | - * \author Josh Klontz \cite jklontz | ||
| 215 | - */ | ||
| 216 | -class CropBlackTransform : public UntrainableTransform | ||
| 217 | -{ | ||
| 218 | - Q_OBJECT | ||
| 219 | - | ||
| 220 | - void project(const Template &src, Template &dst) const | ||
| 221 | - { | ||
| 222 | - Mat gray; | ||
| 223 | - OpenCVUtils::cvtGray(src, gray); | ||
| 224 | - | ||
| 225 | - int xStart = 0; | ||
| 226 | - while (xStart < gray.cols) { | ||
| 227 | - if (mean(gray.col(xStart))[0] >= 1) break; | ||
| 228 | - xStart++; | ||
| 229 | - } | ||
| 230 | - | ||
| 231 | - int xEnd = gray.cols - 1; | ||
| 232 | - while (xEnd >= 0) { | ||
| 233 | - if (mean(gray.col(xEnd))[0] >= 1) break; | ||
| 234 | - xEnd--; | ||
| 235 | - } | ||
| 236 | - | ||
| 237 | - int yStart = 0; | ||
| 238 | - while (yStart < gray.rows) { | ||
| 239 | - if (mean(gray.col(yStart))[0] >= 1) break; | ||
| 240 | - yStart++; | ||
| 241 | - } | ||
| 242 | - | ||
| 243 | - int yEnd = gray.rows - 1; | ||
| 244 | - while (yEnd >= 0) { | ||
| 245 | - if (mean(gray.col(yEnd))[0] >= 1) break; | ||
| 246 | - yEnd--; | ||
| 247 | - } | ||
| 248 | - | ||
| 249 | - dst = src.m()(Rect(xStart, yStart, xEnd-xStart, yEnd-yStart)); | ||
| 250 | - } | ||
| 251 | -}; | ||
| 252 | - | ||
| 253 | -BR_REGISTER(Transform, CropBlackTransform) | ||
| 254 | - | ||
| 255 | -/*! | ||
| 256 | - * \ingroup transforms | ||
| 257 | - * \brief Divide the matrix into 4 smaller matricies of equal size. | ||
| 258 | - * \author Josh Klontz \cite jklontz | ||
| 259 | - */ | ||
| 260 | -class SubdivideTransform : public UntrainableTransform | ||
| 261 | -{ | ||
| 262 | - Q_OBJECT | ||
| 263 | - | ||
| 264 | - void project(const Template &src, Template &dst) const | ||
| 265 | - { | ||
| 266 | - const Mat &m = src; | ||
| 267 | - const int subrows = m.rows/2; | ||
| 268 | - const int subcolumns = m.cols/2; | ||
| 269 | - dst.append(Mat(m,Rect(0, 0, subcolumns, subrows)).clone()); | ||
| 270 | - dst.append(Mat(m,Rect(subcolumns, 0, subcolumns, subrows)).clone()); | ||
| 271 | - dst.append(Mat(m,Rect(0, subrows, subcolumns, subrows)).clone()); | ||
| 272 | - dst.append(Mat(m,Rect(subcolumns, subrows, subcolumns, subrows)).clone()); | ||
| 273 | - } | ||
| 274 | -}; | ||
| 275 | - | ||
| 276 | -BR_REGISTER(Transform, SubdivideTransform) | ||
| 277 | - | ||
| 278 | -/*! | ||
| 279 | - * \ingroup transforms | ||
| 280 | - * \brief Trim the image so the width and the height are the same size. | ||
| 281 | - * \author Josh Klontz \cite jklontz | ||
| 282 | - */ | ||
| 283 | -class CropSquareTransform : public UntrainableTransform | ||
| 284 | -{ | ||
| 285 | - Q_OBJECT | ||
| 286 | - | ||
| 287 | - void project(const Template &src, Template &dst) const | ||
| 288 | - { | ||
| 289 | - const Mat &m = src; | ||
| 290 | - const int newSize = min(m.rows, m.cols); | ||
| 291 | - dst = Mat(m, Rect((m.cols-newSize)/2, (m.rows-newSize)/2, newSize, newSize)); | ||
| 292 | - } | ||
| 293 | -}; | ||
| 294 | - | ||
| 295 | -BR_REGISTER(Transform, CropSquareTransform) | ||
| 296 | - | ||
| 297 | -} // namespace br | ||
| 298 | - | ||
| 299 | -#include "crop.moc" |
openbr/plugins/cvt.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 19 | -#include "openbr_internal.h" | ||
| 20 | -#include "openbr/core/opencvutils.h" | ||
| 21 | - | ||
| 22 | -using namespace cv; | ||
| 23 | - | ||
| 24 | -namespace br | ||
| 25 | -{ | ||
| 26 | - | ||
| 27 | -/*! | ||
| 28 | - * \ingroup transforms | ||
| 29 | - * \brief Colorspace conversion. | ||
| 30 | - * \author Josh Klontz \cite jklontz | ||
| 31 | - */ | ||
| 32 | -class CvtTransform : public UntrainableTransform | ||
| 33 | -{ | ||
| 34 | - Q_OBJECT | ||
| 35 | - Q_ENUMS(ColorSpace) | ||
| 36 | - Q_PROPERTY(ColorSpace colorSpace READ get_colorSpace WRITE set_colorSpace RESET reset_colorSpace STORED false) | ||
| 37 | - Q_PROPERTY(int channel READ get_channel WRITE set_channel RESET reset_channel STORED false) | ||
| 38 | - | ||
| 39 | -public: | ||
| 40 | - enum ColorSpace { Gray = CV_BGR2GRAY, | ||
| 41 | - RGBGray = CV_RGB2GRAY, | ||
| 42 | - HLS = CV_BGR2HLS, | ||
| 43 | - HSV = CV_BGR2HSV, | ||
| 44 | - Lab = CV_BGR2Lab, | ||
| 45 | - Luv = CV_BGR2Luv, | ||
| 46 | - RGB = CV_BGR2RGB, | ||
| 47 | - XYZ = CV_BGR2XYZ, | ||
| 48 | - YCrCb = CV_BGR2YCrCb, | ||
| 49 | - Color = CV_GRAY2BGR }; | ||
| 50 | - | ||
| 51 | -private: | ||
| 52 | - BR_PROPERTY(ColorSpace, colorSpace, Gray) | ||
| 53 | - BR_PROPERTY(int, channel, -1) | ||
| 54 | - | ||
| 55 | - void project(const Template &src, Template &dst) const | ||
| 56 | - { | ||
| 57 | - if (src.m().channels() > 1 || colorSpace == CV_GRAY2BGR) cvtColor(src, dst, colorSpace); | ||
| 58 | - else dst = src; | ||
| 59 | - | ||
| 60 | - if (channel != -1) { | ||
| 61 | - std::vector<Mat> mv; | ||
| 62 | - split(dst, mv); | ||
| 63 | - dst = mv[channel % (int)mv.size()]; | ||
| 64 | - } | ||
| 65 | - } | ||
| 66 | -}; | ||
| 67 | - | ||
| 68 | -BR_REGISTER(Transform, CvtTransform) | ||
| 69 | - | ||
| 70 | -/*! | ||
| 71 | - * \ingroup transforms | ||
| 72 | - * \brief Convert to floating point format. | ||
| 73 | - * \author Josh Klontz \cite jklontz | ||
| 74 | - */ | ||
| 75 | -class CvtFloatTransform : public UntrainableTransform | ||
| 76 | -{ | ||
| 77 | - Q_OBJECT | ||
| 78 | - | ||
| 79 | - void project(const Template &src, Template &dst) const | ||
| 80 | - { | ||
| 81 | - src.m().convertTo(dst, CV_32F); | ||
| 82 | - } | ||
| 83 | -}; | ||
| 84 | - | ||
| 85 | -BR_REGISTER(Transform, CvtFloatTransform) | ||
| 86 | - | ||
| 87 | -/*! | ||
| 88 | - * \ingroup transforms | ||
| 89 | - * \brief Convert to uchar format | ||
| 90 | - * \author Josh Klontz \cite jklontz | ||
| 91 | - */ | ||
| 92 | -class CvtUCharTransform : public UntrainableTransform | ||
| 93 | -{ | ||
| 94 | - Q_OBJECT | ||
| 95 | - | ||
| 96 | - void project(const Template &src, Template &dst) const | ||
| 97 | - { | ||
| 98 | - OpenCVUtils::cvtUChar(src, dst); | ||
| 99 | - } | ||
| 100 | -}; | ||
| 101 | - | ||
| 102 | -BR_REGISTER(Transform, CvtUCharTransform) | ||
| 103 | - | ||
| 104 | -/*! | ||
| 105 | - * \ingroup transforms | ||
| 106 | - * \brief Scales using the given factor | ||
| 107 | - * \author Scott Klum \cite sklum | ||
| 108 | - */ | ||
| 109 | -class ScaleTransform : public UntrainableTransform | ||
| 110 | -{ | ||
| 111 | - Q_OBJECT | ||
| 112 | - | ||
| 113 | - Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) | ||
| 114 | - BR_PROPERTY(float, scaleFactor, 1.) | ||
| 115 | - | ||
| 116 | - void project(const Template &src, Template &dst) const | ||
| 117 | - { | ||
| 118 | - resize(src, dst, Size(src.m().cols*scaleFactor,src.m().rows*scaleFactor)); | ||
| 119 | - } | ||
| 120 | -}; | ||
| 121 | - | ||
| 122 | -BR_REGISTER(Transform, ScaleTransform) | ||
| 123 | - | ||
| 124 | -/*! | ||
| 125 | - * \ingroup transforms | ||
| 126 | - * \brief Split a multi-channel matrix into several single-channel matrices. | ||
| 127 | - * \author Josh Klontz \cite jklontz | ||
| 128 | - */ | ||
| 129 | -class SplitChannelsTransform : public UntrainableTransform | ||
| 130 | -{ | ||
| 131 | - Q_OBJECT | ||
| 132 | - | ||
| 133 | - void project(const Template &src, Template &dst) const | ||
| 134 | - { | ||
| 135 | - std::vector<Mat> mv; | ||
| 136 | - split(src, mv); | ||
| 137 | - foreach (const Mat &m, mv) | ||
| 138 | - dst += m; | ||
| 139 | - } | ||
| 140 | -}; | ||
| 141 | - | ||
| 142 | -BR_REGISTER(Transform, SplitChannelsTransform) | ||
| 143 | - | ||
| 144 | -/*! | ||
| 145 | - * \ingroup transforms | ||
| 146 | - * \brief Enforce the matrix has a certain number of channels by adding or removing channels. | ||
| 147 | - * \author Josh Klontz \cite jklontz | ||
| 148 | - */ | ||
| 149 | -class EnsureChannelsTransform : public UntrainableTransform | ||
| 150 | -{ | ||
| 151 | - Q_OBJECT | ||
| 152 | - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | ||
| 153 | - BR_PROPERTY(int, n, 1) | ||
| 154 | - | ||
| 155 | - void project(const Template &src, Template &dst) const | ||
| 156 | - { | ||
| 157 | - if (src.m().channels() == n) { | ||
| 158 | - dst = src; | ||
| 159 | - } else { | ||
| 160 | - std::vector<Mat> mv; | ||
| 161 | - split(src, mv); | ||
| 162 | - | ||
| 163 | - // Add extra channels | ||
| 164 | - while ((int)mv.size() < n) { | ||
| 165 | - for (int i=0; i<src.m().channels(); i++) { | ||
| 166 | - mv.push_back(mv[i]); | ||
| 167 | - if ((int)mv.size() == n) | ||
| 168 | - break; | ||
| 169 | - } | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - // Remove extra channels | ||
| 173 | - while ((int)mv.size() > n) | ||
| 174 | - mv.pop_back(); | ||
| 175 | - | ||
| 176 | - merge(mv, dst); | ||
| 177 | - } | ||
| 178 | - } | ||
| 179 | -}; | ||
| 180 | - | ||
| 181 | -BR_REGISTER(Transform, EnsureChannelsTransform) | ||
| 182 | - | ||
| 183 | -/*! | ||
| 184 | - * \ingroup transforms | ||
| 185 | - * \brief Drop the alpha channel (if exists). | ||
| 186 | - * \author Austin Blanton \cite imaus10 | ||
| 187 | - */ | ||
| 188 | -class DiscardAlphaTransform : public UntrainableTransform | ||
| 189 | -{ | ||
| 190 | - Q_OBJECT | ||
| 191 | - | ||
| 192 | - void project(const Template &src, Template &dst) const | ||
| 193 | - { | ||
| 194 | - if (src.m().channels() > 4 || src.m().channels() == 2) { | ||
| 195 | - dst.file.fte = true; | ||
| 196 | - return; | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | - dst = src; | ||
| 200 | - if (src.m().channels() == 4) { | ||
| 201 | - std::vector<Mat> mv; | ||
| 202 | - split(src, mv); | ||
| 203 | - mv.pop_back(); | ||
| 204 | - merge(mv, dst); | ||
| 205 | - } | ||
| 206 | - } | ||
| 207 | -}; | ||
| 208 | - | ||
| 209 | -BR_REGISTER(Transform, DiscardAlphaTransform) | ||
| 210 | - | ||
| 211 | -/*! | ||
| 212 | - * \ingroup transforms | ||
| 213 | - * \brief Normalized RG color space. | ||
| 214 | - * \author Josh Klontz \cite jklontz | ||
| 215 | - */ | ||
| 216 | -class RGTransform : public UntrainableTransform | ||
| 217 | -{ | ||
| 218 | - Q_OBJECT | ||
| 219 | - | ||
| 220 | - void project(const Template &src, Template &dst) const | ||
| 221 | - { | ||
| 222 | - if (src.m().type() != CV_8UC3) | ||
| 223 | - qFatal("Expected CV_8UC3 images."); | ||
| 224 | - | ||
| 225 | - const Mat &m = src.m(); | ||
| 226 | - Mat R(m.size(), CV_8UC1); // R / (R+G+B) | ||
| 227 | - Mat G(m.size(), CV_8UC1); // G / (R+G+B) | ||
| 228 | - | ||
| 229 | - for (int i=0; i<m.rows; i++) | ||
| 230 | - for (int j=0; j<m.cols; j++) { | ||
| 231 | - Vec3b v = m.at<Vec3b>(i,j); | ||
| 232 | - const int b = v[0]; | ||
| 233 | - const int g = v[1]; | ||
| 234 | - const int r = v[2]; | ||
| 235 | - const int sum = b + g + r; | ||
| 236 | - if (sum > 0) { | ||
| 237 | - R.at<uchar>(i, j) = saturate_cast<uchar>(255.0*r/(r+g+b)); | ||
| 238 | - G.at<uchar>(i, j) = saturate_cast<uchar>(255.0*g/(r+g+b)); | ||
| 239 | - } else { | ||
| 240 | - R.at<uchar>(i, j) = 0; | ||
| 241 | - G.at<uchar>(i, j) = 0; | ||
| 242 | - } | ||
| 243 | - } | ||
| 244 | - | ||
| 245 | - dst.append(R); | ||
| 246 | - dst.append(G); | ||
| 247 | - } | ||
| 248 | -}; | ||
| 249 | - | ||
| 250 | -BR_REGISTER(Transform, RGTransform) | ||
| 251 | - | ||
| 252 | -/*! | ||
| 253 | - * \ingroup transforms | ||
| 254 | - * \brief dst = a*src+b | ||
| 255 | - * \author Josh Klontz \cite jklontz | ||
| 256 | - */ | ||
| 257 | -class MAddTransform : public UntrainableTransform | ||
| 258 | -{ | ||
| 259 | - Q_OBJECT | ||
| 260 | - Q_PROPERTY(double a READ get_a WRITE set_a RESET reset_a STORED false) | ||
| 261 | - Q_PROPERTY(double b READ get_b WRITE set_b RESET reset_b STORED false) | ||
| 262 | - BR_PROPERTY(double, a, 1) | ||
| 263 | - BR_PROPERTY(double, b, 0) | ||
| 264 | - | ||
| 265 | - void project(const Template &src, Template &dst) const | ||
| 266 | - { | ||
| 267 | - src.m().convertTo(dst.m(), src.m().depth(), a, b); | ||
| 268 | - } | ||
| 269 | -}; | ||
| 270 | - | ||
| 271 | -BR_REGISTER(Transform, MAddTransform) | ||
| 272 | - | ||
| 273 | -/*! | ||
| 274 | - * \ingroup transforms | ||
| 275 | - * \brief Computes the absolute value of each element. | ||
| 276 | - * \author Josh Klontz \cite jklontz | ||
| 277 | - */ | ||
| 278 | -class AbsTransform : public UntrainableTransform | ||
| 279 | -{ | ||
| 280 | - Q_OBJECT | ||
| 281 | - | ||
| 282 | - void project(const Template &src, Template &dst) const | ||
| 283 | - { | ||
| 284 | - dst = abs(src); | ||
| 285 | - } | ||
| 286 | -}; | ||
| 287 | - | ||
| 288 | -BR_REGISTER(Transform, AbsTransform) | ||
| 289 | - | ||
| 290 | -} // namespace br | ||
| 291 | - | ||
| 292 | -#include "cvt.moc" |
openbr/plugins/cascade.cpp renamed to openbr/plugins/detection/cascade.cpp
| @@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/objdetect/objdetect.hpp> | 17 | #include <opencv2/objdetect/objdetect.hpp> |
| 18 | -#include "openbr_internal.h" | 18 | +#include <openbr/plugins/openbr_internal.h> |
| 19 | #include "openbr/core/opencvutils.h" | 19 | #include "openbr/core/opencvutils.h" |
| 20 | #include "openbr/core/resource.h" | 20 | #include "openbr/core/resource.h" |
| 21 | #include "openbr/core/qtutils.h" | 21 | #include "openbr/core/qtutils.h" |
openbr/plugins/eyes.cpp renamed to openbr/plugins/detection/eyes.cpp
| @@ -35,8 +35,9 @@ | @@ -35,8 +35,9 @@ | ||
| 35 | 35 | ||
| 36 | #include <opencv2/imgproc/imgproc.hpp> | 36 | #include <opencv2/imgproc/imgproc.hpp> |
| 37 | #include <opencv2/imgproc/imgproc_c.h> | 37 | #include <opencv2/imgproc/imgproc_c.h> |
| 38 | -#include "openbr_internal.h" | ||
| 39 | -#include "openbr/core/opencvutils.h" | 38 | + |
| 39 | +#include <openbr/plugins/openbr_internal.h> | ||
| 40 | +#include <openbr/core/opencvutils.h> | ||
| 40 | 41 | ||
| 41 | using namespace cv; | 42 | using namespace cv; |
| 42 | 43 |
openbr/plugins/detection/keypointdetector.cpp
0 → 100644
| 1 | +#include <opencv2/features2d/features2d.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | +#include <openbr/core/opencvutils.h> | ||
| 5 | + | ||
| 6 | +using namespace cv; | ||
| 7 | + | ||
| 8 | +namespace br | ||
| 9 | +{ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \ingroup transforms | ||
| 13 | + * \brief Wraps OpenCV Key Point Detector | ||
| 14 | + * \author Josh Klontz \cite jklontz | ||
| 15 | + */ | ||
| 16 | +class KeyPointDetectorTransform : public UntrainableTransform | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + Q_PROPERTY(QString detector READ get_detector WRITE set_detector RESET reset_detector STORED false) | ||
| 20 | + BR_PROPERTY(QString, detector, "SIFT") | ||
| 21 | + | ||
| 22 | + Ptr<FeatureDetector> featureDetector; | ||
| 23 | + | ||
| 24 | + void init() | ||
| 25 | + { | ||
| 26 | + featureDetector = FeatureDetector::create(detector.toStdString()); | ||
| 27 | + if (featureDetector.empty()) | ||
| 28 | + qFatal("Failed to create KeyPointDetector: %s", qPrintable(detector)); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + void project(const Template &src, Template &dst) const | ||
| 32 | + { | ||
| 33 | + dst = src; | ||
| 34 | + | ||
| 35 | + std::vector<KeyPoint> keyPoints; | ||
| 36 | + try { | ||
| 37 | + featureDetector->detect(src, keyPoints); | ||
| 38 | + } catch (...) { | ||
| 39 | + qWarning("Key point detection failed for file %s", qPrintable(src.file.name)); | ||
| 40 | + dst.file.fte = true; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + QList<Rect> rects; | ||
| 44 | + foreach (const KeyPoint &keyPoint, keyPoints) | ||
| 45 | + rects.append(Rect(keyPoint.pt.x-keyPoint.size/2, keyPoint.pt.y-keyPoint.size/2, keyPoint.size, keyPoint.size)); | ||
| 46 | + dst.file.setRects(OpenCVUtils::fromRects(rects)); | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +BR_REGISTER(Transform, KeyPointDetectorTransform) | ||
| 51 | + | ||
| 52 | +} // namespace br | ||
| 53 | + | ||
| 54 | +#include "keypointdetector.moc" |
openbr/plugins/distance.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <QFutureSynchronizer> | ||
| 18 | -#include <QtConcurrentRun> | ||
| 19 | -#include <numeric> | ||
| 20 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 21 | -#include <opencv2/imgproc/imgproc_c.h> | ||
| 22 | -#include "openbr_internal.h" | ||
| 23 | - | ||
| 24 | -#include "openbr/core/distance_sse.h" | ||
| 25 | -#include "openbr/core/qtutils.h" | ||
| 26 | -#include "openbr/core/opencvutils.h" | ||
| 27 | - | ||
| 28 | -using namespace cv; | ||
| 29 | - | ||
| 30 | -namespace br | ||
| 31 | -{ | ||
| 32 | - | ||
| 33 | -/*! | ||
| 34 | - * \ingroup distances | ||
| 35 | - * \brief Standard distance metrics | ||
| 36 | - * \author Josh Klontz \cite jklontz | ||
| 37 | - */ | ||
| 38 | -class DistDistance : public UntrainableDistance | ||
| 39 | -{ | ||
| 40 | - Q_OBJECT | ||
| 41 | - Q_ENUMS(Metric) | ||
| 42 | - Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false) | ||
| 43 | - Q_PROPERTY(bool negLogPlusOne READ get_negLogPlusOne WRITE set_negLogPlusOne RESET reset_negLogPlusOne STORED false) | ||
| 44 | - | ||
| 45 | -public: | ||
| 46 | - /*!< */ | ||
| 47 | - enum Metric { Correlation, | ||
| 48 | - ChiSquared, | ||
| 49 | - Intersection, | ||
| 50 | - Bhattacharyya, | ||
| 51 | - INF, | ||
| 52 | - L1, | ||
| 53 | - L2, | ||
| 54 | - Cosine, | ||
| 55 | - Dot}; | ||
| 56 | - | ||
| 57 | -private: | ||
| 58 | - BR_PROPERTY(Metric, metric, L2) | ||
| 59 | - BR_PROPERTY(bool, negLogPlusOne, true) | ||
| 60 | - | ||
| 61 | - float compare(const Mat &a, const Mat &b) const | ||
| 62 | - { | ||
| 63 | - if ((a.size != b.size) || | ||
| 64 | - (a.type() != b.type())) | ||
| 65 | - return -std::numeric_limits<float>::max(); | ||
| 66 | - | ||
| 67 | -// TODO: this max value is never returned based on the switch / default | ||
| 68 | - float result = std::numeric_limits<float>::max(); | ||
| 69 | - switch (metric) { | ||
| 70 | - case Correlation: | ||
| 71 | - return compareHist(a, b, CV_COMP_CORREL); | ||
| 72 | - case ChiSquared: | ||
| 73 | - result = compareHist(a, b, CV_COMP_CHISQR); | ||
| 74 | - break; | ||
| 75 | - case Intersection: | ||
| 76 | - result = compareHist(a, b, CV_COMP_INTERSECT); | ||
| 77 | - break; | ||
| 78 | - case Bhattacharyya: | ||
| 79 | - result = compareHist(a, b, CV_COMP_BHATTACHARYYA); | ||
| 80 | - break; | ||
| 81 | - case INF: | ||
| 82 | - result = norm(a, b, NORM_INF); | ||
| 83 | - break; | ||
| 84 | - case L1: | ||
| 85 | - result = norm(a, b, NORM_L1); | ||
| 86 | - break; | ||
| 87 | - case L2: | ||
| 88 | - result = norm(a, b, NORM_L2); | ||
| 89 | - break; | ||
| 90 | - case Cosine: | ||
| 91 | - return cosine(a, b); | ||
| 92 | - case Dot: | ||
| 93 | - return a.dot(b); | ||
| 94 | - default: | ||
| 95 | - qFatal("Invalid metric"); | ||
| 96 | - } | ||
| 97 | - | ||
| 98 | - if (result != result) | ||
| 99 | - qFatal("NaN result."); | ||
| 100 | - | ||
| 101 | - return negLogPlusOne ? -log(result+1) : result; | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - static float cosine(const Mat &a, const Mat &b) | ||
| 105 | - { | ||
| 106 | - float dot = 0; | ||
| 107 | - float magA = 0; | ||
| 108 | - float magB = 0; | ||
| 109 | - | ||
| 110 | - for (int row=0; row<a.rows; row++) { | ||
| 111 | - for (int col=0; col<a.cols; col++) { | ||
| 112 | - const float target = a.at<float>(row,col); | ||
| 113 | - const float query = b.at<float>(row,col); | ||
| 114 | - dot += target * query; | ||
| 115 | - magA += target * target; | ||
| 116 | - magB += query * query; | ||
| 117 | - } | ||
| 118 | - } | ||
| 119 | - | ||
| 120 | - return dot / (sqrt(magA)*sqrt(magB)); | ||
| 121 | - } | ||
| 122 | -}; | ||
| 123 | - | ||
| 124 | -BR_REGISTER(Distance, DistDistance) | ||
| 125 | - | ||
| 126 | -/*! | ||
| 127 | - * \ingroup distances | ||
| 128 | - * \brief DistDistance wrapper. | ||
| 129 | - * \author Josh Klontz \cite jklontz | ||
| 130 | - */ | ||
| 131 | -class DefaultDistance : public UntrainableDistance | ||
| 132 | -{ | ||
| 133 | - Q_OBJECT | ||
| 134 | - Distance *distance; | ||
| 135 | - | ||
| 136 | - void init() | ||
| 137 | - { | ||
| 138 | - distance = Distance::make("Dist("+file.suffix()+")"); | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - float compare(const cv::Mat &a, const cv::Mat &b) const | ||
| 142 | - { | ||
| 143 | - return distance->compare(a, b); | ||
| 144 | - } | ||
| 145 | -}; | ||
| 146 | - | ||
| 147 | -BR_REGISTER(Distance, DefaultDistance) | ||
| 148 | - | ||
| 149 | -/*! | ||
| 150 | - * \ingroup distances | ||
| 151 | - * \brief Distances in series. | ||
| 152 | - * \author Josh Klontz \cite jklontz | ||
| 153 | - * | ||
| 154 | - * The templates are compared using each br::Distance in order. | ||
| 155 | - * If the result of the comparison with any given distance is -FLOAT_MAX then this result is returned early. | ||
| 156 | - * Otherwise the returned result is the value of comparing the templates using the last br::Distance. | ||
| 157 | - */ | ||
| 158 | -class PipeDistance : public Distance | ||
| 159 | -{ | ||
| 160 | - Q_OBJECT | ||
| 161 | - Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | ||
| 162 | - BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | ||
| 163 | - | ||
| 164 | - void train(const TemplateList &data) | ||
| 165 | - { | ||
| 166 | - QFutureSynchronizer<void> futures; | ||
| 167 | - foreach (br::Distance *distance, distances) | ||
| 168 | - futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | ||
| 169 | - futures.waitForFinished(); | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - float compare(const Template &a, const Template &b) const | ||
| 173 | - { | ||
| 174 | - float result = -std::numeric_limits<float>::max(); | ||
| 175 | - foreach (br::Distance *distance, distances) { | ||
| 176 | - result = distance->compare(a, b); | ||
| 177 | - if (result == -std::numeric_limits<float>::max()) | ||
| 178 | - return result; | ||
| 179 | - } | ||
| 180 | - return result; | ||
| 181 | - } | ||
| 182 | -}; | ||
| 183 | - | ||
| 184 | -BR_REGISTER(Distance, PipeDistance) | ||
| 185 | - | ||
| 186 | -/*! | ||
| 187 | - * \ingroup distances | ||
| 188 | - * \brief Fuses similarity scores across multiple matrices of compared templates | ||
| 189 | - * \author Scott Klum \cite sklum | ||
| 190 | - * \note Operation: Mean, sum, min, max are supported. | ||
| 191 | - */ | ||
| 192 | -class FuseDistance : public Distance | ||
| 193 | -{ | ||
| 194 | - Q_OBJECT | ||
| 195 | - Q_ENUMS(Operation) | ||
| 196 | - Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | ||
| 197 | - Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false) | ||
| 198 | - Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false) | ||
| 199 | - | ||
| 200 | - QList<br::Distance*> distances; | ||
| 201 | - | ||
| 202 | -public: | ||
| 203 | - /*!< */ | ||
| 204 | - enum Operation {Mean, Sum, Max, Min}; | ||
| 205 | - | ||
| 206 | -private: | ||
| 207 | - BR_PROPERTY(QString, description, "L2") | ||
| 208 | - BR_PROPERTY(Operation, operation, Mean) | ||
| 209 | - BR_PROPERTY(QList<float>, weights, QList<float>()) | ||
| 210 | - | ||
| 211 | - void train(const TemplateList &src) | ||
| 212 | - { | ||
| 213 | - // Partition the templates by matrix | ||
| 214 | - QList<int> split; | ||
| 215 | - for (int i=0; i<src.at(0).size(); i++) split.append(1); | ||
| 216 | - | ||
| 217 | - QList<TemplateList> partitionedSrc = src.partition(split); | ||
| 218 | - | ||
| 219 | - while (distances.size() < partitionedSrc.size()) | ||
| 220 | - distances.append(make(description)); | ||
| 221 | - | ||
| 222 | - // Train on each of the partitions | ||
| 223 | - for (int i=0; i<distances.size(); i++) | ||
| 224 | - distances[i]->train(partitionedSrc[i]); | ||
| 225 | - } | ||
| 226 | - | ||
| 227 | - float compare(const Template &a, const Template &b) const | ||
| 228 | - { | ||
| 229 | - if (a.size() != b.size()) qFatal("Comparison size mismatch"); | ||
| 230 | - | ||
| 231 | - QList<float> scores; | ||
| 232 | - for (int i=0; i<distances.size(); i++) { | ||
| 233 | - float weight; | ||
| 234 | - weights.isEmpty() ? weight = 1. : weight = weights[i]; | ||
| 235 | - scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i]))); | ||
| 236 | - } | ||
| 237 | - | ||
| 238 | - switch (operation) { | ||
| 239 | - case Mean: | ||
| 240 | - return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size(); | ||
| 241 | - break; | ||
| 242 | - case Sum: | ||
| 243 | - return std::accumulate(scores.begin(),scores.end(),0.0); | ||
| 244 | - break; | ||
| 245 | - case Min: | ||
| 246 | - return *std::min_element(scores.begin(),scores.end()); | ||
| 247 | - break; | ||
| 248 | - case Max: | ||
| 249 | - return *std::max_element(scores.begin(),scores.end()); | ||
| 250 | - break; | ||
| 251 | - default: | ||
| 252 | - qFatal("Invalid operation."); | ||
| 253 | - } | ||
| 254 | - return 0; | ||
| 255 | - } | ||
| 256 | - | ||
| 257 | - void store(QDataStream &stream) const | ||
| 258 | - { | ||
| 259 | - stream << distances.size(); | ||
| 260 | - foreach (Distance *distance, distances) | ||
| 261 | - distance->store(stream); | ||
| 262 | - } | ||
| 263 | - | ||
| 264 | - void load(QDataStream &stream) | ||
| 265 | - { | ||
| 266 | - int numDistances; | ||
| 267 | - stream >> numDistances; | ||
| 268 | - while (distances.size() < numDistances) | ||
| 269 | - distances.append(make(description)); | ||
| 270 | - foreach (Distance *distance, distances) | ||
| 271 | - distance->load(stream); | ||
| 272 | - } | ||
| 273 | -}; | ||
| 274 | - | ||
| 275 | -BR_REGISTER(Distance, FuseDistance) | ||
| 276 | - | ||
| 277 | -/*! | ||
| 278 | - * \ingroup distances | ||
| 279 | - * \brief Fast 8-bit L1 distance | ||
| 280 | - * \author Josh Klontz \cite jklontz | ||
| 281 | - */ | ||
| 282 | -class ByteL1Distance : public UntrainableDistance | ||
| 283 | -{ | ||
| 284 | - Q_OBJECT | ||
| 285 | - | ||
| 286 | - float compare(const unsigned char *a, const unsigned char *b, size_t size) const | ||
| 287 | - { | ||
| 288 | - return l1(a, b, size); | ||
| 289 | - } | ||
| 290 | -}; | ||
| 291 | - | ||
| 292 | -BR_REGISTER(Distance, ByteL1Distance) | ||
| 293 | - | ||
| 294 | -/*! | ||
| 295 | - * \ingroup distances | ||
| 296 | - * \brief Fast 4-bit L1 distance | ||
| 297 | - * \author Josh Klontz \cite jklontz | ||
| 298 | - */ | ||
| 299 | -class HalfByteL1Distance : public UntrainableDistance | ||
| 300 | -{ | ||
| 301 | - Q_OBJECT | ||
| 302 | - | ||
| 303 | - float compare(const Mat &a, const Mat &b) const | ||
| 304 | - { | ||
| 305 | - return packed_l1(a.data, b.data, a.total()); | ||
| 306 | - } | ||
| 307 | -}; | ||
| 308 | - | ||
| 309 | -BR_REGISTER(Distance, HalfByteL1Distance) | ||
| 310 | - | ||
| 311 | -/*! | ||
| 312 | - * \ingroup distances | ||
| 313 | - * \brief Returns -log(distance(a,b)+1) | ||
| 314 | - * \author Josh Klontz \cite jklontz | ||
| 315 | - */ | ||
| 316 | -class NegativeLogPlusOneDistance : public UntrainableDistance | ||
| 317 | -{ | ||
| 318 | - Q_OBJECT | ||
| 319 | - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 320 | - BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 321 | - | ||
| 322 | - void train(const TemplateList &src) | ||
| 323 | - { | ||
| 324 | - distance->train(src); | ||
| 325 | - } | ||
| 326 | - | ||
| 327 | - float compare(const Template &a, const Template &b) const | ||
| 328 | - { | ||
| 329 | - return -log(distance->compare(a,b)+1); | ||
| 330 | - } | ||
| 331 | - | ||
| 332 | - void store(QDataStream &stream) const | ||
| 333 | - { | ||
| 334 | - distance->store(stream); | ||
| 335 | - } | ||
| 336 | - | ||
| 337 | - void load(QDataStream &stream) | ||
| 338 | - { | ||
| 339 | - distance->load(stream); | ||
| 340 | - } | ||
| 341 | -}; | ||
| 342 | - | ||
| 343 | -BR_REGISTER(Distance, NegativeLogPlusOneDistance) | ||
| 344 | - | ||
| 345 | -/*! | ||
| 346 | - * \ingroup distances | ||
| 347 | - * \brief Returns \c true if the templates are identical, \c false otherwise. | ||
| 348 | - * \author Josh Klontz \cite jklontz | ||
| 349 | - */ | ||
| 350 | -class IdenticalDistance : public UntrainableDistance | ||
| 351 | -{ | ||
| 352 | - Q_OBJECT | ||
| 353 | - | ||
| 354 | - float compare(const Mat &a, const Mat &b) const | ||
| 355 | - { | ||
| 356 | - const size_t size = a.total() * a.elemSize(); | ||
| 357 | - if (size != b.total() * b.elemSize()) return 0; | ||
| 358 | - for (size_t i=0; i<size; i++) | ||
| 359 | - if (a.data[i] != b.data[i]) return 0; | ||
| 360 | - return 1; | ||
| 361 | - } | ||
| 362 | -}; | ||
| 363 | - | ||
| 364 | -BR_REGISTER(Distance, IdenticalDistance) | ||
| 365 | - | ||
| 366 | -/*! | ||
| 367 | - * \ingroup distances | ||
| 368 | - * \brief Online distance metric to attenuate match scores across multiple frames | ||
| 369 | - * \author Brendan klare \cite bklare | ||
| 370 | - */ | ||
| 371 | -class OnlineDistance : public UntrainableDistance | ||
| 372 | -{ | ||
| 373 | - Q_OBJECT | ||
| 374 | - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 375 | - Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | ||
| 376 | - BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 377 | - BR_PROPERTY(float, alpha, 0.1f) | ||
| 378 | - | ||
| 379 | - mutable QHash<QString,float> scoreHash; | ||
| 380 | - mutable QMutex mutex; | ||
| 381 | - | ||
| 382 | - float compare(const Template &target, const Template &query) const | ||
| 383 | - { | ||
| 384 | - float currentScore = distance->compare(target, query); | ||
| 385 | - | ||
| 386 | - QMutexLocker mutexLocker(&mutex); | ||
| 387 | - return scoreHash[target.file.name] = (1.0- alpha) * scoreHash[target.file.name] + alpha * currentScore; | ||
| 388 | - } | ||
| 389 | -}; | ||
| 390 | - | ||
| 391 | -BR_REGISTER(Distance, OnlineDistance) | ||
| 392 | - | ||
| 393 | -/*! | ||
| 394 | - * \ingroup distances | ||
| 395 | - * \brief Attenuation function based distance from attributes | ||
| 396 | - * \author Scott Klum \cite sklum | ||
| 397 | - */ | ||
| 398 | -class AttributeDistance : public UntrainableDistance | ||
| 399 | -{ | ||
| 400 | - Q_OBJECT | ||
| 401 | - Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false) | ||
| 402 | - BR_PROPERTY(QString, attribute, QString()) | ||
| 403 | - | ||
| 404 | - float compare(const Template &target, const Template &query) const | ||
| 405 | - { | ||
| 406 | - float queryValue = query.file.get<float>(attribute); | ||
| 407 | - float targetValue = target.file.get<float>(attribute); | ||
| 408 | - | ||
| 409 | - // TODO: Set this magic number to something meaningful | ||
| 410 | - float stddev = 1; | ||
| 411 | - | ||
| 412 | - if (queryValue == targetValue) return 1; | ||
| 413 | - else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2)); | ||
| 414 | - } | ||
| 415 | -}; | ||
| 416 | - | ||
| 417 | -BR_REGISTER(Distance, AttributeDistance) | ||
| 418 | - | ||
| 419 | -/*! | ||
| 420 | - * \ingroup distances | ||
| 421 | - * \brief Sum match scores across multiple distances | ||
| 422 | - * \author Scott Klum \cite sklum | ||
| 423 | - */ | ||
| 424 | -class SumDistance : public UntrainableDistance | ||
| 425 | -{ | ||
| 426 | - Q_OBJECT | ||
| 427 | - Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | ||
| 428 | - BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | ||
| 429 | - | ||
| 430 | - void train(const TemplateList &data) | ||
| 431 | - { | ||
| 432 | - QFutureSynchronizer<void> futures; | ||
| 433 | - foreach (br::Distance *distance, distances) | ||
| 434 | - futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | ||
| 435 | - futures.waitForFinished(); | ||
| 436 | - } | ||
| 437 | - | ||
| 438 | - float compare(const Template &target, const Template &query) const | ||
| 439 | - { | ||
| 440 | - float result = 0; | ||
| 441 | - | ||
| 442 | - foreach (br::Distance *distance, distances) { | ||
| 443 | - result += distance->compare(target, query); | ||
| 444 | - | ||
| 445 | - if (result == -std::numeric_limits<float>::max()) | ||
| 446 | - return result; | ||
| 447 | - } | ||
| 448 | - | ||
| 449 | - return result; | ||
| 450 | - } | ||
| 451 | -}; | ||
| 452 | - | ||
| 453 | -BR_REGISTER(Distance, SumDistance) | ||
| 454 | - | ||
| 455 | -/*! | ||
| 456 | - * \ingroup transforms | ||
| 457 | - * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance. | ||
| 458 | - * dst will contain a 1 by n vector of scores. | ||
| 459 | - * \author Charles Otto \cite caotto | ||
| 460 | - */ | ||
| 461 | -class GalleryCompareTransform : public Transform | ||
| 462 | -{ | ||
| 463 | - Q_OBJECT | ||
| 464 | - Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true) | ||
| 465 | - Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) | ||
| 466 | - BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 467 | - BR_PROPERTY(QString, galleryName, "") | ||
| 468 | - | ||
| 469 | - TemplateList gallery; | ||
| 470 | - | ||
| 471 | - void project(const Template &src, Template &dst) const | ||
| 472 | - { | ||
| 473 | - dst = src; | ||
| 474 | - if (gallery.isEmpty()) | ||
| 475 | - return; | ||
| 476 | - | ||
| 477 | - QList<float> line = distance->compare(gallery, src); | ||
| 478 | - dst.m() = OpenCVUtils::toMat(line, 1); | ||
| 479 | - } | ||
| 480 | - | ||
| 481 | - void init() | ||
| 482 | - { | ||
| 483 | - if (!galleryName.isEmpty()) | ||
| 484 | - gallery = TemplateList::fromGallery(galleryName); | ||
| 485 | - } | ||
| 486 | - | ||
| 487 | - void train(const TemplateList &data) | ||
| 488 | - { | ||
| 489 | - gallery = data; | ||
| 490 | - } | ||
| 491 | - | ||
| 492 | - void store(QDataStream &stream) const | ||
| 493 | - { | ||
| 494 | - br::Object::store(stream); | ||
| 495 | - stream << gallery; | ||
| 496 | - } | ||
| 497 | - | ||
| 498 | - void load(QDataStream &stream) | ||
| 499 | - { | ||
| 500 | - br::Object::load(stream); | ||
| 501 | - stream >> gallery; | ||
| 502 | - } | ||
| 503 | - | ||
| 504 | -public: | ||
| 505 | - GalleryCompareTransform() : Transform(false, true) {} | ||
| 506 | -}; | ||
| 507 | - | ||
| 508 | -BR_REGISTER(Transform, GalleryCompareTransform) | ||
| 509 | - | ||
| 510 | - | ||
| 511 | -} // namespace br | ||
| 512 | -#include "distance.moc" |
openbr/plugins/distance/L2.cpp
0 → 100644
| 1 | +#include <Eigen/Dense> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup distances | ||
| 10 | + * \brief L2 distance computed using eigen. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class L2Distance : public UntrainableDistance | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + float compare(const cv::Mat &a, const cv::Mat &b) const | ||
| 18 | + { | ||
| 19 | + const int size = a.rows * a.cols; | ||
| 20 | + Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | ||
| 21 | + Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | ||
| 22 | + return (aMap-bMap).squaredNorm(); | ||
| 23 | + } | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +BR_REGISTER(Distance, L2Distance) | ||
| 27 | + | ||
| 28 | +} // namespace br | ||
| 29 | + | ||
| 30 | +#include "L2.moc" |
openbr/plugins/distance/attribute.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup distances | ||
| 8 | + * \brief Attenuation function based distance from attributes | ||
| 9 | + * \author Scott Klum \cite sklum | ||
| 10 | + */ | ||
| 11 | +class AttributeDistance : public UntrainableDistance | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false) | ||
| 15 | + BR_PROPERTY(QString, attribute, QString()) | ||
| 16 | + | ||
| 17 | + float compare(const Template &target, const Template &query) const | ||
| 18 | + { | ||
| 19 | + float queryValue = query.file.get<float>(attribute); | ||
| 20 | + float targetValue = target.file.get<float>(attribute); | ||
| 21 | + | ||
| 22 | + // TODO: Set this magic number to something meaningful | ||
| 23 | + float stddev = 1; | ||
| 24 | + | ||
| 25 | + if (queryValue == targetValue) return 1; | ||
| 26 | + else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2)); | ||
| 27 | + } | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +BR_REGISTER(Distance, AttributeDistance) | ||
| 31 | + | ||
| 32 | +} // namespace br | ||
| 33 | + | ||
| 34 | +#include "attribute.moc" |
openbr/plugins/distance/byteL1.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/distance_sse.h> | ||
| 3 | + | ||
| 4 | +namespace br | ||
| 5 | +{ | ||
| 6 | + | ||
| 7 | +/*! | ||
| 8 | + * \ingroup distances | ||
| 9 | + * \brief Fast 8-bit L1 distance | ||
| 10 | + * \author Josh Klontz \cite jklontz | ||
| 11 | + */ | ||
| 12 | +class ByteL1Distance : public UntrainableDistance | ||
| 13 | +{ | ||
| 14 | + Q_OBJECT | ||
| 15 | + | ||
| 16 | + float compare(const unsigned char *a, const unsigned char *b, size_t size) const | ||
| 17 | + { | ||
| 18 | + return l1(a, b, size); | ||
| 19 | + } | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +BR_REGISTER(Distance, ByteL1Distance) | ||
| 23 | + | ||
| 24 | +} // namespace br | ||
| 25 | + | ||
| 26 | +#include "byteL1.moc" |
openbr/plugins/distance/default.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup distances | ||
| 8 | + * \brief DistDistance wrapper. | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class DefaultDistance : public UntrainableDistance | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Distance *distance; | ||
| 15 | + | ||
| 16 | + void init() | ||
| 17 | + { | ||
| 18 | + distance = Distance::make("Dist("+file.suffix()+")"); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + float compare(const cv::Mat &a, const cv::Mat &b) const | ||
| 22 | + { | ||
| 23 | + return distance->compare(a, b); | ||
| 24 | + } | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +BR_REGISTER(Distance, DefaultDistance) | ||
| 28 | + | ||
| 29 | +} // namespace br | ||
| 30 | + | ||
| 31 | +#include "default.moc" |
openbr/plugins/distance/dist.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | +#include <openbr/plugins/openbr_internal.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup distances | ||
| 11 | + * \brief Standard distance metrics | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + */ | ||
| 14 | +class DistDistance : public UntrainableDistance | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + Q_ENUMS(Metric) | ||
| 18 | + Q_PROPERTY(Metric metric READ get_metric WRITE set_metric RESET reset_metric STORED false) | ||
| 19 | + Q_PROPERTY(bool negLogPlusOne READ get_negLogPlusOne WRITE set_negLogPlusOne RESET reset_negLogPlusOne STORED false) | ||
| 20 | + | ||
| 21 | +public: | ||
| 22 | + /*!< */ | ||
| 23 | + enum Metric { Correlation, | ||
| 24 | + ChiSquared, | ||
| 25 | + Intersection, | ||
| 26 | + Bhattacharyya, | ||
| 27 | + INF, | ||
| 28 | + L1, | ||
| 29 | + L2, | ||
| 30 | + Cosine, | ||
| 31 | + Dot}; | ||
| 32 | + | ||
| 33 | +private: | ||
| 34 | + BR_PROPERTY(Metric, metric, L2) | ||
| 35 | + BR_PROPERTY(bool, negLogPlusOne, true) | ||
| 36 | + | ||
| 37 | + float compare(const Mat &a, const Mat &b) const | ||
| 38 | + { | ||
| 39 | + if ((a.size != b.size) || | ||
| 40 | + (a.type() != b.type())) | ||
| 41 | + return -std::numeric_limits<float>::max(); | ||
| 42 | + | ||
| 43 | +// TODO: this max value is never returned based on the switch / default | ||
| 44 | + float result = std::numeric_limits<float>::max(); | ||
| 45 | + switch (metric) { | ||
| 46 | + case Correlation: | ||
| 47 | + return compareHist(a, b, CV_COMP_CORREL); | ||
| 48 | + case ChiSquared: | ||
| 49 | + result = compareHist(a, b, CV_COMP_CHISQR); | ||
| 50 | + break; | ||
| 51 | + case Intersection: | ||
| 52 | + result = compareHist(a, b, CV_COMP_INTERSECT); | ||
| 53 | + break; | ||
| 54 | + case Bhattacharyya: | ||
| 55 | + result = compareHist(a, b, CV_COMP_BHATTACHARYYA); | ||
| 56 | + break; | ||
| 57 | + case INF: | ||
| 58 | + result = norm(a, b, NORM_INF); | ||
| 59 | + break; | ||
| 60 | + case L1: | ||
| 61 | + result = norm(a, b, NORM_L1); | ||
| 62 | + break; | ||
| 63 | + case L2: | ||
| 64 | + result = norm(a, b, NORM_L2); | ||
| 65 | + break; | ||
| 66 | + case Cosine: | ||
| 67 | + return cosine(a, b); | ||
| 68 | + case Dot: | ||
| 69 | + return a.dot(b); | ||
| 70 | + default: | ||
| 71 | + qFatal("Invalid metric"); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + if (result != result) | ||
| 75 | + qFatal("NaN result."); | ||
| 76 | + | ||
| 77 | + return negLogPlusOne ? -log(result+1) : result; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + static float cosine(const Mat &a, const Mat &b) | ||
| 81 | + { | ||
| 82 | + float dot = 0; | ||
| 83 | + float magA = 0; | ||
| 84 | + float magB = 0; | ||
| 85 | + | ||
| 86 | + for (int row=0; row<a.rows; row++) { | ||
| 87 | + for (int col=0; col<a.cols; col++) { | ||
| 88 | + const float target = a.at<float>(row,col); | ||
| 89 | + const float query = b.at<float>(row,col); | ||
| 90 | + dot += target * query; | ||
| 91 | + magA += target * target; | ||
| 92 | + magB += query * query; | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + return dot / (sqrt(magA)*sqrt(magB)); | ||
| 97 | + } | ||
| 98 | +}; | ||
| 99 | + | ||
| 100 | +BR_REGISTER(Distance, DistDistance) | ||
| 101 | + | ||
| 102 | +} // namespace br | ||
| 103 | + | ||
| 104 | +#include "dist.moc" |
openbr/plugins/distance/fuse.cpp
0 → 100644
| 1 | +#include <numeric> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup distances | ||
| 10 | + * \brief Fuses similarity scores across multiple matrices of compared templates | ||
| 11 | + * \author Scott Klum \cite sklum | ||
| 12 | + * \note Operation: Mean, sum, min, max are supported. | ||
| 13 | + */ | ||
| 14 | +class FuseDistance : public Distance | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + Q_ENUMS(Operation) | ||
| 18 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) | ||
| 19 | + Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false) | ||
| 20 | + Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false) | ||
| 21 | + | ||
| 22 | + QList<br::Distance*> distances; | ||
| 23 | + | ||
| 24 | +public: | ||
| 25 | + /*!< */ | ||
| 26 | + enum Operation {Mean, Sum, Max, Min}; | ||
| 27 | + | ||
| 28 | +private: | ||
| 29 | + BR_PROPERTY(QString, description, "L2") | ||
| 30 | + BR_PROPERTY(Operation, operation, Mean) | ||
| 31 | + BR_PROPERTY(QList<float>, weights, QList<float>()) | ||
| 32 | + | ||
| 33 | + void train(const TemplateList &src) | ||
| 34 | + { | ||
| 35 | + // Partition the templates by matrix | ||
| 36 | + QList<int> split; | ||
| 37 | + for (int i=0; i<src.at(0).size(); i++) split.append(1); | ||
| 38 | + | ||
| 39 | + QList<TemplateList> partitionedSrc = src.partition(split); | ||
| 40 | + | ||
| 41 | + while (distances.size() < partitionedSrc.size()) | ||
| 42 | + distances.append(make(description)); | ||
| 43 | + | ||
| 44 | + // Train on each of the partitions | ||
| 45 | + for (int i=0; i<distances.size(); i++) | ||
| 46 | + distances[i]->train(partitionedSrc[i]); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + float compare(const Template &a, const Template &b) const | ||
| 50 | + { | ||
| 51 | + if (a.size() != b.size()) qFatal("Comparison size mismatch"); | ||
| 52 | + | ||
| 53 | + QList<float> scores; | ||
| 54 | + for (int i=0; i<distances.size(); i++) { | ||
| 55 | + float weight; | ||
| 56 | + weights.isEmpty() ? weight = 1. : weight = weights[i]; | ||
| 57 | + scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i]))); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + switch (operation) { | ||
| 61 | + case Mean: | ||
| 62 | + return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size(); | ||
| 63 | + break; | ||
| 64 | + case Sum: | ||
| 65 | + return std::accumulate(scores.begin(),scores.end(),0.0); | ||
| 66 | + break; | ||
| 67 | + case Min: | ||
| 68 | + return *std::min_element(scores.begin(),scores.end()); | ||
| 69 | + break; | ||
| 70 | + case Max: | ||
| 71 | + return *std::max_element(scores.begin(),scores.end()); | ||
| 72 | + break; | ||
| 73 | + default: | ||
| 74 | + qFatal("Invalid operation."); | ||
| 75 | + } | ||
| 76 | + return 0; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + void store(QDataStream &stream) const | ||
| 80 | + { | ||
| 81 | + stream << distances.size(); | ||
| 82 | + foreach (Distance *distance, distances) | ||
| 83 | + distance->store(stream); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + void load(QDataStream &stream) | ||
| 87 | + { | ||
| 88 | + int numDistances; | ||
| 89 | + stream >> numDistances; | ||
| 90 | + while (distances.size() < numDistances) | ||
| 91 | + distances.append(make(description)); | ||
| 92 | + foreach (Distance *distance, distances) | ||
| 93 | + distance->load(stream); | ||
| 94 | + } | ||
| 95 | +}; | ||
| 96 | + | ||
| 97 | +BR_REGISTER(Distance, FuseDistance) | ||
| 98 | + | ||
| 99 | +} // namespace br | ||
| 100 | + | ||
| 101 | +#include "fuse.moc" |
openbr/plugins/distance/gallerycompare.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +namespace br | ||
| 5 | +{ | ||
| 6 | + | ||
| 7 | +/*! | ||
| 8 | + * \ingroup transforms | ||
| 9 | + * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance. | ||
| 10 | + * dst will contain a 1 by n vector of scores. | ||
| 11 | + * \author Charles Otto \cite caotto | ||
| 12 | + */ | ||
| 13 | +class GalleryCompareTransform : public Transform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true) | ||
| 17 | + Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) | ||
| 18 | + BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 19 | + BR_PROPERTY(QString, galleryName, "") | ||
| 20 | + | ||
| 21 | + TemplateList gallery; | ||
| 22 | + | ||
| 23 | + void project(const Template &src, Template &dst) const | ||
| 24 | + { | ||
| 25 | + dst = src; | ||
| 26 | + if (gallery.isEmpty()) | ||
| 27 | + return; | ||
| 28 | + | ||
| 29 | + QList<float> line = distance->compare(gallery, src); | ||
| 30 | + dst.m() = OpenCVUtils::toMat(line, 1); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + void init() | ||
| 34 | + { | ||
| 35 | + if (!galleryName.isEmpty()) | ||
| 36 | + gallery = TemplateList::fromGallery(galleryName); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + void train(const TemplateList &data) | ||
| 40 | + { | ||
| 41 | + gallery = data; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + void store(QDataStream &stream) const | ||
| 45 | + { | ||
| 46 | + br::Object::store(stream); | ||
| 47 | + stream << gallery; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + void load(QDataStream &stream) | ||
| 51 | + { | ||
| 52 | + br::Object::load(stream); | ||
| 53 | + stream >> gallery; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | +public: | ||
| 57 | + GalleryCompareTransform() : Transform(false, true) {} | ||
| 58 | +}; | ||
| 59 | + | ||
| 60 | +BR_REGISTER(Transform, GalleryCompareTransform) | ||
| 61 | + | ||
| 62 | +} // namespace br | ||
| 63 | + | ||
| 64 | +#include "gallerycompare.moc" |
openbr/plugins/distance/halfbyteL1.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/distance_sse.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup distances | ||
| 11 | + * \brief Fast 4-bit L1 distance | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + */ | ||
| 14 | +class HalfByteL1Distance : public UntrainableDistance | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + | ||
| 18 | + float compare(const Mat &a, const Mat &b) const | ||
| 19 | + { | ||
| 20 | + return packed_l1(a.data, b.data, a.total()); | ||
| 21 | + } | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +BR_REGISTER(Distance, HalfByteL1Distance) | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +} // namespace br | ||
| 28 | + | ||
| 29 | +#include "halfbyteL1.moc" |
openbr/plugins/distance/identical.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup distances | ||
| 10 | + * \brief Returns \c true if the templates are identical, \c false otherwise. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class IdenticalDistance : public UntrainableDistance | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + float compare(const Mat &a, const Mat &b) const | ||
| 18 | + { | ||
| 19 | + const size_t size = a.total() * a.elemSize(); | ||
| 20 | + if (size != b.total() * b.elemSize()) return 0; | ||
| 21 | + for (size_t i=0; i<size; i++) | ||
| 22 | + if (a.data[i] != b.data[i]) return 0; | ||
| 23 | + return 1; | ||
| 24 | + } | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +BR_REGISTER(Distance, IdenticalDistance) | ||
| 28 | + | ||
| 29 | +} // namespace br | ||
| 30 | + | ||
| 31 | +#include "identical.moc" |
openbr/plugins/distance/keypointmatcher.cpp
0 → 100644
| 1 | +#include <opencv2/features2d/features2d.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Wraps OpenCV Key Point Matcher | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class KeyPointMatcherDistance : public UntrainableDistance | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(QString matcher READ get_matcher WRITE set_matcher RESET reset_matcher STORED false) | ||
| 19 | + Q_PROPERTY(float maxRatio READ get_maxRatio WRITE set_maxRatio RESET reset_maxRatio STORED false) | ||
| 20 | + BR_PROPERTY(QString, matcher, "BruteForce") | ||
| 21 | + BR_PROPERTY(float, maxRatio, 0.8) | ||
| 22 | + | ||
| 23 | + Ptr<DescriptorMatcher> descriptorMatcher; | ||
| 24 | + | ||
| 25 | + void init() | ||
| 26 | + { | ||
| 27 | + descriptorMatcher = DescriptorMatcher::create(matcher.toStdString()); | ||
| 28 | + if (descriptorMatcher.empty()) | ||
| 29 | + qFatal("Failed to create DescriptorMatcher: %s", qPrintable(matcher)); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + float compare(const Mat &a, const Mat &b) const | ||
| 33 | + { | ||
| 34 | + if ((a.rows < 2) || (b.rows < 2)) return 0; | ||
| 35 | + | ||
| 36 | + std::vector< std::vector<DMatch> > matches; | ||
| 37 | + if (a.rows < b.rows) descriptorMatcher->knnMatch(a, b, matches, 2); | ||
| 38 | + else descriptorMatcher->knnMatch(b, a, matches, 2); | ||
| 39 | + | ||
| 40 | + QList<float> distances; | ||
| 41 | + foreach (const std::vector<DMatch> &match, matches) { | ||
| 42 | + if (match[0].distance / match[1].distance > maxRatio) continue; | ||
| 43 | + distances.append(match[0].distance); | ||
| 44 | + } | ||
| 45 | + qSort(distances); | ||
| 46 | + | ||
| 47 | + float similarity = 0; | ||
| 48 | + for (int i=0; i<distances.size(); i++) | ||
| 49 | + similarity += 1.f/(1+distances[i])/(i+1); | ||
| 50 | + return similarity; | ||
| 51 | + } | ||
| 52 | +}; | ||
| 53 | + | ||
| 54 | +BR_REGISTER(Distance, KeyPointMatcherDistance) | ||
| 55 | + | ||
| 56 | +} // namespace br | ||
| 57 | + | ||
| 58 | +#include "keypointmatcher.moc" |
openbr/plugins/distance/l1.cpp
0 → 100644
| 1 | +#include <Eigen/Dense> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup distances | ||
| 10 | + * \brief L1 distance computed using eigen. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class L1Distance : public UntrainableDistance | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + float compare(const cv::Mat &a, const cv::Mat &b) const | ||
| 18 | + { | ||
| 19 | + const int size = a.rows * a.cols; | ||
| 20 | + Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | ||
| 21 | + Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | ||
| 22 | + return (aMap-bMap).cwiseAbs().sum(); | ||
| 23 | + } | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +BR_REGISTER(Distance, L1Distance) | ||
| 27 | + | ||
| 28 | +} // namespace br | ||
| 29 | + | ||
| 30 | +#include "L1.moc" |
openbr/plugins/distance/neglogplusone.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup distances | ||
| 8 | + * \brief Returns -log(distance(a,b)+1) | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class NegativeLogPlusOneDistance : public UntrainableDistance | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 15 | + BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 16 | + | ||
| 17 | + void train(const TemplateList &src) | ||
| 18 | + { | ||
| 19 | + distance->train(src); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + float compare(const Template &a, const Template &b) const | ||
| 23 | + { | ||
| 24 | + return -log(distance->compare(a,b)+1); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + void store(QDataStream &stream) const | ||
| 28 | + { | ||
| 29 | + distance->store(stream); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + void load(QDataStream &stream) | ||
| 33 | + { | ||
| 34 | + distance->load(stream); | ||
| 35 | + } | ||
| 36 | +}; | ||
| 37 | + | ||
| 38 | +BR_REGISTER(Distance, NegativeLogPlusOneDistance) | ||
| 39 | + | ||
| 40 | +} // namespace br | ||
| 41 | + | ||
| 42 | +#include "neglogplusone.moc" |
openbr/plugins/distance/online.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup distances | ||
| 8 | + * \brief Online distance metric to attenuate match scores across multiple frames | ||
| 9 | + * \author Brendan klare \cite bklare | ||
| 10 | + */ | ||
| 11 | +class OnlineDistance : public UntrainableDistance | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 15 | + Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | ||
| 16 | + BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 17 | + BR_PROPERTY(float, alpha, 0.1f) | ||
| 18 | + | ||
| 19 | + mutable QHash<QString,float> scoreHash; | ||
| 20 | + mutable QMutex mutex; | ||
| 21 | + | ||
| 22 | + float compare(const Template &target, const Template &query) const | ||
| 23 | + { | ||
| 24 | + float currentScore = distance->compare(target, query); | ||
| 25 | + | ||
| 26 | + QMutexLocker mutexLocker(&mutex); | ||
| 27 | + return scoreHash[target.file.name] = (1.0- alpha) * scoreHash[target.file.name] + alpha * currentScore; | ||
| 28 | + } | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +BR_REGISTER(Distance, OnlineDistance) | ||
| 32 | + | ||
| 33 | +} // namespace br | ||
| 34 | + | ||
| 35 | +#include "online.moc" |
openbr/plugins/distance/pipe.cpp
0 → 100644
| 1 | +#include <QtConcurrent> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup distances | ||
| 10 | + * \brief Distances in series. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + * | ||
| 13 | + * The templates are compared using each br::Distance in order. | ||
| 14 | + * If the result of the comparison with any given distance is -FLOAT_MAX then this result is returned early. | ||
| 15 | + * Otherwise the returned result is the value of comparing the templates using the last br::Distance. | ||
| 16 | + */ | ||
| 17 | +class PipeDistance : public Distance | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | ||
| 21 | + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | ||
| 22 | + | ||
| 23 | + void train(const TemplateList &data) | ||
| 24 | + { | ||
| 25 | + QFutureSynchronizer<void> futures; | ||
| 26 | + foreach (br::Distance *distance, distances) | ||
| 27 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | ||
| 28 | + futures.waitForFinished(); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + float compare(const Template &a, const Template &b) const | ||
| 32 | + { | ||
| 33 | + float result = -std::numeric_limits<float>::max(); | ||
| 34 | + foreach (br::Distance *distance, distances) { | ||
| 35 | + result = distance->compare(a, b); | ||
| 36 | + if (result == -std::numeric_limits<float>::max()) | ||
| 37 | + return result; | ||
| 38 | + } | ||
| 39 | + return result; | ||
| 40 | + } | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +BR_REGISTER(Distance, PipeDistance) | ||
| 44 | + | ||
| 45 | +} // namespace br | ||
| 46 | + | ||
| 47 | +#include "pipe.moc" |
openbr/plugins/distance/sum.cpp
0 → 100644
| 1 | +#include <QtConcurrent> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup distances | ||
| 10 | + * \brief Sum match scores across multiple distances | ||
| 11 | + * \author Scott Klum \cite sklum | ||
| 12 | + */ | ||
| 13 | +class SumDistance : public UntrainableDistance | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | ||
| 17 | + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | ||
| 18 | + | ||
| 19 | + void train(const TemplateList &data) | ||
| 20 | + { | ||
| 21 | + QFutureSynchronizer<void> futures; | ||
| 22 | + foreach (br::Distance *distance, distances) | ||
| 23 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | ||
| 24 | + futures.waitForFinished(); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + float compare(const Template &target, const Template &query) const | ||
| 28 | + { | ||
| 29 | + float result = 0; | ||
| 30 | + | ||
| 31 | + foreach (br::Distance *distance, distances) { | ||
| 32 | + result += distance->compare(target, query); | ||
| 33 | + | ||
| 34 | + if (result == -std::numeric_limits<float>::max()) | ||
| 35 | + return result; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + return result; | ||
| 39 | + } | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +BR_REGISTER(Distance, SumDistance) | ||
| 43 | + | ||
| 44 | +} // namespace br | ||
| 45 | + | ||
| 46 | +#include "sum.moc" |
openbr/plugins/draw.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/highgui/highgui.hpp> | ||
| 18 | -#include <opencv2/highgui/highgui_c.h> | ||
| 19 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 20 | -#include <vector> | ||
| 21 | -#include "openbr_internal.h" | ||
| 22 | -#include "openbr/core/opencvutils.h" | ||
| 23 | - | ||
| 24 | -using namespace cv; | ||
| 25 | - | ||
| 26 | -namespace br | ||
| 27 | -{ | ||
| 28 | - | ||
| 29 | -/*! | ||
| 30 | - * \ingroup transforms | ||
| 31 | - * \brief Renders metadata onto the image. | ||
| 32 | - * | ||
| 33 | - * The inPlace argument controls whether or not the image is cloned before the metadata is drawn. | ||
| 34 | - * | ||
| 35 | - * \author Josh Klontz \cite jklontz | ||
| 36 | - */ | ||
| 37 | -class DrawTransform : public UntrainableTransform | ||
| 38 | -{ | ||
| 39 | - Q_OBJECT | ||
| 40 | - Q_PROPERTY(bool verbose READ get_verbose WRITE set_verbose RESET reset_verbose STORED false) | ||
| 41 | - Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) | ||
| 42 | - Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) | ||
| 43 | - Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | ||
| 44 | - Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false) | ||
| 45 | - Q_PROPERTY(bool named READ get_named WRITE set_named RESET reset_named STORED false) | ||
| 46 | - Q_PROPERTY(bool location READ get_location WRITE set_location RESET reset_location STORED false) | ||
| 47 | - BR_PROPERTY(bool, verbose, false) | ||
| 48 | - BR_PROPERTY(bool, points, true) | ||
| 49 | - BR_PROPERTY(bool, rects, true) | ||
| 50 | - BR_PROPERTY(bool, inPlace, false) | ||
| 51 | - BR_PROPERTY(int, lineThickness, 1) | ||
| 52 | - BR_PROPERTY(bool, named, true) | ||
| 53 | - BR_PROPERTY(bool, location, true) | ||
| 54 | - | ||
| 55 | - void project(const Template &src, Template &dst) const | ||
| 56 | - { | ||
| 57 | - const Scalar color(0,255,0); | ||
| 58 | - const Scalar verboseColor(255, 255, 0); | ||
| 59 | - dst.m() = inPlace ? src.m() : src.m().clone(); | ||
| 60 | - | ||
| 61 | - if (points) { | ||
| 62 | - const QList<Point2f> pointsList = (named) ? OpenCVUtils::toPoints(src.file.points()+src.file.namedPoints()) : OpenCVUtils::toPoints(src.file.points()); | ||
| 63 | - for (int i=0; i<pointsList.size(); i++) { | ||
| 64 | - const Point2f &point = pointsList[i]; | ||
| 65 | - circle(dst, point, 3, color, -1); | ||
| 66 | - QString label = (location) ? QString("%1,(%2,%3)").arg(QString::number(i),QString::number(point.x),QString::number(point.y)) : QString("%1").arg(QString::number(i)); | ||
| 67 | - if (verbose) putText(dst, label.toStdString(), point, FONT_HERSHEY_SIMPLEX, 0.5, verboseColor, 1); | ||
| 68 | - } | ||
| 69 | - } | ||
| 70 | - if (rects) { | ||
| 71 | - foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects())) | ||
| 72 | - rectangle(dst, rect, color, lineThickness); | ||
| 73 | - } | ||
| 74 | - } | ||
| 75 | -}; | ||
| 76 | - | ||
| 77 | -BR_REGISTER(Transform, DrawTransform) | ||
| 78 | - | ||
| 79 | - | ||
| 80 | -/*! | ||
| 81 | - * \ingroup transforms | ||
| 82 | - * \brief Draw the value of the specified property at the specified point on the image | ||
| 83 | - * | ||
| 84 | - * The inPlace argument controls whether or not the image is cloned before it is drawn on. | ||
| 85 | - * | ||
| 86 | - * \author Charles Otto \cite caotto | ||
| 87 | - */ | ||
| 88 | -class DrawPropertyPointTransform : public UntrainableTransform | ||
| 89 | -{ | ||
| 90 | - Q_OBJECT | ||
| 91 | - Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | ||
| 92 | - Q_PROPERTY(QString pointName READ get_pointName WRITE set_pointName RESET reset_pointName STORED false) | ||
| 93 | - Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | ||
| 94 | - BR_PROPERTY(QString, propName, "") | ||
| 95 | - BR_PROPERTY(QString, pointName, "") | ||
| 96 | - BR_PROPERTY(bool, inPlace, false) | ||
| 97 | - | ||
| 98 | - | ||
| 99 | - void project(const Template &src, Template &dst) const | ||
| 100 | - { | ||
| 101 | - dst = src; | ||
| 102 | - if (propName.isEmpty() || pointName.isEmpty()) | ||
| 103 | - return; | ||
| 104 | - | ||
| 105 | - dst.m() = inPlace ? src.m() : src.m().clone(); | ||
| 106 | - | ||
| 107 | - const Scalar textColor(255, 255, 0); | ||
| 108 | - | ||
| 109 | - QVariant prop = dst.file.value(propName); | ||
| 110 | - | ||
| 111 | - | ||
| 112 | - if (!prop.canConvert(QVariant::String)) | ||
| 113 | - return; | ||
| 114 | - QString propString = prop.toString(); | ||
| 115 | - | ||
| 116 | - QVariant point = dst.file.value(pointName); | ||
| 117 | - | ||
| 118 | - if (!point.canConvert(QVariant::PointF)) | ||
| 119 | - return; | ||
| 120 | - | ||
| 121 | - QPointF targetPoint = point.toPointF(); | ||
| 122 | - | ||
| 123 | - Point2f cvPoint =OpenCVUtils::toPoint(targetPoint); | ||
| 124 | - | ||
| 125 | - std::string text = propName.toStdString() + ": " + propString.toStdString(); | ||
| 126 | - putText(dst, text, cvPoint, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1); | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | -}; | ||
| 130 | -BR_REGISTER(Transform, DrawPropertyPointTransform) | ||
| 131 | - | ||
| 132 | -/*! | ||
| 133 | - * \ingroup transforms | ||
| 134 | - * \brief Draw the values of a list of properties at the specified point on the image | ||
| 135 | - * | ||
| 136 | - * The inPlace argument controls whether or not the image is cloned before it is drawn on. | ||
| 137 | - * | ||
| 138 | - * \author Charles Otto \cite caotto | ||
| 139 | - */ | ||
| 140 | -class DrawPropertiesPointTransform : public UntrainableTransform | ||
| 141 | -{ | ||
| 142 | - Q_OBJECT | ||
| 143 | - Q_PROPERTY(QStringList propNames READ get_propNames WRITE set_propNames RESET reset_propNames STORED false) | ||
| 144 | - Q_PROPERTY(QString pointName READ get_pointName WRITE set_pointName RESET reset_pointName STORED false) | ||
| 145 | - Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | ||
| 146 | - BR_PROPERTY(QStringList, propNames, QStringList()) | ||
| 147 | - BR_PROPERTY(QString, pointName, "") | ||
| 148 | - BR_PROPERTY(bool, inPlace, false) | ||
| 149 | - | ||
| 150 | - void project(const Template &src, Template &dst) const | ||
| 151 | - { | ||
| 152 | - dst = src; | ||
| 153 | - if (propNames.isEmpty() || pointName.isEmpty()) | ||
| 154 | - return; | ||
| 155 | - | ||
| 156 | - dst.m() = inPlace ? src.m() : src.m().clone(); | ||
| 157 | - | ||
| 158 | - QVariant point = dst.file.value(pointName); | ||
| 159 | - | ||
| 160 | - if (!point.canConvert(QVariant::PointF)) | ||
| 161 | - return; | ||
| 162 | - | ||
| 163 | - QPointF targetPoint = point.toPointF(); | ||
| 164 | - | ||
| 165 | - Point2f cvPoint =OpenCVUtils::toPoint(targetPoint); | ||
| 166 | - | ||
| 167 | - | ||
| 168 | - const Scalar textColor(255, 255, 0); | ||
| 169 | - | ||
| 170 | - std::string outString = ""; | ||
| 171 | - foreach (const QString &propName, propNames) | ||
| 172 | - { | ||
| 173 | - QVariant prop = dst.file.value(propName); | ||
| 174 | - | ||
| 175 | - if (!prop.canConvert(QVariant::String)) | ||
| 176 | - continue; | ||
| 177 | - QString propString = prop.toString(); | ||
| 178 | - outString += propName.toStdString() + ": " + propString.toStdString() + " "; | ||
| 179 | - | ||
| 180 | - } | ||
| 181 | - if (outString.empty()) | ||
| 182 | - return; | ||
| 183 | - | ||
| 184 | - putText(dst, outString, cvPoint, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1); | ||
| 185 | - } | ||
| 186 | - | ||
| 187 | -}; | ||
| 188 | -BR_REGISTER(Transform, DrawPropertiesPointTransform) | ||
| 189 | - | ||
| 190 | - | ||
| 191 | -/*! | ||
| 192 | - * \ingroup transforms | ||
| 193 | - * \brief Draws a grid on the image | ||
| 194 | - * \author Josh Klontz \cite jklontz | ||
| 195 | - */ | ||
| 196 | -class DrawGridTransform : public UntrainableTransform | ||
| 197 | -{ | ||
| 198 | - Q_OBJECT | ||
| 199 | - Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | ||
| 200 | - Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | ||
| 201 | - Q_PROPERTY(int r READ get_r WRITE set_r RESET reset_r STORED false) | ||
| 202 | - Q_PROPERTY(int g READ get_g WRITE set_g RESET reset_g STORED false) | ||
| 203 | - Q_PROPERTY(int b READ get_b WRITE set_b RESET reset_b STORED false) | ||
| 204 | - BR_PROPERTY(int, rows, 0) | ||
| 205 | - BR_PROPERTY(int, columns, 0) | ||
| 206 | - BR_PROPERTY(int, r, 196) | ||
| 207 | - BR_PROPERTY(int, g, 196) | ||
| 208 | - BR_PROPERTY(int, b, 196) | ||
| 209 | - | ||
| 210 | - void project(const Template &src, Template &dst) const | ||
| 211 | - { | ||
| 212 | - Mat m = src.m().clone(); | ||
| 213 | - float rowStep = 1.f * m.rows / (rows+1); | ||
| 214 | - float columnStep = 1.f * m.cols / (columns+1); | ||
| 215 | - int thickness = qMin(m.rows, m.cols) / 256; | ||
| 216 | - for (float row = rowStep/2; row < m.rows; row += rowStep) | ||
| 217 | - line(m, Point(0, row), Point(m.cols, row), Scalar(r, g, b), thickness, CV_AA); | ||
| 218 | - for (float column = columnStep/2; column < m.cols; column += columnStep) | ||
| 219 | - line(m, Point(column, 0), Point(column, m.rows), Scalar(r, g, b), thickness, CV_AA); | ||
| 220 | - dst = m; | ||
| 221 | - } | ||
| 222 | -}; | ||
| 223 | - | ||
| 224 | -BR_REGISTER(Transform, DrawGridTransform) | ||
| 225 | - | ||
| 226 | -/*! | ||
| 227 | - * \ingroup transforms | ||
| 228 | - * \brief Computes the mean of a set of templates. | ||
| 229 | - * \note Suitable for visualization only as it sets every projected template to the mean template. | ||
| 230 | - * \author Scott Klum \cite sklum | ||
| 231 | - */ | ||
| 232 | -class MeanTransform : public Transform | ||
| 233 | -{ | ||
| 234 | - Q_OBJECT | ||
| 235 | - | ||
| 236 | - Mat mean; | ||
| 237 | - | ||
| 238 | - void train(const TemplateList &data) | ||
| 239 | - { | ||
| 240 | - mean = Mat::zeros(data[0].m().rows,data[0].m().cols,CV_32F); | ||
| 241 | - | ||
| 242 | - for (int i = 0; i < data.size(); i++) { | ||
| 243 | - Mat converted; | ||
| 244 | - data[i].m().convertTo(converted, CV_32F); | ||
| 245 | - mean += converted; | ||
| 246 | - } | ||
| 247 | - | ||
| 248 | - mean /= data.size(); | ||
| 249 | - } | ||
| 250 | - | ||
| 251 | - void project(const Template &src, Template &dst) const | ||
| 252 | - { | ||
| 253 | - dst = src; | ||
| 254 | - dst.m() = mean; | ||
| 255 | - } | ||
| 256 | - | ||
| 257 | -}; | ||
| 258 | - | ||
| 259 | -BR_REGISTER(Transform, MeanTransform) | ||
| 260 | - | ||
| 261 | -/*! | ||
| 262 | - * \ingroup transforms | ||
| 263 | - * \brief Load the image named in the specified property, draw it on the current matrix adjacent to the rect specified in the other property. | ||
| 264 | - * \author Charles Otto \cite caotto | ||
| 265 | - */ | ||
| 266 | -class AdjacentOverlayTransform : public Transform | ||
| 267 | -{ | ||
| 268 | - Q_OBJECT | ||
| 269 | - | ||
| 270 | - Q_PROPERTY(QString imgName READ get_imgName WRITE set_imgName RESET reset_imgName STORED false) | ||
| 271 | - Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false) | ||
| 272 | - BR_PROPERTY(QString, imgName, "") | ||
| 273 | - BR_PROPERTY(QString, targetName, "") | ||
| 274 | - | ||
| 275 | - QSharedPointer<Transform> opener; | ||
| 276 | - void project(const Template &src, Template &dst) const | ||
| 277 | - { | ||
| 278 | - dst = src; | ||
| 279 | - | ||
| 280 | - if (imgName.isEmpty() || targetName.isEmpty() || !dst.file.contains(imgName) || !dst.file.contains(targetName)) | ||
| 281 | - return; | ||
| 282 | - | ||
| 283 | - QVariant temp = src.file.value(imgName); | ||
| 284 | - cv::Mat im; | ||
| 285 | - // is this a filename? | ||
| 286 | - if (temp.canConvert<QString>()) { | ||
| 287 | - QString im_name = temp.toString(); | ||
| 288 | - Template temp_im; | ||
| 289 | - opener->project(File(im_name), temp_im); | ||
| 290 | - im = temp_im.m(); | ||
| 291 | - } | ||
| 292 | - // a cv::Mat ? | ||
| 293 | - else if (temp.canConvert<cv::Mat>()) | ||
| 294 | - im = src.file.get<cv::Mat>(imgName); | ||
| 295 | - else | ||
| 296 | - qDebug() << "Unrecognized property type " << imgName << "for" << src.file.name; | ||
| 297 | - | ||
| 298 | - // Location of detected face in source image | ||
| 299 | - QRectF target_location = src.file.get<QRectF>(targetName); | ||
| 300 | - | ||
| 301 | - // match width with target region | ||
| 302 | - qreal target_width = target_location.width(); | ||
| 303 | - qreal current_width = im.cols; | ||
| 304 | - qreal current_height = im.rows; | ||
| 305 | - | ||
| 306 | - qreal aspect_ratio = current_height / current_width; | ||
| 307 | - qreal target_height = target_width * aspect_ratio; | ||
| 308 | - | ||
| 309 | - cv::resize(im, im, cv::Size(target_width, target_height)); | ||
| 310 | - | ||
| 311 | - // ROI used to maybe crop the matched image | ||
| 312 | - cv::Rect clip_roi; | ||
| 313 | - clip_roi.x = 0; | ||
| 314 | - clip_roi.y = 0; | ||
| 315 | - clip_roi.width = im.cols; | ||
| 316 | - clip_roi.height= im.rows <= dst.m().rows ? im.rows : dst.m().rows; | ||
| 317 | - | ||
| 318 | - int half_width = src.m().cols / 2; | ||
| 319 | - int out_x = 0; | ||
| 320 | - | ||
| 321 | - // place in the source image we will copy the matched image to. | ||
| 322 | - cv::Rect target_roi; | ||
| 323 | - bool left_side = false; | ||
| 324 | - int width_adjust = 0; | ||
| 325 | - // Place left | ||
| 326 | - if (target_location.center().rx() > half_width) { | ||
| 327 | - out_x = target_location.left() - im.cols; | ||
| 328 | - if (out_x < 0) { | ||
| 329 | - width_adjust = abs(out_x); | ||
| 330 | - out_x = 0; | ||
| 331 | - } | ||
| 332 | - left_side = true; | ||
| 333 | - } | ||
| 334 | - // place right | ||
| 335 | - else { | ||
| 336 | - out_x = target_location.right(); | ||
| 337 | - int high = out_x + im.cols; | ||
| 338 | - if (high >= src.m().cols) { | ||
| 339 | - width_adjust = abs(high - src.m().cols + 1); | ||
| 340 | - } | ||
| 341 | - } | ||
| 342 | - | ||
| 343 | - cv::Mat outIm; | ||
| 344 | - if (width_adjust) | ||
| 345 | - { | ||
| 346 | - outIm.create(dst.m().rows, dst.m().cols + width_adjust, CV_8UC3); | ||
| 347 | - memset(outIm.data, 127, outIm.rows * outIm.cols * outIm.channels()); | ||
| 348 | - | ||
| 349 | - Rect temp; | ||
| 350 | - | ||
| 351 | - if (left_side) | ||
| 352 | - temp = Rect(abs(width_adjust), 0, dst.m().cols, dst.m().rows); | ||
| 353 | - | ||
| 354 | - else | ||
| 355 | - temp = Rect(0, 0, dst.m().cols, dst.m().rows); | ||
| 356 | - | ||
| 357 | - dst.m().copyTo(outIm(temp)); | ||
| 358 | - | ||
| 359 | - } | ||
| 360 | - else | ||
| 361 | - outIm = dst.m(); | ||
| 362 | - | ||
| 363 | - if (clip_roi.height + target_location.top() >= outIm.rows) | ||
| 364 | - { | ||
| 365 | - clip_roi.height -= abs(outIm.rows - (clip_roi.height + target_location.top() )); | ||
| 366 | - } | ||
| 367 | - if (clip_roi.x + clip_roi.width >= im.cols) { | ||
| 368 | - clip_roi.width -= abs(im.cols - (clip_roi.x + clip_roi.width + 1)); | ||
| 369 | - if (clip_roi.width < 0) | ||
| 370 | - clip_roi.width = 1; | ||
| 371 | - } | ||
| 372 | - | ||
| 373 | - if (clip_roi.y + clip_roi.height >= im.rows) { | ||
| 374 | - clip_roi.height -= abs(im.rows - (clip_roi.y + clip_roi.height + 1)); | ||
| 375 | - } | ||
| 376 | - if (clip_roi.x < 0) | ||
| 377 | - clip_roi.x = 0; | ||
| 378 | - if (clip_roi.y < 0) | ||
| 379 | - clip_roi.y = 0; | ||
| 380 | - | ||
| 381 | - if (clip_roi.height < 0) | ||
| 382 | - clip_roi.height = 0; | ||
| 383 | - | ||
| 384 | - if (clip_roi.width < 0) | ||
| 385 | - clip_roi.width = 0; | ||
| 386 | - | ||
| 387 | - | ||
| 388 | - if (clip_roi.y + clip_roi.height >= im.rows) | ||
| 389 | - { | ||
| 390 | - qDebug() << "Bad clip y" << clip_roi.y + clip_roi.height << im.rows; | ||
| 391 | - } | ||
| 392 | - if (clip_roi.x + clip_roi.width >= im.cols) | ||
| 393 | - { | ||
| 394 | - qDebug() << "Bad clip x" << clip_roi.x + clip_roi.width << im.cols; | ||
| 395 | - } | ||
| 396 | - | ||
| 397 | - if (clip_roi.y < 0 || clip_roi.height < 0) | ||
| 398 | - { | ||
| 399 | - qDebug() << "bad clip y, low" << clip_roi.y << clip_roi.height; | ||
| 400 | - qFatal("die"); | ||
| 401 | - } | ||
| 402 | - if (clip_roi.x < 0 || clip_roi.width < 0) | ||
| 403 | - { | ||
| 404 | - qDebug() << "bad clip x, low" << clip_roi.x << clip_roi.width; | ||
| 405 | - qFatal("die"); | ||
| 406 | - } | ||
| 407 | - | ||
| 408 | - target_roi.x = out_x; | ||
| 409 | - target_roi.width = clip_roi.width; | ||
| 410 | - target_roi.y = target_location.top(); | ||
| 411 | - target_roi.height = clip_roi.height; | ||
| 412 | - | ||
| 413 | - | ||
| 414 | - im = im(clip_roi); | ||
| 415 | - | ||
| 416 | - if (target_roi.x < 0 || target_roi.x >= outIm.cols) | ||
| 417 | - { | ||
| 418 | - qDebug() << "Bad xdim in targetROI!" << target_roi.x << " out im x: " << outIm.cols; | ||
| 419 | - qFatal("die"); | ||
| 420 | - } | ||
| 421 | - | ||
| 422 | - if (target_roi.x + target_roi.width < 0 || (target_roi.x + target_roi.width) >= outIm.cols) | ||
| 423 | - { | ||
| 424 | - qDebug() << "Bad xdim in targetROI!" << target_roi.x + target_roi.width; | ||
| 425 | - qFatal("die"); | ||
| 426 | - } | ||
| 427 | - | ||
| 428 | - if (target_roi.y < 0 || target_roi.y >= outIm.rows) | ||
| 429 | - { | ||
| 430 | - qDebug() << "Bad ydim in targetROI!" << target_roi.y; | ||
| 431 | - qFatal("die"); | ||
| 432 | - } | ||
| 433 | - | ||
| 434 | - if ((target_roi.y + target_roi.height) < 0 || (target_roi.y + target_roi.height) > outIm.rows) | ||
| 435 | - { | ||
| 436 | - qDebug() << "Bad ydim in targetROI!" << target_roi.y + target_roi.height; | ||
| 437 | - qDebug() << "target_roi.y: " << target_roi.y << " height: " << target_roi.height; | ||
| 438 | - qFatal("die"); | ||
| 439 | - } | ||
| 440 | - | ||
| 441 | - | ||
| 442 | - std::vector<cv::Mat> channels; | ||
| 443 | - cv::split(outIm, channels); | ||
| 444 | - | ||
| 445 | - std::vector<cv::Mat> patch_channels; | ||
| 446 | - cv::split(im, patch_channels); | ||
| 447 | - | ||
| 448 | - for (size_t i=0; i < channels.size(); i++) | ||
| 449 | - { | ||
| 450 | - cv::addWeighted(channels[i](target_roi), 0, patch_channels[i % patch_channels.size()], 1, 0,channels[i](target_roi)); | ||
| 451 | - } | ||
| 452 | - cv::merge(channels, outIm); | ||
| 453 | - dst.m() = outIm; | ||
| 454 | - | ||
| 455 | - } | ||
| 456 | - | ||
| 457 | - void init() | ||
| 458 | - { | ||
| 459 | - opener = QSharedPointer<br::Transform>(br::Transform::make("Cache(Open)", NULL)); | ||
| 460 | - } | ||
| 461 | - | ||
| 462 | -}; | ||
| 463 | - | ||
| 464 | -BR_REGISTER(Transform, AdjacentOverlayTransform) | ||
| 465 | - | ||
| 466 | -/*! | ||
| 467 | - * \ingroup transforms | ||
| 468 | - * \brief Draw a line representing the direction and magnitude of optical flow at the specified points. | ||
| 469 | - * \author Austin Blanton \cite imaus10 | ||
| 470 | - */ | ||
| 471 | -class DrawOpticalFlow : public UntrainableTransform | ||
| 472 | -{ | ||
| 473 | - Q_OBJECT | ||
| 474 | - Q_PROPERTY(QString original READ get_original WRITE set_original RESET reset_original STORED false) | ||
| 475 | - BR_PROPERTY(QString, original, "original") | ||
| 476 | - | ||
| 477 | - void project(const Template &src, Template &dst) const | ||
| 478 | - { | ||
| 479 | - const Scalar color(0,255,0); | ||
| 480 | - Mat flow = src.m(); | ||
| 481 | - dst = src; | ||
| 482 | - if (!dst.file.contains(original)) qFatal("The original img must be saved in the metadata with SaveMat."); | ||
| 483 | - dst.m() = dst.file.get<Mat>(original); | ||
| 484 | - dst.file.remove(original); | ||
| 485 | - foreach (const Point2f &pt, OpenCVUtils::toPoints(dst.file.points())) { | ||
| 486 | - Point2f dxy = flow.at<Point2f>(pt.y, pt.x); | ||
| 487 | - Point2f newPt(pt.x+dxy.x, pt.y+dxy.y); | ||
| 488 | - line(dst, pt, newPt, color); | ||
| 489 | - } | ||
| 490 | - } | ||
| 491 | -}; | ||
| 492 | -BR_REGISTER(Transform, DrawOpticalFlow) | ||
| 493 | - | ||
| 494 | -/*! | ||
| 495 | - * \ingroup transforms | ||
| 496 | - * \brief Fill in the segmentations or draw a line between intersecting segments. | ||
| 497 | - * \author Austin Blanton \cite imaus10 | ||
| 498 | - */ | ||
| 499 | -class DrawSegmentation : public UntrainableTransform | ||
| 500 | -{ | ||
| 501 | - Q_OBJECT | ||
| 502 | - Q_PROPERTY(bool fillSegment READ get_fillSegment WRITE set_fillSegment RESET reset_fillSegment STORED false) | ||
| 503 | - BR_PROPERTY(bool, fillSegment, true) | ||
| 504 | - | ||
| 505 | - void project(const Template &src, Template &dst) const | ||
| 506 | - { | ||
| 507 | - if (!src.file.contains("SegmentsMask") || !src.file.contains("NumSegments")) qFatal("Must supply a Contours object in the metadata to drawContours."); | ||
| 508 | - Mat segments = src.file.get<Mat>("SegmentsMask"); | ||
| 509 | - int numSegments = src.file.get<int>("NumSegments"); | ||
| 510 | - | ||
| 511 | - dst.file = src.file; | ||
| 512 | - Mat drawn = fillSegment ? Mat(segments.size(), CV_8UC3, Scalar::all(0)) : src.m(); | ||
| 513 | - | ||
| 514 | - for (int i=1; i<numSegments+1; i++) { | ||
| 515 | - Mat mask = segments == i; | ||
| 516 | - if (fillSegment) { // color the whole segment | ||
| 517 | - // set to a random color - get ready for a craaaazy acid trip | ||
| 518 | - int b = theRNG().uniform(0, 255); | ||
| 519 | - int g = theRNG().uniform(0, 255); | ||
| 520 | - int r = theRNG().uniform(0, 255); | ||
| 521 | - drawn.setTo(Scalar(r,g,b), mask); | ||
| 522 | - } else { // draw lines where there's a color change | ||
| 523 | - vector<vector<Point> > contours; | ||
| 524 | - Scalar color(0,255,0); | ||
| 525 | - findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); | ||
| 526 | - drawContours(drawn, contours, -1, color); | ||
| 527 | - } | ||
| 528 | - } | ||
| 529 | - | ||
| 530 | - dst.m() = drawn; | ||
| 531 | - } | ||
| 532 | -}; | ||
| 533 | -BR_REGISTER(Transform, DrawSegmentation) | ||
| 534 | - | ||
| 535 | -/*! | ||
| 536 | - * \ingroup transforms | ||
| 537 | - * \brief Write all mats to disk as images. | ||
| 538 | - * \author Brendan Klare \cite bklare | ||
| 539 | - */ | ||
| 540 | -class WriteImageTransform : public TimeVaryingTransform | ||
| 541 | -{ | ||
| 542 | - Q_OBJECT | ||
| 543 | - Q_PROPERTY(QString outputDirectory READ get_outputDirectory WRITE set_outputDirectory RESET reset_outputDirectory STORED false) | ||
| 544 | - Q_PROPERTY(QString imageName READ get_imageName WRITE set_imageName RESET reset_imageName STORED false) | ||
| 545 | - Q_PROPERTY(QString imgExtension READ get_imgExtension WRITE set_imgExtension RESET reset_imgExtension STORED false) | ||
| 546 | - BR_PROPERTY(QString, outputDirectory, "Temp") | ||
| 547 | - BR_PROPERTY(QString, imageName, "image") | ||
| 548 | - BR_PROPERTY(QString, imgExtension, "jpg") | ||
| 549 | - | ||
| 550 | - int cnt; | ||
| 551 | - | ||
| 552 | - void init() { | ||
| 553 | - cnt = 0; | ||
| 554 | - if (! QDir(outputDirectory).exists()) | ||
| 555 | - QDir().mkdir(outputDirectory); | ||
| 556 | - } | ||
| 557 | - | ||
| 558 | - void projectUpdate(const Template &src, Template &dst) | ||
| 559 | - { | ||
| 560 | - dst = src; | ||
| 561 | - OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, 10, QChar('0')).arg(imgExtension)); | ||
| 562 | - } | ||
| 563 | - | ||
| 564 | -}; | ||
| 565 | -BR_REGISTER(Transform, WriteImageTransform) | ||
| 566 | - | ||
| 567 | - | ||
| 568 | -/** | ||
| 569 | - * @brief The MeanImageTransform class computes the average template/image | ||
| 570 | - * and save the result as an encoded image. | ||
| 571 | - */ | ||
| 572 | -class MeanImageTransform : public TimeVaryingTransform | ||
| 573 | -{ | ||
| 574 | - Q_OBJECT | ||
| 575 | - | ||
| 576 | - Q_PROPERTY(QString imgname READ get_imgname WRITE set_imgname RESET reset_imgname STORED false) | ||
| 577 | - Q_PROPERTY(QString ext READ get_ext WRITE set_ext RESET reset_ext STORED false) | ||
| 578 | - | ||
| 579 | - BR_PROPERTY(QString, imgname, "average") | ||
| 580 | - BR_PROPERTY(QString, ext, "jpg") | ||
| 581 | - | ||
| 582 | - Mat average; | ||
| 583 | - int cnt; | ||
| 584 | - | ||
| 585 | - void init() | ||
| 586 | - { | ||
| 587 | - cnt = 0; | ||
| 588 | - } | ||
| 589 | - | ||
| 590 | - void projectUpdate(const Template &src, Template &dst) | ||
| 591 | - { | ||
| 592 | - dst = src; | ||
| 593 | - if (cnt == 0) { | ||
| 594 | - if (src.m().channels() == 1) | ||
| 595 | - average = Mat::zeros(dst.m().size(),CV_64FC1); | ||
| 596 | - else if (src.m().channels() == 3) | ||
| 597 | - average = Mat::zeros(dst.m().size(),CV_64FC3); | ||
| 598 | - else | ||
| 599 | - qFatal("Unsupported number of channels"); | ||
| 600 | - } | ||
| 601 | - | ||
| 602 | - Mat temp; | ||
| 603 | - if (src.m().channels() == 1) { | ||
| 604 | - src.m().convertTo(temp, CV_64FC1); | ||
| 605 | - average += temp; | ||
| 606 | - } else if (src.m().channels() == 3) { | ||
| 607 | - src.m().convertTo(temp, CV_64FC3); | ||
| 608 | - average += temp; | ||
| 609 | - } else | ||
| 610 | - qFatal("Unsupported number of channels"); | ||
| 611 | - | ||
| 612 | - cnt++; | ||
| 613 | - } | ||
| 614 | - | ||
| 615 | - virtual void finalize(TemplateList &output) | ||
| 616 | - { | ||
| 617 | - average /= float(cnt); | ||
| 618 | - imwrite(QString("%1.%2").arg(imgname).arg(ext).toStdString(), average); | ||
| 619 | - output = TemplateList(); | ||
| 620 | - } | ||
| 621 | - | ||
| 622 | - | ||
| 623 | -public: | ||
| 624 | - MeanImageTransform() : TimeVaryingTransform(false, false) {} | ||
| 625 | -}; | ||
| 626 | - | ||
| 627 | -BR_REGISTER(Transform, MeanImageTransform) | ||
| 628 | - | ||
| 629 | - | ||
| 630 | -// TODO: re-implement EditTransform using Qt | ||
| 631 | -#if 0 | ||
| 632 | -/*! | ||
| 633 | - * \ingroup transforms | ||
| 634 | - * \brief Remove landmarks. | ||
| 635 | - * \author Josh Klontz \cite jklontz | ||
| 636 | - */ | ||
| 637 | -class EditTransform : public UntrainableTransform | ||
| 638 | -{ | ||
| 639 | - Q_OBJECT | ||
| 640 | - | ||
| 641 | - Transform *draw; | ||
| 642 | - static Template currentTemplate; | ||
| 643 | - static QMutex currentTemplateLock; | ||
| 644 | - | ||
| 645 | - void init() | ||
| 646 | - { | ||
| 647 | - draw = make("Draw"); | ||
| 648 | - Globals->setProperty("parallelism", "0"); // Can only work in single threaded mode | ||
| 649 | - } | ||
| 650 | - | ||
| 651 | - void project(const Template &src, Template &dst) const | ||
| 652 | - { | ||
| 653 | - dst = src; | ||
| 654 | - | ||
| 655 | - if (Globals->parallelism) { | ||
| 656 | - qWarning("Edit::project() only works in single threaded mode."); | ||
| 657 | - return; | ||
| 658 | - } | ||
| 659 | - | ||
| 660 | - currentTemplateLock.lock(); | ||
| 661 | - currentTemplate = src; | ||
| 662 | - OpenCVUtils::showImage(src, "Edit", false); | ||
| 663 | - setMouseCallback("Edit", mouseCallback, (void*)this); | ||
| 664 | - mouseEvent(0, 0, 0, 0); | ||
| 665 | - waitKey(-1); | ||
| 666 | - dst = currentTemplate; | ||
| 667 | - currentTemplateLock.unlock(); | ||
| 668 | - } | ||
| 669 | - | ||
| 670 | - static void mouseCallback(int event, int x, int y, int flags, void *userdata) | ||
| 671 | - { | ||
| 672 | - ((const EditTransform*)userdata)->mouseEvent(event, x, y, flags); | ||
| 673 | - } | ||
| 674 | - | ||
| 675 | - void mouseEvent(int event, int x, int y, int flags) const | ||
| 676 | - { | ||
| 677 | - (void) event; | ||
| 678 | - if (flags) { | ||
| 679 | - QList<QRectF> rects = currentTemplate.file.rects(); | ||
| 680 | - for (int i=rects.size()-1; i>=0; i--) | ||
| 681 | - if (rects[i].contains(x,y)) | ||
| 682 | - rects.removeAt(i); | ||
| 683 | - currentTemplate.file.setRects(rects); | ||
| 684 | - } | ||
| 685 | - | ||
| 686 | - Template temp; | ||
| 687 | - draw->project(currentTemplate, temp); | ||
| 688 | - OpenCVUtils::showImage(temp, "Edit", false); | ||
| 689 | - } | ||
| 690 | -}; | ||
| 691 | - | ||
| 692 | -Template EditTransform::currentTemplate; | ||
| 693 | -QMutex EditTransform::currentTemplateLock; | ||
| 694 | - | ||
| 695 | -BR_REGISTER(Transform, EditTransform) | ||
| 696 | -#endif | ||
| 697 | - | ||
| 698 | -} // namespace br | ||
| 699 | - | ||
| 700 | -#include "draw.moc" |
openbr/plugins/eigen3.cpp
| @@ -652,46 +652,6 @@ class SparseLDATransform : public Transform | @@ -652,46 +652,6 @@ class SparseLDATransform : public Transform | ||
| 652 | 652 | ||
| 653 | BR_REGISTER(Transform, SparseLDATransform) | 653 | BR_REGISTER(Transform, SparseLDATransform) |
| 654 | 654 | ||
| 655 | -/*! | ||
| 656 | - * \ingroup distances | ||
| 657 | - * \brief L1 distance computed using eigen. | ||
| 658 | - * \author Josh Klontz \cite jklontz | ||
| 659 | - */ | ||
| 660 | -class L1Distance : public UntrainableDistance | ||
| 661 | -{ | ||
| 662 | - Q_OBJECT | ||
| 663 | - | ||
| 664 | - float compare(const cv::Mat &a, const cv::Mat &b) const | ||
| 665 | - { | ||
| 666 | - const int size = a.rows * a.cols; | ||
| 667 | - Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | ||
| 668 | - Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | ||
| 669 | - return (aMap-bMap).cwiseAbs().sum(); | ||
| 670 | - } | ||
| 671 | -}; | ||
| 672 | - | ||
| 673 | -BR_REGISTER(Distance, L1Distance) | ||
| 674 | - | ||
| 675 | -/*! | ||
| 676 | - * \ingroup distances | ||
| 677 | - * \brief L2 distance computed using eigen. | ||
| 678 | - * \author Josh Klontz \cite jklontz | ||
| 679 | - */ | ||
| 680 | -class L2Distance : public UntrainableDistance | ||
| 681 | -{ | ||
| 682 | - Q_OBJECT | ||
| 683 | - | ||
| 684 | - float compare(const cv::Mat &a, const cv::Mat &b) const | ||
| 685 | - { | ||
| 686 | - const int size = a.rows * a.cols; | ||
| 687 | - Eigen::Map<Eigen::VectorXf> aMap((float*)a.data, size); | ||
| 688 | - Eigen::Map<Eigen::VectorXf> bMap((float*)b.data, size); | ||
| 689 | - return (aMap-bMap).squaredNorm(); | ||
| 690 | - } | ||
| 691 | -}; | ||
| 692 | - | ||
| 693 | -BR_REGISTER(Distance, L2Distance) | ||
| 694 | - | ||
| 695 | } // namespace br | 655 | } // namespace br |
| 696 | 656 | ||
| 697 | #include "eigen3.moc" | 657 | #include "eigen3.moc" |
openbr/plugins/fill.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/photo/photo.hpp> | ||
| 18 | -#include "openbr_internal.h" | ||
| 19 | - | ||
| 20 | -using namespace cv; | ||
| 21 | - | ||
| 22 | -namespace br | ||
| 23 | -{ | ||
| 24 | - | ||
| 25 | -/*! | ||
| 26 | - * \ingroup transforms | ||
| 27 | - * \brief Wraps OpenCV inpainting | ||
| 28 | - * \author Josh Klontz \cite jklontz | ||
| 29 | - */ | ||
| 30 | -class InpaintTransform : public UntrainableTransform | ||
| 31 | -{ | ||
| 32 | - Q_OBJECT | ||
| 33 | - Q_ENUMS(Method) | ||
| 34 | - Q_PROPERTY(int radius READ get_radius WRITE set_radius RESET reset_radius STORED false) | ||
| 35 | - Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) | ||
| 36 | - | ||
| 37 | -public: | ||
| 38 | - /*!< */ | ||
| 39 | - enum Method { NavierStokes = INPAINT_NS, | ||
| 40 | - Telea = INPAINT_TELEA }; | ||
| 41 | - | ||
| 42 | -private: | ||
| 43 | - BR_PROPERTY(int, radius, 1) | ||
| 44 | - BR_PROPERTY(Method, method, NavierStokes) | ||
| 45 | - Transform *cvtGray; | ||
| 46 | - | ||
| 47 | - void init() | ||
| 48 | - { | ||
| 49 | - cvtGray = make("Cvt(Gray)"); | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - void project(const Template &src, Template &dst) const | ||
| 53 | - { | ||
| 54 | - inpaint(src, (*cvtGray)(src)<5, dst, radius, method); | ||
| 55 | - } | ||
| 56 | -}; | ||
| 57 | - | ||
| 58 | -BR_REGISTER(Transform, InpaintTransform) | ||
| 59 | - | ||
| 60 | -/*! | ||
| 61 | - * \ingroup transforms | ||
| 62 | - * \brief Fill 0 pixels with the mean of non-0 pixels. | ||
| 63 | - * \author Josh Klontz \cite jklontz | ||
| 64 | - */ | ||
| 65 | -class MeanFillTransform : public UntrainableTransform | ||
| 66 | -{ | ||
| 67 | - Q_OBJECT | ||
| 68 | - | ||
| 69 | - void project(const Template &src, Template &dst) const | ||
| 70 | - { | ||
| 71 | - dst = src.m().clone(); | ||
| 72 | - dst.m().setTo(mean(dst, dst.m()!=0), dst.m()==0); | ||
| 73 | - } | ||
| 74 | -}; | ||
| 75 | - | ||
| 76 | -BR_REGISTER(Transform, MeanFillTransform) | ||
| 77 | - | ||
| 78 | -/*! | ||
| 79 | - * \ingroup transforms | ||
| 80 | - * \brief Fill black pixels with the specified color. | ||
| 81 | - * \author Josh Klontz \cite jklontz | ||
| 82 | - */ | ||
| 83 | -class FloodTransform : public UntrainableTransform | ||
| 84 | -{ | ||
| 85 | - Q_OBJECT | ||
| 86 | - Q_PROPERTY(int r READ get_r WRITE set_r RESET reset_r STORED false) | ||
| 87 | - Q_PROPERTY(int g READ get_g WRITE set_g RESET reset_g STORED false) | ||
| 88 | - Q_PROPERTY(int b READ get_b WRITE set_b RESET reset_b STORED false) | ||
| 89 | - Q_PROPERTY(bool all READ get_all WRITE set_all RESET reset_all STORED false) | ||
| 90 | - BR_PROPERTY(int, r, 0) | ||
| 91 | - BR_PROPERTY(int, g, 0) | ||
| 92 | - BR_PROPERTY(int, b, 0) | ||
| 93 | - BR_PROPERTY(bool, all, false) | ||
| 94 | - | ||
| 95 | - void project(const Template &src, Template &dst) const | ||
| 96 | - { | ||
| 97 | - dst = src.m().clone(); | ||
| 98 | - dst.m().setTo(Scalar(r, g, b), all ? Mat() : dst.m()==0); | ||
| 99 | - } | ||
| 100 | -}; | ||
| 101 | - | ||
| 102 | -BR_REGISTER(Transform, FloodTransform) | ||
| 103 | - | ||
| 104 | -/*! | ||
| 105 | - * \ingroup transforms | ||
| 106 | - * \brief Alpha-blend two matrices | ||
| 107 | - * \author Josh Klontz \cite jklontz | ||
| 108 | - */ | ||
| 109 | -class BlendTransform : public UntrainableMetaTransform | ||
| 110 | -{ | ||
| 111 | - Q_OBJECT | ||
| 112 | - Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | ||
| 113 | - BR_PROPERTY(float, alpha, 0.5) | ||
| 114 | - | ||
| 115 | - void project(const Template &src, Template &dst) const | ||
| 116 | - { | ||
| 117 | - if (src.size() != 2) qFatal("Expected two source matrices."); | ||
| 118 | - addWeighted(src[0], alpha, src[1], 1-alpha, 0, dst); | ||
| 119 | - } | ||
| 120 | -}; | ||
| 121 | - | ||
| 122 | -BR_REGISTER(Transform, BlendTransform) | ||
| 123 | - | ||
| 124 | -} // namespace br | ||
| 125 | - | ||
| 126 | -#include "fill.moc" |
openbr/plugins/filter.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 18 | -#include "openbr_internal.h" | ||
| 19 | -#include "openbr/core/tanh_sse.h" | ||
| 20 | - | ||
| 21 | -using namespace cv; | ||
| 22 | - | ||
| 23 | -namespace br | ||
| 24 | -{ | ||
| 25 | - | ||
| 26 | -/*! | ||
| 27 | - * \ingroup transforms | ||
| 28 | - * \brief Gamma correction | ||
| 29 | - * \author Josh Klontz \cite jklontz | ||
| 30 | - */ | ||
| 31 | -class GammaTransform : public UntrainableTransform | ||
| 32 | -{ | ||
| 33 | - Q_OBJECT | ||
| 34 | - Q_PROPERTY(float gamma READ get_gamma WRITE set_gamma RESET reset_gamma STORED false) | ||
| 35 | - BR_PROPERTY(float, gamma, 0.2) | ||
| 36 | - | ||
| 37 | - Mat lut; | ||
| 38 | - | ||
| 39 | - void init() | ||
| 40 | - { | ||
| 41 | - lut.create(256, 1, CV_32FC1); | ||
| 42 | - if (gamma == 0) for (int i=0; i<256; i++) lut.at<float>(i,0) = log((float)i); | ||
| 43 | - else for (int i=0; i<256; i++) lut.at<float>(i,0) = pow(i, gamma); | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - void project(const Template &src, Template &dst) const | ||
| 47 | - { | ||
| 48 | - if (src.m().depth() == CV_8U) LUT(src, lut, dst); | ||
| 49 | - else pow(src, gamma, dst); | ||
| 50 | - } | ||
| 51 | -}; | ||
| 52 | - | ||
| 53 | -BR_REGISTER(Transform, GammaTransform) | ||
| 54 | - | ||
| 55 | -/*! | ||
| 56 | - * \ingroup transforms | ||
| 57 | - * \brief Gaussian blur | ||
| 58 | - * \author Josh Klontz \cite jklontz | ||
| 59 | - */ | ||
| 60 | -class BlurTransform : public UntrainableTransform | ||
| 61 | -{ | ||
| 62 | - Q_OBJECT | ||
| 63 | - Q_PROPERTY(float sigma READ get_sigma WRITE set_sigma RESET reset_sigma STORED false) | ||
| 64 | - Q_PROPERTY(bool ROI READ get_ROI WRITE set_ROI RESET reset_ROI STORED false) | ||
| 65 | - BR_PROPERTY(float, sigma, 1) | ||
| 66 | - BR_PROPERTY(bool, ROI, false) | ||
| 67 | - | ||
| 68 | - void project(const Template &src, Template &dst) const | ||
| 69 | - { | ||
| 70 | - if (!ROI) GaussianBlur(src, dst, Size(0,0), sigma); | ||
| 71 | - else { | ||
| 72 | - dst.m() = src.m(); | ||
| 73 | - foreach (const QRectF &rect, src.file.rects()) { | ||
| 74 | - Rect region(rect.x(), rect.y(), rect.width(), rect.height()); | ||
| 75 | - Mat input = dst.m(); | ||
| 76 | - Mat output = input.clone(); | ||
| 77 | - GaussianBlur(input(region), output(region), Size(0,0), sigma); | ||
| 78 | - dst.m() = output; | ||
| 79 | - } | ||
| 80 | - } | ||
| 81 | - } | ||
| 82 | -}; | ||
| 83 | - | ||
| 84 | -BR_REGISTER(Transform, BlurTransform) | ||
| 85 | - | ||
| 86 | -/*! | ||
| 87 | - * \ingroup transforms | ||
| 88 | - * \brief Difference of gaussians | ||
| 89 | - * \author Josh Klontz \cite jklontz | ||
| 90 | - */ | ||
| 91 | -class DoGTransform : public UntrainableTransform | ||
| 92 | -{ | ||
| 93 | - Q_OBJECT | ||
| 94 | - Q_PROPERTY(float sigma0 READ get_sigma0 WRITE set_sigma0 RESET reset_sigma0 STORED false) | ||
| 95 | - Q_PROPERTY(float sigma1 READ get_sigma1 WRITE set_sigma1 RESET reset_sigma1 STORED false) | ||
| 96 | - BR_PROPERTY(float, sigma0, 1) | ||
| 97 | - BR_PROPERTY(float, sigma1, 2) | ||
| 98 | - | ||
| 99 | - Size ksize0, ksize1; | ||
| 100 | - | ||
| 101 | - static Size getKernelSize(double sigma) | ||
| 102 | - { | ||
| 103 | - // Inverts OpenCV's conversion from kernel size to sigma: | ||
| 104 | - // sigma = ((ksize-1)*0.5 - 1)*0.3 + 0.8 | ||
| 105 | - // See documentation for cv::getGaussianKernel() | ||
| 106 | - int ksize = ((sigma - 0.8) / 0.3 + 1) * 2 + 1; | ||
| 107 | - if (ksize % 2 == 0) ksize++; | ||
| 108 | - return Size(ksize, ksize); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - void init() | ||
| 112 | - { | ||
| 113 | - ksize0 = getKernelSize(sigma0); | ||
| 114 | - ksize1 = getKernelSize(sigma1); | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - void project(const Template &src, Template &dst) const | ||
| 118 | - { | ||
| 119 | - Mat g0, g1; | ||
| 120 | - GaussianBlur(src, g0, ksize0, 0); | ||
| 121 | - GaussianBlur(src, g1, ksize1, 0); | ||
| 122 | - subtract(g0, g1, dst); | ||
| 123 | - } | ||
| 124 | -}; | ||
| 125 | - | ||
| 126 | -BR_REGISTER(Transform, DoGTransform) | ||
| 127 | - | ||
| 128 | -/*! | ||
| 129 | - * \ingroup transforms | ||
| 130 | - * \brief Meyers, E.; Wolf, L. | ||
| 131 | - * “Using biologically inspired features for face processing,” | ||
| 132 | - * Int. Journal of Computer Vision, vol. 76, no. 1, pp 93–104, 2008. | ||
| 133 | - * \author Scott Klum \cite sklum | ||
| 134 | - */ | ||
| 135 | - | ||
| 136 | -class CSDNTransform : public UntrainableTransform | ||
| 137 | -{ | ||
| 138 | - Q_OBJECT | ||
| 139 | - | ||
| 140 | - Q_PROPERTY(float s READ get_s WRITE set_s RESET reset_s STORED false) | ||
| 141 | - BR_PROPERTY(int, s, 16) | ||
| 142 | - | ||
| 143 | - void project(const Template &src, Template &dst) const | ||
| 144 | - { | ||
| 145 | - if (src.m().channels() != 1) qFatal("Expected single channel source matrix."); | ||
| 146 | - | ||
| 147 | - const int nRows = src.m().rows; | ||
| 148 | - const int nCols = src.m().cols; | ||
| 149 | - | ||
| 150 | - Mat m; | ||
| 151 | - src.m().convertTo(m, CV_32FC1); | ||
| 152 | - | ||
| 153 | - const int surround = s/2; | ||
| 154 | - | ||
| 155 | - for ( int i = 0; i < nRows; i++ ) { | ||
| 156 | - for ( int j = 0; j < nCols; j++ ) { | ||
| 157 | - int width = min( j+surround, nCols ) - max( 0, j-surround ); | ||
| 158 | - int height = min( i+surround, nRows ) - max( 0, i-surround ); | ||
| 159 | - | ||
| 160 | - Rect_<int> ROI(max(0, j-surround), max(0, i-surround), width, height); | ||
| 161 | - | ||
| 162 | - Scalar_<float> avg = mean(m(ROI)); | ||
| 163 | - | ||
| 164 | - m.at<float>(i,j) = m.at<float>(i,j) - avg[0]; | ||
| 165 | - } | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - dst = m; | ||
| 169 | - | ||
| 170 | - } | ||
| 171 | -}; | ||
| 172 | - | ||
| 173 | -BR_REGISTER(Transform, CSDNTransform) | ||
| 174 | - | ||
| 175 | -/*! | ||
| 176 | - * \ingroup transforms | ||
| 177 | - * \brief Xiaoyang Tan; Triggs, B.; | ||
| 178 | - * "Enhanced Local Texture Feature Sets for Face Recognition Under Difficult Lighting Conditions," | ||
| 179 | - * Image Processing, IEEE Transactions on , vol.19, no.6, pp.1635-1650, June 2010 | ||
| 180 | - * \author Josh Klontz \cite jklontz | ||
| 181 | - */ | ||
| 182 | -class ContrastEqTransform : public UntrainableTransform | ||
| 183 | -{ | ||
| 184 | - Q_OBJECT | ||
| 185 | - Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a STORED false) | ||
| 186 | - Q_PROPERTY(float t READ get_t WRITE set_t RESET reset_t STORED false) | ||
| 187 | - BR_PROPERTY(float, a, 1) | ||
| 188 | - BR_PROPERTY(float, t, 0.1) | ||
| 189 | - | ||
| 190 | - void project(const Template &src, Template &dst) const | ||
| 191 | - { | ||
| 192 | - if (src.m().channels() != 1) qFatal("Expected single channel source matrix."); | ||
| 193 | - | ||
| 194 | - // Stage 1 | ||
| 195 | - Mat stage1; | ||
| 196 | - { | ||
| 197 | - Mat abs_dst; | ||
| 198 | - absdiff(src, Scalar(0), abs_dst); | ||
| 199 | - Mat pow_dst; | ||
| 200 | - pow(abs_dst, a, pow_dst); | ||
| 201 | - float denominator = pow((float)mean(pow_dst)[0], 1.f/a); | ||
| 202 | - src.m().convertTo(stage1, CV_32F, 1/denominator); | ||
| 203 | - } | ||
| 204 | - | ||
| 205 | - // Stage 2 | ||
| 206 | - Mat stage2; | ||
| 207 | - { | ||
| 208 | - Mat abs_dst; | ||
| 209 | - absdiff(stage1, Scalar(0), abs_dst); | ||
| 210 | - Mat min_dst; | ||
| 211 | - min(abs_dst, t, min_dst); | ||
| 212 | - Mat pow_dst; | ||
| 213 | - pow(min_dst, a, pow_dst); | ||
| 214 | - float denominator = pow((float)mean(pow_dst)[0], 1.f/a); | ||
| 215 | - stage1.convertTo(stage2, CV_32F, 1/denominator); | ||
| 216 | - } | ||
| 217 | - | ||
| 218 | - // Hyperbolic tangent | ||
| 219 | - const int nRows = src.m().rows; | ||
| 220 | - const int nCols = src.m().cols; | ||
| 221 | - const float* p = (const float*)stage2.ptr(); | ||
| 222 | - Mat m(nRows, nCols, CV_32FC1); | ||
| 223 | - for (int i=0; i<nRows; i++) | ||
| 224 | - for (int j=0; j<nCols; j++) | ||
| 225 | - m.at<float>(i, j) = fast_tanh(p[i*nCols+j]); | ||
| 226 | - // TODO: m.at<float>(i, j) = t * fast_tanh(p[i*nCols+j] / t); | ||
| 227 | - | ||
| 228 | - dst = m; | ||
| 229 | - } | ||
| 230 | -}; | ||
| 231 | - | ||
| 232 | -BR_REGISTER(Transform, ContrastEqTransform) | ||
| 233 | - | ||
| 234 | -/*! | ||
| 235 | - * \ingroup transforms | ||
| 236 | - * \brief Raise each element to the specified power. | ||
| 237 | - * \author Josh Klontz \cite jklontz | ||
| 238 | - */ | ||
| 239 | -class PowTransform : public UntrainableTransform | ||
| 240 | -{ | ||
| 241 | - Q_OBJECT | ||
| 242 | - Q_PROPERTY(float power READ get_power WRITE set_power RESET reset_power STORED false) | ||
| 243 | - Q_PROPERTY(bool preserveSign READ get_preserveSign WRITE set_preserveSign RESET reset_preserveSign STORED false) | ||
| 244 | - BR_PROPERTY(float, power, 2) | ||
| 245 | - BR_PROPERTY(bool, preserveSign, false) | ||
| 246 | - | ||
| 247 | - void project(const Template &src, Template &dst) const | ||
| 248 | - { | ||
| 249 | - pow(preserveSign ? abs(src) : src.m(), power, dst); | ||
| 250 | - if (preserveSign) subtract(Scalar::all(0), dst, dst, src.m() < 0); | ||
| 251 | - } | ||
| 252 | -}; | ||
| 253 | - | ||
| 254 | -BR_REGISTER(Transform, PowTransform) | ||
| 255 | - | ||
| 256 | -} // namespace br | ||
| 257 | - | ||
| 258 | -#include "filter.moc" |
openbr/plugins/format.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <QDate> | ||
| 18 | -#include <QSize> | ||
| 19 | -#include <QChar> | ||
| 20 | -#ifndef BR_EMBEDDED | ||
| 21 | -#include <QtXml> | ||
| 22 | -#endif // BR_EMBEDDED | ||
| 23 | -#include <QFile> | ||
| 24 | -#include <QFileInfo> | ||
| 25 | - | ||
| 26 | -#include <opencv2/highgui/highgui.hpp> | ||
| 27 | -#include <opencv2/highgui/highgui_c.h> | ||
| 28 | -#include "openbr_internal.h" | ||
| 29 | - | ||
| 30 | -#include "openbr/core/bee.h" | ||
| 31 | -#include "openbr/core/opencvutils.h" | ||
| 32 | -#include "openbr/core/qtutils.h" | ||
| 33 | - | ||
| 34 | -using namespace cv; | ||
| 35 | - | ||
| 36 | -namespace br | ||
| 37 | -{ | ||
| 38 | - | ||
| 39 | - /*! | ||
| 40 | - * \ingroup formats | ||
| 41 | - * \brief Read all frames of a video using OpenCV | ||
| 42 | - * \author Charles Otto \cite caotto | ||
| 43 | - */ | ||
| 44 | -class videoFormat : public Format | ||
| 45 | -{ | ||
| 46 | - Q_OBJECT | ||
| 47 | - | ||
| 48 | -public: | ||
| 49 | - Template read() const | ||
| 50 | - { | ||
| 51 | - if (!file.exists() ) | ||
| 52 | - return Template(); | ||
| 53 | - | ||
| 54 | - VideoCapture videoSource(file.name.toStdString()); | ||
| 55 | - videoSource.open(file.name.toStdString() ); | ||
| 56 | - | ||
| 57 | - | ||
| 58 | - Template frames; | ||
| 59 | - if (!videoSource.isOpened()) { | ||
| 60 | - qWarning("video file open failed"); | ||
| 61 | - return frames; | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - bool open = true; | ||
| 65 | - while (open) { | ||
| 66 | - cv::Mat frame; | ||
| 67 | - open = videoSource.read(frame); | ||
| 68 | - if (!open) break; | ||
| 69 | - | ||
| 70 | - frames.append(cv::Mat()); | ||
| 71 | - frames.back() = frame.clone(); | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - return frames; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - void write(const Template &t) const | ||
| 78 | - { | ||
| 79 | - int fourcc = OpenCVUtils::getFourcc(); | ||
| 80 | - VideoWriter videoSink(file.name.toStdString(), fourcc, 30, t.begin()->size()); | ||
| 81 | - | ||
| 82 | - // Did we successfully open the output file? | ||
| 83 | - if (!videoSink.isOpened() ) qFatal("Failed to open output file"); | ||
| 84 | - | ||
| 85 | - for (Template::const_iterator it = t.begin(); it!= t.end(); ++it) { | ||
| 86 | - videoSink << *it; | ||
| 87 | - } | ||
| 88 | - } | ||
| 89 | -}; | ||
| 90 | - | ||
| 91 | -BR_REGISTER(Format, videoFormat) | ||
| 92 | - | ||
| 93 | -/*! | ||
| 94 | - * \ingroup formats | ||
| 95 | - * \brief A simple binary matrix format. | ||
| 96 | - * \author Josh Klontz \cite jklontz | ||
| 97 | - * First 4 bytes indicate the number of rows. | ||
| 98 | - * Second 4 bytes indicate the number of columns. | ||
| 99 | - * The rest of the bytes are 32-bit floating data elements in row-major order. | ||
| 100 | - */ | ||
| 101 | -class binFormat : public Format | ||
| 102 | -{ | ||
| 103 | - Q_OBJECT | ||
| 104 | - Q_PROPERTY(bool raw READ get_raw WRITE set_raw RESET reset_raw STORED false) | ||
| 105 | - BR_PROPERTY(bool, raw, false) | ||
| 106 | - | ||
| 107 | - Template read() const | ||
| 108 | - { | ||
| 109 | - QByteArray data; | ||
| 110 | - QtUtils::readFile(file, data); | ||
| 111 | - if (raw) { | ||
| 112 | - return Template(file, Mat(1, data.size(), CV_8UC1, data.data()).clone()); | ||
| 113 | - } else { | ||
| 114 | - return Template(file, Mat(((quint32*)data.data())[0], | ||
| 115 | - ((quint32*)data.data())[1], | ||
| 116 | - CV_32FC1, | ||
| 117 | - data.data()+8).clone()); | ||
| 118 | - } | ||
| 119 | - } | ||
| 120 | - | ||
| 121 | - void write(const Template &t) const | ||
| 122 | - { | ||
| 123 | - QFile f(file); | ||
| 124 | - QtUtils::touchDir(f); | ||
| 125 | - if (!f.open(QFile::WriteOnly)) | ||
| 126 | - qFatal("Failed to open %s for writing.", qPrintable(file)); | ||
| 127 | - | ||
| 128 | - Mat m; | ||
| 129 | - if (!raw) { | ||
| 130 | - if (t.m().type() != CV_32FC1) | ||
| 131 | - t.m().convertTo(m, CV_32F); | ||
| 132 | - else m = t.m(); | ||
| 133 | - | ||
| 134 | - if (m.channels() != 1) qFatal("Only supports single channel matrices."); | ||
| 135 | - | ||
| 136 | - f.write((const char *) &m.rows, 4); | ||
| 137 | - f.write((const char *) &m.cols, 4); | ||
| 138 | - } | ||
| 139 | - else m = t.m(); | ||
| 140 | - | ||
| 141 | - qint64 rowSize = m.cols * sizeof(float); | ||
| 142 | - for (int i=0; i < m.rows; i++) | ||
| 143 | - { | ||
| 144 | - f.write((const char *) m.row(i).data, rowSize); | ||
| 145 | - } | ||
| 146 | - f.close(); | ||
| 147 | - } | ||
| 148 | -}; | ||
| 149 | - | ||
| 150 | -BR_REGISTER(Format, binFormat) | ||
| 151 | - | ||
| 152 | -/*! | ||
| 153 | - * \ingroup formats | ||
| 154 | - * \brief Reads a comma separated value file. | ||
| 155 | - * \author Josh Klontz \cite jklontz | ||
| 156 | - */ | ||
| 157 | -class csvFormat : public Format | ||
| 158 | -{ | ||
| 159 | - Q_OBJECT | ||
| 160 | - | ||
| 161 | - Template read() const | ||
| 162 | - { | ||
| 163 | - QFile f(file.name); | ||
| 164 | - f.open(QFile::ReadOnly); | ||
| 165 | - QStringList lines(QString(f.readAll()).split(QRegularExpression("[\n|\r\n|\r]"), QString::SkipEmptyParts)); | ||
| 166 | - f.close(); | ||
| 167 | - | ||
| 168 | - bool isUChar = true; | ||
| 169 | - QList< QList<float> > valsList; | ||
| 170 | - foreach (const QString &line, lines) { | ||
| 171 | - QList<float> vals; | ||
| 172 | - foreach (const QString &word, line.split(QRegExp(" *, *"), QString::SkipEmptyParts)) { | ||
| 173 | - bool ok; | ||
| 174 | - const float val = word.toFloat(&ok); | ||
| 175 | - vals.append(val); | ||
| 176 | - isUChar = isUChar && (val == float(uchar(val))); | ||
| 177 | - } | ||
| 178 | - if (!vals.isEmpty()) | ||
| 179 | - valsList.append(vals); | ||
| 180 | - } | ||
| 181 | - | ||
| 182 | - Mat m(valsList.size(), valsList[0].size(), CV_32FC1); | ||
| 183 | - for (int i=0; i<valsList.size(); i++) | ||
| 184 | - for (int j=0; j<valsList[i].size(); j++) | ||
| 185 | - m.at<float>(i,j) = valsList[i][j]; | ||
| 186 | - | ||
| 187 | - if (isUChar) m.convertTo(m, CV_8U); | ||
| 188 | - return Template(m); | ||
| 189 | - } | ||
| 190 | - | ||
| 191 | - void write(const Template &t) const | ||
| 192 | - { | ||
| 193 | - const Mat &m = t.m(); | ||
| 194 | - if (t.size() != 1) qFatal("Only supports single matrix templates."); | ||
| 195 | - if (m.channels() != 1) qFatal("Only supports single channel matrices."); | ||
| 196 | - | ||
| 197 | - QStringList lines; lines.reserve(m.rows); | ||
| 198 | - for (int r=0; r<m.rows; r++) { | ||
| 199 | - QStringList elements; elements.reserve(m.cols); | ||
| 200 | - for (int c=0; c<m.cols; c++) | ||
| 201 | - elements.append(OpenCVUtils::elemToString(m, r, c)); | ||
| 202 | - lines.append(elements.join(",")); | ||
| 203 | - } | ||
| 204 | - | ||
| 205 | - QtUtils::writeFile(file, lines); | ||
| 206 | - } | ||
| 207 | -}; | ||
| 208 | - | ||
| 209 | -BR_REGISTER(Format, csvFormat) | ||
| 210 | - | ||
| 211 | -/*! | ||
| 212 | - * \ingroup formats | ||
| 213 | - * \brief Reads image files. | ||
| 214 | - * \author Josh Klontz \cite jklontz | ||
| 215 | - */ | ||
| 216 | -class DefaultFormat : public Format | ||
| 217 | -{ | ||
| 218 | - Q_OBJECT | ||
| 219 | - | ||
| 220 | - Template read() const | ||
| 221 | - { | ||
| 222 | - Template t; | ||
| 223 | - | ||
| 224 | - if (file.name.startsWith("http://") || file.name.startsWith("https://") || file.name.startsWith("www.")) { | ||
| 225 | - if (Factory<Format>::names().contains("url")) { | ||
| 226 | - File urlFile = file; | ||
| 227 | - urlFile.name.append(".url"); | ||
| 228 | - QScopedPointer<Format> url(Factory<Format>::make(urlFile)); | ||
| 229 | - t = url->read(); | ||
| 230 | - } | ||
| 231 | - } else { | ||
| 232 | - Mat m = imread(file.resolved().toStdString()); | ||
| 233 | - if (m.data) { | ||
| 234 | - t.append(m); | ||
| 235 | - } else { | ||
| 236 | - videoFormat videoReader; | ||
| 237 | - videoReader.file = file; | ||
| 238 | - t = videoReader.read(); | ||
| 239 | - } | ||
| 240 | - } | ||
| 241 | - | ||
| 242 | - return t; | ||
| 243 | - } | ||
| 244 | - | ||
| 245 | - void write(const Template &t) const | ||
| 246 | - { | ||
| 247 | - if (t.size() > 1) { | ||
| 248 | - videoFormat videoWriter; | ||
| 249 | - videoWriter.file = file; | ||
| 250 | - videoWriter.write(t); | ||
| 251 | - } else if (t.size() == 1) { | ||
| 252 | - QtUtils::touchDir(QDir(file.path())); | ||
| 253 | - imwrite(file.name.toStdString(), t); | ||
| 254 | - } | ||
| 255 | - } | ||
| 256 | -}; | ||
| 257 | - | ||
| 258 | -BR_REGISTER(Format, DefaultFormat) | ||
| 259 | - | ||
| 260 | -/*! | ||
| 261 | - * \ingroup formats | ||
| 262 | - * \brief Reads a NIST LFFS file. | ||
| 263 | - * \author Josh Klontz \cite jklontz | ||
| 264 | - */ | ||
| 265 | -class lffsFormat : public Format | ||
| 266 | -{ | ||
| 267 | - Q_OBJECT | ||
| 268 | - | ||
| 269 | - Template read() const | ||
| 270 | - { | ||
| 271 | - QByteArray byteArray; | ||
| 272 | - QtUtils::readFile(file.name, byteArray); | ||
| 273 | - return Mat(1, byteArray.size(), CV_8UC1, byteArray.data()).clone(); | ||
| 274 | - } | ||
| 275 | - | ||
| 276 | - void write(const Template &t) const | ||
| 277 | - { | ||
| 278 | - QByteArray byteArray((const char*)t.m().data, t.m().total()*t.m().elemSize()); | ||
| 279 | - QtUtils::writeFile(file.name, byteArray); | ||
| 280 | - } | ||
| 281 | -}; | ||
| 282 | - | ||
| 283 | -BR_REGISTER(Format, lffsFormat) | ||
| 284 | - | ||
| 285 | -/*! | ||
| 286 | - * \ingroup formats | ||
| 287 | - * \brief Reads a NIST BEE similarity matrix. | ||
| 288 | - * \author Josh Klontz \cite jklontz | ||
| 289 | - */ | ||
| 290 | -class mtxFormat : public Format | ||
| 291 | -{ | ||
| 292 | - Q_OBJECT | ||
| 293 | - | ||
| 294 | - Template read() const | ||
| 295 | - { | ||
| 296 | - QString target, query; | ||
| 297 | - Template result = BEE::readMatrix(file, &target, &query); | ||
| 298 | - result.file.set("Target", target); | ||
| 299 | - result.file.set("Query", query); | ||
| 300 | - return result; | ||
| 301 | - } | ||
| 302 | - | ||
| 303 | - void write(const Template &t) const | ||
| 304 | - { | ||
| 305 | - BEE::writeMatrix(t, file); | ||
| 306 | - } | ||
| 307 | -}; | ||
| 308 | - | ||
| 309 | -BR_REGISTER(Format, mtxFormat) | ||
| 310 | - | ||
| 311 | -/*! | ||
| 312 | - * \ingroup formats | ||
| 313 | - * \brief Reads a NIST BEE mask matrix. | ||
| 314 | - * \author Josh Klontz \cite jklontz | ||
| 315 | - */ | ||
| 316 | -class maskFormat : public mtxFormat | ||
| 317 | -{ | ||
| 318 | - Q_OBJECT | ||
| 319 | -}; | ||
| 320 | - | ||
| 321 | -BR_REGISTER(Format, maskFormat) | ||
| 322 | - | ||
| 323 | -/*! | ||
| 324 | - * \ingroup formats | ||
| 325 | - * \brief MATLAB <tt>.mat</tt> format. | ||
| 326 | - * \author Josh Klontz \cite jklontz | ||
| 327 | - * http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf | ||
| 328 | - * \note matFormat is known not to work with compressed matrices | ||
| 329 | - */ | ||
| 330 | -class matFormat : public Format | ||
| 331 | -{ | ||
| 332 | - Q_OBJECT | ||
| 333 | - | ||
| 334 | - struct Element | ||
| 335 | - { | ||
| 336 | - // It is always best to cast integers to a Qt integer type, such as qint16 or quint32, when reading and writing. | ||
| 337 | - // This ensures that you always know exactly what size integers you are reading and writing, no matter what the | ||
| 338 | - // underlying platform and architecture the application happens to be running on. | ||
| 339 | - // http://qt-project.org/doc/qt-4.8/datastreamformat.html | ||
| 340 | - quint32 type, bytes; | ||
| 341 | - QByteArray data; | ||
| 342 | - Element() : type(0), bytes(0) {} | ||
| 343 | - Element(QDataStream &stream) | ||
| 344 | - : type(0), bytes(0) | ||
| 345 | - { | ||
| 346 | - // Read first 4 bytes into type (32 bit integer), | ||
| 347 | - // specifying the type of data used | ||
| 348 | - if (stream.readRawData((char*)&type, 4) != 4) | ||
| 349 | - qFatal("Unexpected end of file."); | ||
| 350 | - | ||
| 351 | - if (type >= 1 << 16) { | ||
| 352 | - // Small data format | ||
| 353 | - bytes = type; | ||
| 354 | - type = type & 0x0000FFFF; | ||
| 355 | - bytes = bytes >> 16; | ||
| 356 | - } else { | ||
| 357 | - // Regular format | ||
| 358 | - // Read 4 bytes into bytes (32 bit integer), | ||
| 359 | - // specifying the size of the element | ||
| 360 | - if (stream.readRawData((char*)&bytes, 4) != 4) | ||
| 361 | - qFatal("Unexpected end of file."); | ||
| 362 | - } | ||
| 363 | - | ||
| 364 | - // Set the size of data to bytes | ||
| 365 | - data.resize(bytes); | ||
| 366 | - | ||
| 367 | - // Read bytes amount of data from the file into data | ||
| 368 | - if (int(bytes) != stream.readRawData(data.data(), bytes)) | ||
| 369 | - qFatal("Unexpected end of file."); | ||
| 370 | - | ||
| 371 | - // Alignment | ||
| 372 | - int skipBytes = (bytes < 4) ? (4 - bytes) : (8 - bytes%8)%8; | ||
| 373 | - if (skipBytes != 0) stream.skipRawData(skipBytes); | ||
| 374 | - } | ||
| 375 | - }; | ||
| 376 | - | ||
| 377 | - Template read() const | ||
| 378 | - { | ||
| 379 | - QByteArray byteArray; | ||
| 380 | - QtUtils::readFile(file, byteArray); | ||
| 381 | - QDataStream f(byteArray); | ||
| 382 | - | ||
| 383 | - { // Check header | ||
| 384 | - QByteArray header(128, 0); | ||
| 385 | - f.readRawData(header.data(), 128); | ||
| 386 | - if (!header.startsWith("MATLAB 5.0 MAT-file")) | ||
| 387 | - qFatal("Invalid MAT header."); | ||
| 388 | - } | ||
| 389 | - | ||
| 390 | - Template t(file); | ||
| 391 | - | ||
| 392 | - while (!f.atEnd()) { | ||
| 393 | - Element element(f); | ||
| 394 | - | ||
| 395 | - // miCOMPRESSED | ||
| 396 | - if (element.type == 15) { | ||
| 397 | - // Prepend the number of bytes to element.data | ||
| 398 | - element.data.prepend((char*)&element.bytes, 4); // Qt zlib wrapper requires this to preallocate the buffer | ||
| 399 | - QDataStream uncompressed(qUncompress(element.data)); | ||
| 400 | - element = Element(uncompressed); | ||
| 401 | - } | ||
| 402 | - | ||
| 403 | - // miMATRIX | ||
| 404 | - if (element.type == 14) { | ||
| 405 | - QDataStream matrix(element.data); | ||
| 406 | - qint32 rows = 0, columns = 0; | ||
| 407 | - int matrixType = 0; | ||
| 408 | - QByteArray matrixData; | ||
| 409 | - while (!matrix.atEnd()) { | ||
| 410 | - Element subelement(matrix); | ||
| 411 | - if (subelement.type == 5) { // Dimensions array | ||
| 412 | - if (subelement.bytes == 8) { | ||
| 413 | - rows = ((qint32*)subelement.data.data())[0]; | ||
| 414 | - columns = ((qint32*)subelement.data.data())[1]; | ||
| 415 | - } else { | ||
| 416 | - qWarning("matFormat::read can only handle 2D arrays."); | ||
| 417 | - } | ||
| 418 | - } else if (subelement.type == 7) { //miSINGLE | ||
| 419 | - matrixType = CV_32FC1; | ||
| 420 | - matrixData = subelement.data; | ||
| 421 | - } else if (subelement.type == 9) { //miDOUBLE | ||
| 422 | - matrixType = CV_64FC1; | ||
| 423 | - matrixData = subelement.data; | ||
| 424 | - } | ||
| 425 | - } | ||
| 426 | - | ||
| 427 | - if ((rows > 0) && (columns > 0) && (matrixType != 0) && !matrixData.isEmpty()) { | ||
| 428 | - Mat transposed; | ||
| 429 | - transpose(Mat(columns, rows, matrixType, matrixData.data()), transposed); | ||
| 430 | - t.append(transposed); | ||
| 431 | - } | ||
| 432 | - } | ||
| 433 | - } | ||
| 434 | - | ||
| 435 | - return t; | ||
| 436 | - } | ||
| 437 | - | ||
| 438 | - void write(const Template &t) const | ||
| 439 | - { | ||
| 440 | - QByteArray data; | ||
| 441 | - QDataStream stream(&data, QFile::WriteOnly); | ||
| 442 | - | ||
| 443 | - { // Header | ||
| 444 | - QByteArray header = "MATLAB 5.0 MAT-file; Made with OpenBR | www.openbiometrics.org\n"; | ||
| 445 | - QByteArray buffer(116-header.size(), 0); | ||
| 446 | - stream.writeRawData(header.data(), header.size()); | ||
| 447 | - stream.writeRawData(buffer.data(), buffer.size()); | ||
| 448 | - quint64 subsystem = 0; | ||
| 449 | - quint16 version = 0x0100; | ||
| 450 | - const char *endianness = "IM"; | ||
| 451 | - stream.writeRawData((const char*)&subsystem, 8); | ||
| 452 | - stream.writeRawData((const char*)&version, 2); | ||
| 453 | - stream.writeRawData(endianness, 2); | ||
| 454 | - } | ||
| 455 | - | ||
| 456 | - for (int i=0; i<t.size(); i++) { | ||
| 457 | - const Mat &m = t[i]; | ||
| 458 | - if (m.channels() != 1) qFatal("Only supports single channel matrices."); | ||
| 459 | - | ||
| 460 | - QByteArray subdata; | ||
| 461 | - QDataStream substream(&subdata, QFile::WriteOnly); | ||
| 462 | - | ||
| 463 | - { // Array Flags | ||
| 464 | - quint32 type = 6; | ||
| 465 | - quint32 bytes = 8; | ||
| 466 | - quint64 arrayClass = 0; | ||
| 467 | - switch (m.type()) { | ||
| 468 | - case CV_64FC1: arrayClass = 6; break; | ||
| 469 | - case CV_32FC1: arrayClass = 7; break; | ||
| 470 | - case CV_8UC1: arrayClass = 8; break; | ||
| 471 | - case CV_8SC1: arrayClass = 9; break; | ||
| 472 | - case CV_16UC1: arrayClass = 10; break; | ||
| 473 | - case CV_16SC1: arrayClass = 11; break; | ||
| 474 | - case CV_32SC1: arrayClass = 12; break; | ||
| 475 | - default: qFatal("Unsupported matrix class."); | ||
| 476 | - } | ||
| 477 | - substream.writeRawData((const char*)&type, 4); | ||
| 478 | - substream.writeRawData((const char*)&bytes, 4); | ||
| 479 | - substream.writeRawData((const char*)&arrayClass, 8); | ||
| 480 | - } | ||
| 481 | - | ||
| 482 | - { // Dimensions Array | ||
| 483 | - quint32 type = 5; | ||
| 484 | - quint32 bytes = 8; | ||
| 485 | - substream.writeRawData((const char*)&type, 4); | ||
| 486 | - substream.writeRawData((const char*)&bytes, 4); | ||
| 487 | - substream.writeRawData((const char*)&m.rows, 4); | ||
| 488 | - substream.writeRawData((const char*)&m.cols, 4); | ||
| 489 | - } | ||
| 490 | - | ||
| 491 | - { // Array Name | ||
| 492 | - QByteArray name(qPrintable(QString("OpenBR_%1").arg(QString::number(i)))); | ||
| 493 | - quint32 type = 1; | ||
| 494 | - quint32 bytes = name.size(); | ||
| 495 | - QByteArray buffer((8 - bytes%8)%8, 0); | ||
| 496 | - substream.writeRawData((const char*)&type, 4); | ||
| 497 | - substream.writeRawData((const char*)&bytes, 4); | ||
| 498 | - substream.writeRawData(name.data(), name.size()); | ||
| 499 | - substream.writeRawData(buffer.data(), buffer.size()); | ||
| 500 | - } | ||
| 501 | - | ||
| 502 | - { // Real part | ||
| 503 | - quint32 type = 0; | ||
| 504 | - switch (m.type()) { | ||
| 505 | - case CV_8SC1: type = 1; break; | ||
| 506 | - case CV_8UC1: type = 2; break; | ||
| 507 | - case CV_16SC1: type = 3; break; | ||
| 508 | - case CV_16UC1: type = 4; break; | ||
| 509 | - case CV_32SC1: type = 5; break; | ||
| 510 | - case CV_32FC1: type = 7; break; | ||
| 511 | - case CV_64FC1: type = 9; break; | ||
| 512 | - default: qFatal("Unsupported matrix type."); | ||
| 513 | - } | ||
| 514 | - quint32 bytes = m.elemSize() * m.rows * m.cols; | ||
| 515 | - QByteArray buffer((8 - bytes%8)%8, 0); | ||
| 516 | - Mat transposed; | ||
| 517 | - transpose(m, transposed); | ||
| 518 | - substream.writeRawData((const char*)&type, 4); | ||
| 519 | - substream.writeRawData((const char*)&bytes, 4); | ||
| 520 | - substream.writeRawData((const char*)transposed.data, bytes); | ||
| 521 | - substream.writeRawData(buffer.data(), buffer.size()); | ||
| 522 | - } | ||
| 523 | - | ||
| 524 | - { // Matrix | ||
| 525 | - quint32 type = 14; | ||
| 526 | - quint32 bytes = subdata.size(); | ||
| 527 | - stream.writeRawData((const char*)&type, 4); | ||
| 528 | - stream.writeRawData((const char*)&bytes, 4); | ||
| 529 | - stream.writeRawData(subdata.data(), subdata.size()); | ||
| 530 | - } | ||
| 531 | - } | ||
| 532 | - | ||
| 533 | - QtUtils::writeFile(file, data); | ||
| 534 | - } | ||
| 535 | -}; | ||
| 536 | - | ||
| 537 | -BR_REGISTER(Format, matFormat) | ||
| 538 | - | ||
| 539 | -/*! | ||
| 540 | - * \ingroup formats | ||
| 541 | - * \brief Returns an empty matrix. | ||
| 542 | - * \author Josh Klontz \cite jklontz | ||
| 543 | - */ | ||
| 544 | -class nullFormat : public Format | ||
| 545 | -{ | ||
| 546 | - Q_OBJECT | ||
| 547 | - | ||
| 548 | - Template read() const | ||
| 549 | - { | ||
| 550 | - return Template(file, Mat()); | ||
| 551 | - } | ||
| 552 | - | ||
| 553 | - void write(const Template &t) const | ||
| 554 | - { | ||
| 555 | - (void)t; | ||
| 556 | - } | ||
| 557 | -}; | ||
| 558 | - | ||
| 559 | -BR_REGISTER(Format, nullFormat) | ||
| 560 | - | ||
| 561 | -/*! | ||
| 562 | - * \ingroup formats | ||
| 563 | - * \brief RAW format | ||
| 564 | - * | ||
| 565 | - * http://www.nist.gov/srd/nistsd27.cfm | ||
| 566 | - * \author Josh Klontz \cite jklontz | ||
| 567 | - */ | ||
| 568 | -class rawFormat : public Format | ||
| 569 | -{ | ||
| 570 | - Q_OBJECT | ||
| 571 | - static QHash<QString, QHash<QString,QSize> > imageSizes; // QHash<Path, QHash<File,Size> > | ||
| 572 | - | ||
| 573 | - Template read() const | ||
| 574 | - { | ||
| 575 | - QString path = file.path(); | ||
| 576 | - if (!imageSizes.contains(path)) { | ||
| 577 | - static QMutex mutex; | ||
| 578 | - QMutexLocker locker(&mutex); | ||
| 579 | - | ||
| 580 | - if (!imageSizes.contains(path)) { | ||
| 581 | - const QString imageSize = path+"/ImageSize.txt"; | ||
| 582 | - QStringList lines; | ||
| 583 | - if (QFileInfo(imageSize).exists()) { | ||
| 584 | - lines = QtUtils::readLines(imageSize); | ||
| 585 | - lines.removeFirst(); // Remove header | ||
| 586 | - } | ||
| 587 | - | ||
| 588 | - QHash<QString,QSize> sizes; | ||
| 589 | - QRegExp whiteSpace("\\s+"); | ||
| 590 | - foreach (const QString &line, lines) { | ||
| 591 | - QStringList words = line.split(whiteSpace); | ||
| 592 | - if (words.size() != 3) continue; | ||
| 593 | - sizes.insert(words[0], QSize(words[2].toInt(), words[1].toInt())); | ||
| 594 | - } | ||
| 595 | - | ||
| 596 | - imageSizes.insert(path, sizes); | ||
| 597 | - } | ||
| 598 | - } | ||
| 599 | - | ||
| 600 | - QByteArray data; | ||
| 601 | - QtUtils::readFile(file, data); | ||
| 602 | - | ||
| 603 | - QSize size = imageSizes[path][file.baseName()]; | ||
| 604 | - if (!size.isValid()) size = QSize(800,768); | ||
| 605 | - if (data.size() != size.width() * size.height()) | ||
| 606 | - qFatal("Expected %d*%d bytes, got %d.", size.height(), size.width(), data.size()); | ||
| 607 | - return Template(file, Mat(size.height(), size.width(), CV_8UC1, data.data()).clone()); | ||
| 608 | - } | ||
| 609 | - | ||
| 610 | - void write(const Template &t) const | ||
| 611 | - { | ||
| 612 | - QtUtils::writeFile(file, QByteArray().setRawData((const char*)t.m().data, t.m().total() * t.m().elemSize())); | ||
| 613 | - } | ||
| 614 | -}; | ||
| 615 | - | ||
| 616 | -QHash<QString, QHash<QString,QSize> > rawFormat::imageSizes; | ||
| 617 | - | ||
| 618 | -BR_REGISTER(Format, rawFormat) | ||
| 619 | - | ||
| 620 | -/*! | ||
| 621 | - * \ingroup formats | ||
| 622 | - * \brief Retrieves an image from a webcam. | ||
| 623 | - * \author Josh Klontz \cite jklontz | ||
| 624 | - */ | ||
| 625 | -class webcamFormat : public Format | ||
| 626 | -{ | ||
| 627 | - Q_OBJECT | ||
| 628 | - | ||
| 629 | - Template read() const | ||
| 630 | - { | ||
| 631 | - static QScopedPointer<VideoCapture> videoCapture; | ||
| 632 | - | ||
| 633 | - if (videoCapture.isNull()) | ||
| 634 | - videoCapture.reset(new VideoCapture(0)); | ||
| 635 | - | ||
| 636 | - Mat m; | ||
| 637 | - videoCapture->read(m); | ||
| 638 | - return Template(m); | ||
| 639 | - } | ||
| 640 | - | ||
| 641 | - void write(const Template &t) const | ||
| 642 | - { | ||
| 643 | - (void) t; | ||
| 644 | - qFatal("Not supported."); | ||
| 645 | - } | ||
| 646 | -}; | ||
| 647 | - | ||
| 648 | -BR_REGISTER(Format, webcamFormat) | ||
| 649 | - | ||
| 650 | -/*! | ||
| 651 | - * \ingroup formats | ||
| 652 | - * \brief Decodes images from Base64 xml | ||
| 653 | - * \author Scott Klum \cite sklum | ||
| 654 | - * \author Josh Klontz \cite jklontz | ||
| 655 | - */ | ||
| 656 | -class xmlFormat : public Format | ||
| 657 | -{ | ||
| 658 | - Q_OBJECT | ||
| 659 | - | ||
| 660 | - Template read() const | ||
| 661 | - { | ||
| 662 | - Template t; | ||
| 663 | - | ||
| 664 | -#ifndef BR_EMBEDDED | ||
| 665 | - QString fileName = file.get<QString>("path") + file.name; | ||
| 666 | - | ||
| 667 | - QDomDocument doc(fileName); | ||
| 668 | - QFile f(fileName); | ||
| 669 | - | ||
| 670 | - if (!f.open(QIODevice::ReadOnly)) qFatal("Unable to open %s for reading.", qPrintable(file.flat())); | ||
| 671 | - if (!doc.setContent(&f)) qWarning("Unable to parse %s.", qPrintable(file.flat())); | ||
| 672 | - f.close(); | ||
| 673 | - | ||
| 674 | - QDomElement docElem = doc.documentElement(); | ||
| 675 | - QDomNode subject = docElem.firstChild(); | ||
| 676 | - while (!subject.isNull()) { | ||
| 677 | - QDomNode fileNode = subject.firstChild(); | ||
| 678 | - | ||
| 679 | - while (!fileNode.isNull()) { | ||
| 680 | - QDomElement e = fileNode.toElement(); | ||
| 681 | - | ||
| 682 | - if (e.tagName() == "FORMAL_IMG") { | ||
| 683 | - QByteArray byteArray = QByteArray::fromBase64(qPrintable(e.text())); | ||
| 684 | - Mat m = imdecode(Mat(3, byteArray.size(), CV_8UC3, byteArray.data()), CV_LOAD_IMAGE_COLOR); | ||
| 685 | - if (!m.data) qWarning("xmlFormat::read failed to decode image data."); | ||
| 686 | - t.append(m); | ||
| 687 | - } else if ((e.tagName() == "RELEASE_IMG") || | ||
| 688 | - (e.tagName() == "PREBOOK_IMG") || | ||
| 689 | - (e.tagName() == "LPROFILE") || | ||
| 690 | - (e.tagName() == "RPROFILE")) { | ||
| 691 | - // Ignore these other image fields for now | ||
| 692 | - } else { | ||
| 693 | - t.file.set(e.tagName(), e.text()); | ||
| 694 | - } | ||
| 695 | - | ||
| 696 | - fileNode = fileNode.nextSibling(); | ||
| 697 | - } | ||
| 698 | - subject = subject.nextSibling(); | ||
| 699 | - } | ||
| 700 | - | ||
| 701 | - // Calculate age | ||
| 702 | - if (t.file.contains("DOB")) { | ||
| 703 | - const QDate dob = QDate::fromString(t.file.get<QString>("DOB").left(10), "yyyy-MM-dd"); | ||
| 704 | - const QDate current = QDate::currentDate(); | ||
| 705 | - int age = current.year() - dob.year(); | ||
| 706 | - if (current.month() < dob.month()) age--; | ||
| 707 | - t.file.set("Age", age); | ||
| 708 | - } | ||
| 709 | -#endif // BR_EMBEDDED | ||
| 710 | - | ||
| 711 | - return t; | ||
| 712 | - } | ||
| 713 | - | ||
| 714 | - void write(const Template &t) const | ||
| 715 | - { | ||
| 716 | - QStringList lines; | ||
| 717 | - lines.append("<?xml version=\"1.0\" standalone=\"yes\"?>"); | ||
| 718 | - lines.append("<openbr-xml-format>"); | ||
| 719 | - lines.append("\t<xml-data>"); | ||
| 720 | - foreach (const QString &key, t.file.localKeys()) { | ||
| 721 | - if ((key == "Index") || (key == "Label")) continue; | ||
| 722 | - lines.append("\t\t<"+key+">"+QtUtils::toString(t.file.value(key))+"</"+key+">"); | ||
| 723 | - } | ||
| 724 | - std::vector<uchar> data; | ||
| 725 | - imencode(".jpg",t.m(),data); | ||
| 726 | - QByteArray byteArray = QByteArray::fromRawData((const char*)data.data(), data.size()); | ||
| 727 | - lines.append("\t\t<FORMAL_IMG>"+byteArray.toBase64()+"</FORMAL_IMG>"); | ||
| 728 | - lines.append("\t</xml-data>"); | ||
| 729 | - lines.append("</openbr-xml-format>"); | ||
| 730 | - QtUtils::writeFile(file, lines); | ||
| 731 | - } | ||
| 732 | -}; | ||
| 733 | - | ||
| 734 | -BR_REGISTER(Format, xmlFormat) | ||
| 735 | - | ||
| 736 | -/*! | ||
| 737 | - * \ingroup formats | ||
| 738 | - * \brief Reads in scores or ground truth from a text table. | ||
| 739 | - * \author Josh Klontz \cite jklontz | ||
| 740 | - * | ||
| 741 | - * Example of the format: | ||
| 742 | - * \code | ||
| 743 | - * 2.2531514 FALSE 99990377 99990164 | ||
| 744 | - * 2.2549822 TRUE 99990101 99990101 | ||
| 745 | - * \endcode | ||
| 746 | - */ | ||
| 747 | -class scoresFormat : public Format | ||
| 748 | -{ | ||
| 749 | - Q_OBJECT | ||
| 750 | - Q_PROPERTY(int column READ get_column WRITE set_column RESET reset_column STORED false) | ||
| 751 | - Q_PROPERTY(bool groundTruth READ get_groundTruth WRITE set_groundTruth RESET reset_groundTruth STORED false) | ||
| 752 | - Q_PROPERTY(QString delimiter READ get_delimiter WRITE set_delimiter RESET reset_delimiter STORED false) | ||
| 753 | - BR_PROPERTY(int, column, 0) | ||
| 754 | - BR_PROPERTY(bool, groundTruth, false) | ||
| 755 | - BR_PROPERTY(QString, delimiter, "\t") | ||
| 756 | - | ||
| 757 | - Template read() const | ||
| 758 | - { | ||
| 759 | - QFile f(file.name); | ||
| 760 | - if (!f.open(QFile::ReadOnly | QFile::Text)) | ||
| 761 | - qFatal("Failed to open %s for reading.", qPrintable(f.fileName())); | ||
| 762 | - QList<float> values; | ||
| 763 | - while (!f.atEnd()) { | ||
| 764 | - const QStringList words = QString(f.readLine()).split(delimiter); | ||
| 765 | - if (words.size() <= column) qFatal("Expected file to have at least %d columns.", column+1); | ||
| 766 | - const QString &word = words[column]; | ||
| 767 | - bool ok; | ||
| 768 | - float value = word.toFloat(&ok); | ||
| 769 | - if (!ok) value = (QtUtils::toBool(word) ? BEE::Match : BEE::NonMatch); | ||
| 770 | - values.append(value); | ||
| 771 | - } | ||
| 772 | - if (values.size() == 1) | ||
| 773 | - qWarning("Only one value read, double check file line endings."); | ||
| 774 | - Mat result = OpenCVUtils::toMat(values); | ||
| 775 | - if (groundTruth) result.convertTo(result, CV_8U); | ||
| 776 | - return result; | ||
| 777 | - } | ||
| 778 | - | ||
| 779 | - void write(const Template &t) const | ||
| 780 | - { | ||
| 781 | - (void) t; | ||
| 782 | - qFatal("Not implemented."); | ||
| 783 | - } | ||
| 784 | -}; | ||
| 785 | - | ||
| 786 | -BR_REGISTER(Format, scoresFormat) | ||
| 787 | - | ||
| 788 | -/*! | ||
| 789 | - * \ingroup formats | ||
| 790 | - * \brief Reads FBI EBTS transactions. | ||
| 791 | - * \author Scott Klum \cite sklum | ||
| 792 | - * https://www.fbibiospecs.org/ebts.html | ||
| 793 | - */ | ||
| 794 | -class ebtsFormat : public Format | ||
| 795 | -{ | ||
| 796 | - Q_OBJECT | ||
| 797 | - | ||
| 798 | - struct Field { | ||
| 799 | - int type; | ||
| 800 | - QList<QByteArray> data; | ||
| 801 | - }; | ||
| 802 | - | ||
| 803 | - struct Record { | ||
| 804 | - int type; | ||
| 805 | - quint32 bytes; | ||
| 806 | - int position; // Starting position of record | ||
| 807 | - | ||
| 808 | - QHash<int,QList<QByteArray> > fields; | ||
| 809 | - }; | ||
| 810 | - | ||
| 811 | - quint32 recordBytes(const QByteArray &byteArray, const float recordType, int from) const | ||
| 812 | - { | ||
| 813 | - bool ok; | ||
| 814 | - quint32 size; | ||
| 815 | - | ||
| 816 | - if (recordType == 4 || recordType == 7) { | ||
| 817 | - // read first four bytes | ||
| 818 | - ok = true; | ||
| 819 | - size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData()); | ||
| 820 | - } else { | ||
| 821 | - int index = byteArray.indexOf(QChar(0x1D), from); | ||
| 822 | - size = byteArray.mid(from, index-from).split(':').last().toInt(&ok); | ||
| 823 | - } | ||
| 824 | - | ||
| 825 | - return ok ? size : -1; | ||
| 826 | - } | ||
| 827 | - | ||
| 828 | - void parseRecord(const QByteArray &byteArray, Record &record) const | ||
| 829 | - { | ||
| 830 | - if (record.type == 4 || record.type == 7) { | ||
| 831 | - // Just a binary blob | ||
| 832 | - // Read everything after the first four bytes | ||
| 833 | - // Not current supported | ||
| 834 | - } else { | ||
| 835 | - // Continue reading fields until we get all the data | ||
| 836 | - unsigned int position = record.position; | ||
| 837 | - while (position < record.position + record.bytes) { | ||
| 838 | - int index = byteArray.indexOf(QChar(0x1D), position); | ||
| 839 | - Field field = parseField(byteArray.mid(position, index-position),QChar(0x1F)); | ||
| 840 | - if (field.type == 999 ) { | ||
| 841 | - // Data begin after the field identifier and the colon | ||
| 842 | - int dataBegin = byteArray.indexOf(':', position)+1; | ||
| 843 | - field.data.clear(); | ||
| 844 | - field.data.append(byteArray.mid(dataBegin, record.bytes-(dataBegin-record.position))); | ||
| 845 | - | ||
| 846 | - // Data fields are always last in the record | ||
| 847 | - record.fields.insert(field.type,field.data); | ||
| 848 | - break; | ||
| 849 | - } | ||
| 850 | - // Advance the position accounting for the separator | ||
| 851 | - position += index-position+1; | ||
| 852 | - record.fields.insert(field.type,field.data); | ||
| 853 | - } | ||
| 854 | - } | ||
| 855 | - } | ||
| 856 | - | ||
| 857 | - Field parseField(const QByteArray &byteArray, const QChar &sep) const | ||
| 858 | - { | ||
| 859 | - bool ok; | ||
| 860 | - Field f; | ||
| 861 | - | ||
| 862 | - QList<QByteArray> data = byteArray.split(':'); | ||
| 863 | - | ||
| 864 | - f.type = data.first().split('.').last().toInt(&ok); | ||
| 865 | - f.data = data.last().split(sep.toLatin1()); | ||
| 866 | - | ||
| 867 | - return f; | ||
| 868 | - } | ||
| 869 | - | ||
| 870 | - Template read() const | ||
| 871 | - { | ||
| 872 | - QByteArray byteArray; | ||
| 873 | - QtUtils::readFile(file, byteArray); | ||
| 874 | - | ||
| 875 | - Template t; | ||
| 876 | - | ||
| 877 | - Mat m; | ||
| 878 | - | ||
| 879 | - QList<Record> records; | ||
| 880 | - | ||
| 881 | - // Read the type one record (every EBTS file will have one of these) | ||
| 882 | - Record r1; | ||
| 883 | - r1.type = 1; | ||
| 884 | - r1.position = 0; | ||
| 885 | - r1.bytes = recordBytes(byteArray,r1.type,r1.position); | ||
| 886 | - | ||
| 887 | - // The fields in a type 1 record are strictly defined | ||
| 888 | - QList<QByteArray> data = byteArray.mid(r1.position,r1.bytes).split(QChar(0x1D).toLatin1()); | ||
| 889 | - foreach (const QByteArray &datum, data) { | ||
| 890 | - Field f = parseField(datum,QChar(0x1F)); | ||
| 891 | - r1.fields.insert(f.type,f.data); | ||
| 892 | - } | ||
| 893 | - | ||
| 894 | - records.append(r1); | ||
| 895 | - | ||
| 896 | - // Read the type two record (every EBTS file will have one of these) | ||
| 897 | - Record r2; | ||
| 898 | - r2.type = 2; | ||
| 899 | - r2.position = r1.bytes; | ||
| 900 | - r2.bytes = recordBytes(byteArray,r2.type,r2.position); | ||
| 901 | - | ||
| 902 | - // The fields in a type 2 record are strictly defined | ||
| 903 | - data = byteArray.mid(r2.position,r2.bytes).split(QChar(0x1D).toLatin1()); | ||
| 904 | - foreach (const QByteArray &datum, data) { | ||
| 905 | - Field f = parseField(datum,QChar(0x1F)); | ||
| 906 | - r2.fields.insert(f.type,f.data); | ||
| 907 | - } | ||
| 908 | - | ||
| 909 | - // Demographics | ||
| 910 | - if (r2.fields.contains(18)) { | ||
| 911 | - QString name = r2.fields.value(18).first(); | ||
| 912 | - QStringList names = name.split(','); | ||
| 913 | - t.file.set("FIRSTNAME", names.at(1)); | ||
| 914 | - t.file.set("LASTNAME", names.at(0)); | ||
| 915 | - } | ||
| 916 | - | ||
| 917 | - if (r2.fields.contains(22)) t.file.set("DOB", r2.fields.value(22).first().toInt()); | ||
| 918 | - if (r2.fields.contains(24)) t.file.set("GENDER", QString(r2.fields.value(24).first())); | ||
| 919 | - if (r2.fields.contains(25)) t.file.set("RACE", QString(r2.fields.value(25).first())); | ||
| 920 | - | ||
| 921 | - if (t.file.contains("DOB")) { | ||
| 922 | - const QDate dob = QDate::fromString(t.file.get<QString>("DOB"), "yyyyMMdd"); | ||
| 923 | - const QDate current = QDate::currentDate(); | ||
| 924 | - int age = current.year() - dob.year(); | ||
| 925 | - if (current.month() < dob.month()) age--; | ||
| 926 | - t.file.set("Age", age); | ||
| 927 | - } | ||
| 928 | - | ||
| 929 | - records.append(r2); | ||
| 930 | - | ||
| 931 | - // The third field of the first record contains informations about all the remaining records in the transaction | ||
| 932 | - // We don't care about the first two and the final items | ||
| 933 | - QList<QByteArray> recordTypes = r1.fields.value(3); | ||
| 934 | - for (int i=2; i<recordTypes.size()-1; i++) { | ||
| 935 | - // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type | ||
| 936 | - QByteArray recordType = recordTypes[i].mid(3); | ||
| 937 | - Record r; | ||
| 938 | - r.type = recordType.toInt(); | ||
| 939 | - records.append(r); | ||
| 940 | - } | ||
| 941 | - | ||
| 942 | - QList<int> frontalIdxs; | ||
| 943 | - int position = r1.bytes + r2.bytes; | ||
| 944 | - for (int i=2; i<records.size(); i++) { | ||
| 945 | - records[i].position = position; | ||
| 946 | - records[i].bytes = recordBytes(byteArray,records[i].type,position); | ||
| 947 | - | ||
| 948 | - parseRecord(byteArray, records[i]); | ||
| 949 | - if (records[i].type == 10) frontalIdxs.append(i); | ||
| 950 | - position += records[i].bytes; | ||
| 951 | - } | ||
| 952 | - | ||
| 953 | - if (!frontalIdxs.isEmpty()) { | ||
| 954 | - // We use the first type 10 record to get the frontal | ||
| 955 | - QByteArray frontal = records[frontalIdxs.first()].fields.value(999).first(); | ||
| 956 | - m = imdecode(Mat(3, frontal.size(), CV_8UC3, frontal.data()), CV_LOAD_IMAGE_COLOR); | ||
| 957 | - if (!m.data) qWarning("ebtsFormat::read failed to decode image data."); | ||
| 958 | - t.m() = m; | ||
| 959 | - } else qWarning("ebtsFormat::cannot find image data within file."); | ||
| 960 | - | ||
| 961 | - return t; | ||
| 962 | - } | ||
| 963 | - | ||
| 964 | - void write(const Template &t) const | ||
| 965 | - { | ||
| 966 | - (void) t; | ||
| 967 | - qFatal("Writing EBTS files is not supported."); | ||
| 968 | - } | ||
| 969 | -}; | ||
| 970 | - | ||
| 971 | -BR_REGISTER(Format, ebtsFormat) | ||
| 972 | - | ||
| 973 | -} // namespace br | ||
| 974 | - | ||
| 975 | -#include "format.moc" |
openbr/plugins/format/binary.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/qtutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup formats | ||
| 11 | + * \brief A simple binary matrix format. | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + * First 4 bytes indicate the number of rows. | ||
| 14 | + * Second 4 bytes indicate the number of columns. | ||
| 15 | + * The rest of the bytes are 32-bit floating data elements in row-major order. | ||
| 16 | + */ | ||
| 17 | +class binaryFormat : public Format | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + Q_PROPERTY(bool raw READ get_raw WRITE set_raw RESET reset_raw STORED false) | ||
| 21 | + BR_PROPERTY(bool, raw, false) | ||
| 22 | + | ||
| 23 | + Template read() const | ||
| 24 | + { | ||
| 25 | + QByteArray data; | ||
| 26 | + QtUtils::readFile(file, data); | ||
| 27 | + if (raw) { | ||
| 28 | + return Template(file, Mat(1, data.size(), CV_8UC1, data.data()).clone()); | ||
| 29 | + } else { | ||
| 30 | + return Template(file, Mat(((quint32*)data.data())[0], | ||
| 31 | + ((quint32*)data.data())[1], | ||
| 32 | + CV_32FC1, | ||
| 33 | + data.data()+8).clone()); | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + void write(const Template &t) const | ||
| 38 | + { | ||
| 39 | + QFile f(file); | ||
| 40 | + QtUtils::touchDir(f); | ||
| 41 | + if (!f.open(QFile::WriteOnly)) | ||
| 42 | + qFatal("Failed to open %s for writing.", qPrintable(file)); | ||
| 43 | + | ||
| 44 | + Mat m; | ||
| 45 | + if (!raw) { | ||
| 46 | + if (t.m().type() != CV_32FC1) | ||
| 47 | + t.m().convertTo(m, CV_32F); | ||
| 48 | + else m = t.m(); | ||
| 49 | + | ||
| 50 | + if (m.channels() != 1) qFatal("Only supports single channel matrices."); | ||
| 51 | + | ||
| 52 | + f.write((const char *) &m.rows, 4); | ||
| 53 | + f.write((const char *) &m.cols, 4); | ||
| 54 | + } | ||
| 55 | + else m = t.m(); | ||
| 56 | + | ||
| 57 | + qint64 rowSize = m.cols * sizeof(float); | ||
| 58 | + for (int i=0; i < m.rows; i++) | ||
| 59 | + { | ||
| 60 | + f.write((const char *) m.row(i).data, rowSize); | ||
| 61 | + } | ||
| 62 | + f.close(); | ||
| 63 | + } | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +BR_REGISTER(Format, binaryFormat) | ||
| 67 | + | ||
| 68 | +} // namespace br | ||
| 69 | + | ||
| 70 | +#include "binary.moc" |
openbr/plugins/format/csv.cpp
0 → 100644
| 1 | +#include <QRegularExpression> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | +#include <openbr/core/opencvutils.h> | ||
| 5 | +#include <openbr/core/qtutils.h> | ||
| 6 | + | ||
| 7 | +using namespace cv; | ||
| 8 | + | ||
| 9 | +namespace br | ||
| 10 | +{ | ||
| 11 | + | ||
| 12 | +/*! | ||
| 13 | + * \ingroup formats | ||
| 14 | + * \brief Reads a comma separated value file. | ||
| 15 | + * \author Josh Klontz \cite jklontz | ||
| 16 | + */ | ||
| 17 | +class csvFormat : public Format | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + | ||
| 21 | + Template read() const | ||
| 22 | + { | ||
| 23 | + QFile f(file.name); | ||
| 24 | + f.open(QFile::ReadOnly); | ||
| 25 | + QStringList lines(QString(f.readAll()).split(QRegularExpression("[\n|\r\n|\r]"), QString::SkipEmptyParts)); | ||
| 26 | + f.close(); | ||
| 27 | + | ||
| 28 | + bool isUChar = true; | ||
| 29 | + QList< QList<float> > valsList; | ||
| 30 | + foreach (const QString &line, lines) { | ||
| 31 | + QList<float> vals; | ||
| 32 | + foreach (const QString &word, line.split(QRegExp(" *, *"), QString::SkipEmptyParts)) { | ||
| 33 | + bool ok; | ||
| 34 | + const float val = word.toFloat(&ok); | ||
| 35 | + vals.append(val); | ||
| 36 | + isUChar = isUChar && (val == float(uchar(val))); | ||
| 37 | + } | ||
| 38 | + if (!vals.isEmpty()) | ||
| 39 | + valsList.append(vals); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + Mat m(valsList.size(), valsList[0].size(), CV_32FC1); | ||
| 43 | + for (int i=0; i<valsList.size(); i++) | ||
| 44 | + for (int j=0; j<valsList[i].size(); j++) | ||
| 45 | + m.at<float>(i,j) = valsList[i][j]; | ||
| 46 | + | ||
| 47 | + if (isUChar) m.convertTo(m, CV_8U); | ||
| 48 | + return Template(m); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + void write(const Template &t) const | ||
| 52 | + { | ||
| 53 | + const Mat &m = t.m(); | ||
| 54 | + if (t.size() != 1) qFatal("Only supports single matrix templates."); | ||
| 55 | + if (m.channels() != 1) qFatal("Only supports single channel matrices."); | ||
| 56 | + | ||
| 57 | + QStringList lines; lines.reserve(m.rows); | ||
| 58 | + for (int r=0; r<m.rows; r++) { | ||
| 59 | + QStringList elements; elements.reserve(m.cols); | ||
| 60 | + for (int c=0; c<m.cols; c++) | ||
| 61 | + elements.append(OpenCVUtils::elemToString(m, r, c)); | ||
| 62 | + lines.append(elements.join(",")); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + QtUtils::writeFile(file, lines); | ||
| 66 | + } | ||
| 67 | +}; | ||
| 68 | + | ||
| 69 | +BR_REGISTER(Format, csvFormat) | ||
| 70 | + | ||
| 71 | +} // namespace br | ||
| 72 | + | ||
| 73 | +#include "csv.moc" |
openbr/plugins/format/ebts.cpp
0 → 100644
| 1 | +#include <QtEndian> | ||
| 2 | +#include <opencv2/highgui/highgui.hpp> | ||
| 3 | + | ||
| 4 | +#include <openbr/plugins/openbr_internal.h> | ||
| 5 | +#include <openbr/core/qtutils.h> | ||
| 6 | + | ||
| 7 | +using namespace cv; | ||
| 8 | + | ||
| 9 | +namespace br | ||
| 10 | +{ | ||
| 11 | + | ||
| 12 | +/*! | ||
| 13 | + * \ingroup formats | ||
| 14 | + * \brief Reads FBI EBTS transactions. | ||
| 15 | + * \author Scott Klum \cite sklum | ||
| 16 | + * https://www.fbibiospecs.org/ebts.html | ||
| 17 | + */ | ||
| 18 | +class ebtsFormat : public Format | ||
| 19 | +{ | ||
| 20 | + Q_OBJECT | ||
| 21 | + | ||
| 22 | + struct Field { | ||
| 23 | + int type; | ||
| 24 | + QList<QByteArray> data; | ||
| 25 | + }; | ||
| 26 | + | ||
| 27 | + struct Record { | ||
| 28 | + int type; | ||
| 29 | + quint32 bytes; | ||
| 30 | + int position; // Starting position of record | ||
| 31 | + | ||
| 32 | + QHash<int,QList<QByteArray> > fields; | ||
| 33 | + }; | ||
| 34 | + | ||
| 35 | + quint32 recordBytes(const QByteArray &byteArray, const float recordType, int from) const | ||
| 36 | + { | ||
| 37 | + bool ok; | ||
| 38 | + quint32 size; | ||
| 39 | + | ||
| 40 | + if (recordType == 4 || recordType == 7) { | ||
| 41 | + // read first four bytes | ||
| 42 | + ok = true; | ||
| 43 | + size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData()); | ||
| 44 | + } else { | ||
| 45 | + int index = byteArray.indexOf(QChar(0x1D), from); | ||
| 46 | + size = byteArray.mid(from, index-from).split(':').last().toInt(&ok); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + return ok ? size : -1; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + void parseRecord(const QByteArray &byteArray, Record &record) const | ||
| 53 | + { | ||
| 54 | + if (record.type == 4 || record.type == 7) { | ||
| 55 | + // Just a binary blob | ||
| 56 | + // Read everything after the first four bytes | ||
| 57 | + // Not current supported | ||
| 58 | + } else { | ||
| 59 | + // Continue reading fields until we get all the data | ||
| 60 | + unsigned int position = record.position; | ||
| 61 | + while (position < record.position + record.bytes) { | ||
| 62 | + int index = byteArray.indexOf(QChar(0x1D), position); | ||
| 63 | + Field field = parseField(byteArray.mid(position, index-position),QChar(0x1F)); | ||
| 64 | + if (field.type == 999 ) { | ||
| 65 | + // Data begin after the field identifier and the colon | ||
| 66 | + int dataBegin = byteArray.indexOf(':', position)+1; | ||
| 67 | + field.data.clear(); | ||
| 68 | + field.data.append(byteArray.mid(dataBegin, record.bytes-(dataBegin-record.position))); | ||
| 69 | + | ||
| 70 | + // Data fields are always last in the record | ||
| 71 | + record.fields.insert(field.type,field.data); | ||
| 72 | + break; | ||
| 73 | + } | ||
| 74 | + // Advance the position accounting for the separator | ||
| 75 | + position += index-position+1; | ||
| 76 | + record.fields.insert(field.type,field.data); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + Field parseField(const QByteArray &byteArray, const QChar &sep) const | ||
| 82 | + { | ||
| 83 | + bool ok; | ||
| 84 | + Field f; | ||
| 85 | + | ||
| 86 | + QList<QByteArray> data = byteArray.split(':'); | ||
| 87 | + | ||
| 88 | + f.type = data.first().split('.').last().toInt(&ok); | ||
| 89 | + f.data = data.last().split(sep.toLatin1()); | ||
| 90 | + | ||
| 91 | + return f; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + Template read() const | ||
| 95 | + { | ||
| 96 | + QByteArray byteArray; | ||
| 97 | + QtUtils::readFile(file, byteArray); | ||
| 98 | + | ||
| 99 | + Template t; | ||
| 100 | + | ||
| 101 | + Mat m; | ||
| 102 | + | ||
| 103 | + QList<Record> records; | ||
| 104 | + | ||
| 105 | + // Read the type one record (every EBTS file will have one of these) | ||
| 106 | + Record r1; | ||
| 107 | + r1.type = 1; | ||
| 108 | + r1.position = 0; | ||
| 109 | + r1.bytes = recordBytes(byteArray,r1.type,r1.position); | ||
| 110 | + | ||
| 111 | + // The fields in a type 1 record are strictly defined | ||
| 112 | + QList<QByteArray> data = byteArray.mid(r1.position,r1.bytes).split(QChar(0x1D).toLatin1()); | ||
| 113 | + foreach (const QByteArray &datum, data) { | ||
| 114 | + Field f = parseField(datum,QChar(0x1F)); | ||
| 115 | + r1.fields.insert(f.type,f.data); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + records.append(r1); | ||
| 119 | + | ||
| 120 | + // Read the type two record (every EBTS file will have one of these) | ||
| 121 | + Record r2; | ||
| 122 | + r2.type = 2; | ||
| 123 | + r2.position = r1.bytes; | ||
| 124 | + r2.bytes = recordBytes(byteArray,r2.type,r2.position); | ||
| 125 | + | ||
| 126 | + // The fields in a type 2 record are strictly defined | ||
| 127 | + data = byteArray.mid(r2.position,r2.bytes).split(QChar(0x1D).toLatin1()); | ||
| 128 | + foreach (const QByteArray &datum, data) { | ||
| 129 | + Field f = parseField(datum,QChar(0x1F)); | ||
| 130 | + r2.fields.insert(f.type,f.data); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + // Demographics | ||
| 134 | + if (r2.fields.contains(18)) { | ||
| 135 | + QString name = r2.fields.value(18).first(); | ||
| 136 | + QStringList names = name.split(','); | ||
| 137 | + t.file.set("FIRSTNAME", names.at(1)); | ||
| 138 | + t.file.set("LASTNAME", names.at(0)); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + if (r2.fields.contains(22)) t.file.set("DOB", r2.fields.value(22).first().toInt()); | ||
| 142 | + if (r2.fields.contains(24)) t.file.set("GENDER", QString(r2.fields.value(24).first())); | ||
| 143 | + if (r2.fields.contains(25)) t.file.set("RACE", QString(r2.fields.value(25).first())); | ||
| 144 | + | ||
| 145 | + if (t.file.contains("DOB")) { | ||
| 146 | + const QDate dob = QDate::fromString(t.file.get<QString>("DOB"), "yyyyMMdd"); | ||
| 147 | + const QDate current = QDate::currentDate(); | ||
| 148 | + int age = current.year() - dob.year(); | ||
| 149 | + if (current.month() < dob.month()) age--; | ||
| 150 | + t.file.set("Age", age); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + records.append(r2); | ||
| 154 | + | ||
| 155 | + // The third field of the first record contains informations about all the remaining records in the transaction | ||
| 156 | + // We don't care about the first two and the final items | ||
| 157 | + QList<QByteArray> recordTypes = r1.fields.value(3); | ||
| 158 | + for (int i=2; i<recordTypes.size()-1; i++) { | ||
| 159 | + // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type | ||
| 160 | + QByteArray recordType = recordTypes[i].mid(3); | ||
| 161 | + Record r; | ||
| 162 | + r.type = recordType.toInt(); | ||
| 163 | + records.append(r); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + QList<int> frontalIdxs; | ||
| 167 | + int position = r1.bytes + r2.bytes; | ||
| 168 | + for (int i=2; i<records.size(); i++) { | ||
| 169 | + records[i].position = position; | ||
| 170 | + records[i].bytes = recordBytes(byteArray,records[i].type,position); | ||
| 171 | + | ||
| 172 | + parseRecord(byteArray, records[i]); | ||
| 173 | + if (records[i].type == 10) frontalIdxs.append(i); | ||
| 174 | + position += records[i].bytes; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + if (!frontalIdxs.isEmpty()) { | ||
| 178 | + // We use the first type 10 record to get the frontal | ||
| 179 | + QByteArray frontal = records[frontalIdxs.first()].fields.value(999).first(); | ||
| 180 | + m = imdecode(Mat(3, frontal.size(), CV_8UC3, frontal.data()), CV_LOAD_IMAGE_COLOR); | ||
| 181 | + if (!m.data) qWarning("ebtsFormat::read failed to decode image data."); | ||
| 182 | + t.m() = m; | ||
| 183 | + } else qWarning("ebtsFormat::cannot find image data within file."); | ||
| 184 | + | ||
| 185 | + return t; | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + void write(const Template &t) const | ||
| 189 | + { | ||
| 190 | + (void) t; | ||
| 191 | + qFatal("Writing EBTS files is not supported."); | ||
| 192 | + } | ||
| 193 | +}; | ||
| 194 | + | ||
| 195 | +BR_REGISTER(Format, ebtsFormat) | ||
| 196 | + | ||
| 197 | +} // namespace br | ||
| 198 | + | ||
| 199 | +#include "ebts.moc" |
openbr/plugins/format/lffs.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/qtutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup formats | ||
| 11 | + * \brief Reads a NIST LFFS file. | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + */ | ||
| 14 | +class lffsFormat : public Format | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + | ||
| 18 | + Template read() const | ||
| 19 | + { | ||
| 20 | + QByteArray byteArray; | ||
| 21 | + QtUtils::readFile(file.name, byteArray); | ||
| 22 | + return Mat(1, byteArray.size(), CV_8UC1, byteArray.data()).clone(); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + void write(const Template &t) const | ||
| 26 | + { | ||
| 27 | + QByteArray byteArray((const char*)t.m().data, t.m().total()*t.m().elemSize()); | ||
| 28 | + QtUtils::writeFile(file.name, byteArray); | ||
| 29 | + } | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +BR_REGISTER(Format, lffsFormat) | ||
| 33 | + | ||
| 34 | +} // namespace br | ||
| 35 | + | ||
| 36 | +#include "lffs.moc" |
openbr/plugins/format/mat.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/qtutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup formats | ||
| 11 | + * \brief MATLAB <tt>.mat</tt> format. | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + * http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf | ||
| 14 | + * \note matFormat is known not to work with compressed matrices | ||
| 15 | + */ | ||
| 16 | +class matFormat : public Format | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + | ||
| 20 | + struct Element | ||
| 21 | + { | ||
| 22 | + // It is always best to cast integers to a Qt integer type, such as qint16 or quint32, when reading and writing. | ||
| 23 | + // This ensures that you always know exactly what size integers you are reading and writing, no matter what the | ||
| 24 | + // underlying platform and architecture the application happens to be running on. | ||
| 25 | + // http://qt-project.org/doc/qt-4.8/datastreamformat.html | ||
| 26 | + quint32 type, bytes; | ||
| 27 | + QByteArray data; | ||
| 28 | + Element() : type(0), bytes(0) {} | ||
| 29 | + Element(QDataStream &stream) | ||
| 30 | + : type(0), bytes(0) | ||
| 31 | + { | ||
| 32 | + // Read first 4 bytes into type (32 bit integer), | ||
| 33 | + // specifying the type of data used | ||
| 34 | + if (stream.readRawData((char*)&type, 4) != 4) | ||
| 35 | + qFatal("Unexpected end of file."); | ||
| 36 | + | ||
| 37 | + if (type >= 1 << 16) { | ||
| 38 | + // Small data format | ||
| 39 | + bytes = type; | ||
| 40 | + type = type & 0x0000FFFF; | ||
| 41 | + bytes = bytes >> 16; | ||
| 42 | + } else { | ||
| 43 | + // Regular format | ||
| 44 | + // Read 4 bytes into bytes (32 bit integer), | ||
| 45 | + // specifying the size of the element | ||
| 46 | + if (stream.readRawData((char*)&bytes, 4) != 4) | ||
| 47 | + qFatal("Unexpected end of file."); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // Set the size of data to bytes | ||
| 51 | + data.resize(bytes); | ||
| 52 | + | ||
| 53 | + // Read bytes amount of data from the file into data | ||
| 54 | + if (int(bytes) != stream.readRawData(data.data(), bytes)) | ||
| 55 | + qFatal("Unexpected end of file."); | ||
| 56 | + | ||
| 57 | + // Alignment | ||
| 58 | + int skipBytes = (bytes < 4) ? (4 - bytes) : (8 - bytes%8)%8; | ||
| 59 | + if (skipBytes != 0) stream.skipRawData(skipBytes); | ||
| 60 | + } | ||
| 61 | + }; | ||
| 62 | + | ||
| 63 | + Template read() const | ||
| 64 | + { | ||
| 65 | + QByteArray byteArray; | ||
| 66 | + QtUtils::readFile(file, byteArray); | ||
| 67 | + QDataStream f(byteArray); | ||
| 68 | + | ||
| 69 | + { // Check header | ||
| 70 | + QByteArray header(128, 0); | ||
| 71 | + f.readRawData(header.data(), 128); | ||
| 72 | + if (!header.startsWith("MATLAB 5.0 MAT-file")) | ||
| 73 | + qFatal("Invalid MAT header."); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + Template t(file); | ||
| 77 | + | ||
| 78 | + while (!f.atEnd()) { | ||
| 79 | + Element element(f); | ||
| 80 | + | ||
| 81 | + // miCOMPRESSED | ||
| 82 | + if (element.type == 15) { | ||
| 83 | + // Prepend the number of bytes to element.data | ||
| 84 | + element.data.prepend((char*)&element.bytes, 4); // Qt zlib wrapper requires this to preallocate the buffer | ||
| 85 | + QDataStream uncompressed(qUncompress(element.data)); | ||
| 86 | + element = Element(uncompressed); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + // miMATRIX | ||
| 90 | + if (element.type == 14) { | ||
| 91 | + QDataStream matrix(element.data); | ||
| 92 | + qint32 rows = 0, columns = 0; | ||
| 93 | + int matrixType = 0; | ||
| 94 | + QByteArray matrixData; | ||
| 95 | + while (!matrix.atEnd()) { | ||
| 96 | + Element subelement(matrix); | ||
| 97 | + if (subelement.type == 5) { // Dimensions array | ||
| 98 | + if (subelement.bytes == 8) { | ||
| 99 | + rows = ((qint32*)subelement.data.data())[0]; | ||
| 100 | + columns = ((qint32*)subelement.data.data())[1]; | ||
| 101 | + } else { | ||
| 102 | + qWarning("matFormat::read can only handle 2D arrays."); | ||
| 103 | + } | ||
| 104 | + } else if (subelement.type == 7) { //miSINGLE | ||
| 105 | + matrixType = CV_32FC1; | ||
| 106 | + matrixData = subelement.data; | ||
| 107 | + } else if (subelement.type == 9) { //miDOUBLE | ||
| 108 | + matrixType = CV_64FC1; | ||
| 109 | + matrixData = subelement.data; | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + if ((rows > 0) && (columns > 0) && (matrixType != 0) && !matrixData.isEmpty()) { | ||
| 114 | + Mat transposed; | ||
| 115 | + transpose(Mat(columns, rows, matrixType, matrixData.data()), transposed); | ||
| 116 | + t.append(transposed); | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + return t; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + void write(const Template &t) const | ||
| 125 | + { | ||
| 126 | + QByteArray data; | ||
| 127 | + QDataStream stream(&data, QFile::WriteOnly); | ||
| 128 | + | ||
| 129 | + { // Header | ||
| 130 | + QByteArray header = "MATLAB 5.0 MAT-file; Made with OpenBR | www.openbiometrics.org\n"; | ||
| 131 | + QByteArray buffer(116-header.size(), 0); | ||
| 132 | + stream.writeRawData(header.data(), header.size()); | ||
| 133 | + stream.writeRawData(buffer.data(), buffer.size()); | ||
| 134 | + quint64 subsystem = 0; | ||
| 135 | + quint16 version = 0x0100; | ||
| 136 | + const char *endianness = "IM"; | ||
| 137 | + stream.writeRawData((const char*)&subsystem, 8); | ||
| 138 | + stream.writeRawData((const char*)&version, 2); | ||
| 139 | + stream.writeRawData(endianness, 2); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + for (int i=0; i<t.size(); i++) { | ||
| 143 | + const Mat &m = t[i]; | ||
| 144 | + if (m.channels() != 1) qFatal("Only supports single channel matrices."); | ||
| 145 | + | ||
| 146 | + QByteArray subdata; | ||
| 147 | + QDataStream substream(&subdata, QFile::WriteOnly); | ||
| 148 | + | ||
| 149 | + { // Array Flags | ||
| 150 | + quint32 type = 6; | ||
| 151 | + quint32 bytes = 8; | ||
| 152 | + quint64 arrayClass = 0; | ||
| 153 | + switch (m.type()) { | ||
| 154 | + case CV_64FC1: arrayClass = 6; break; | ||
| 155 | + case CV_32FC1: arrayClass = 7; break; | ||
| 156 | + case CV_8UC1: arrayClass = 8; break; | ||
| 157 | + case CV_8SC1: arrayClass = 9; break; | ||
| 158 | + case CV_16UC1: arrayClass = 10; break; | ||
| 159 | + case CV_16SC1: arrayClass = 11; break; | ||
| 160 | + case CV_32SC1: arrayClass = 12; break; | ||
| 161 | + default: qFatal("Unsupported matrix class."); | ||
| 162 | + } | ||
| 163 | + substream.writeRawData((const char*)&type, 4); | ||
| 164 | + substream.writeRawData((const char*)&bytes, 4); | ||
| 165 | + substream.writeRawData((const char*)&arrayClass, 8); | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + { // Dimensions Array | ||
| 169 | + quint32 type = 5; | ||
| 170 | + quint32 bytes = 8; | ||
| 171 | + substream.writeRawData((const char*)&type, 4); | ||
| 172 | + substream.writeRawData((const char*)&bytes, 4); | ||
| 173 | + substream.writeRawData((const char*)&m.rows, 4); | ||
| 174 | + substream.writeRawData((const char*)&m.cols, 4); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + { // Array Name | ||
| 178 | + QByteArray name(qPrintable(QString("OpenBR_%1").arg(QString::number(i)))); | ||
| 179 | + quint32 type = 1; | ||
| 180 | + quint32 bytes = name.size(); | ||
| 181 | + QByteArray buffer((8 - bytes%8)%8, 0); | ||
| 182 | + substream.writeRawData((const char*)&type, 4); | ||
| 183 | + substream.writeRawData((const char*)&bytes, 4); | ||
| 184 | + substream.writeRawData(name.data(), name.size()); | ||
| 185 | + substream.writeRawData(buffer.data(), buffer.size()); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + { // Real part | ||
| 189 | + quint32 type = 0; | ||
| 190 | + switch (m.type()) { | ||
| 191 | + case CV_8SC1: type = 1; break; | ||
| 192 | + case CV_8UC1: type = 2; break; | ||
| 193 | + case CV_16SC1: type = 3; break; | ||
| 194 | + case CV_16UC1: type = 4; break; | ||
| 195 | + case CV_32SC1: type = 5; break; | ||
| 196 | + case CV_32FC1: type = 7; break; | ||
| 197 | + case CV_64FC1: type = 9; break; | ||
| 198 | + default: qFatal("Unsupported matrix type."); | ||
| 199 | + } | ||
| 200 | + quint32 bytes = m.elemSize() * m.rows * m.cols; | ||
| 201 | + QByteArray buffer((8 - bytes%8)%8, 0); | ||
| 202 | + Mat transposed; | ||
| 203 | + transpose(m, transposed); | ||
| 204 | + substream.writeRawData((const char*)&type, 4); | ||
| 205 | + substream.writeRawData((const char*)&bytes, 4); | ||
| 206 | + substream.writeRawData((const char*)transposed.data, bytes); | ||
| 207 | + substream.writeRawData(buffer.data(), buffer.size()); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + { // Matrix | ||
| 211 | + quint32 type = 14; | ||
| 212 | + quint32 bytes = subdata.size(); | ||
| 213 | + stream.writeRawData((const char*)&type, 4); | ||
| 214 | + stream.writeRawData((const char*)&bytes, 4); | ||
| 215 | + stream.writeRawData(subdata.data(), subdata.size()); | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + QtUtils::writeFile(file, data); | ||
| 220 | + } | ||
| 221 | +}; | ||
| 222 | + | ||
| 223 | +BR_REGISTER(Format, matFormat) | ||
| 224 | + | ||
| 225 | +} // namespace br | ||
| 226 | + | ||
| 227 | +#include "mat.moc" |
openbr/plugins/format/mtx.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/bee.h> | ||
| 3 | + | ||
| 4 | +namespace br | ||
| 5 | +{ | ||
| 6 | + | ||
| 7 | +/*! | ||
| 8 | + * \ingroup formats | ||
| 9 | + * \brief Reads a NIST BEE similarity matrix. | ||
| 10 | + * \author Josh Klontz \cite jklontz | ||
| 11 | + */ | ||
| 12 | +class mtxFormat : public Format | ||
| 13 | +{ | ||
| 14 | + Q_OBJECT | ||
| 15 | + | ||
| 16 | + Template read() const | ||
| 17 | + { | ||
| 18 | + QString target, query; | ||
| 19 | + Template result = BEE::readMatrix(file, &target, &query); | ||
| 20 | + result.file.set("Target", target); | ||
| 21 | + result.file.set("Query", query); | ||
| 22 | + return result; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + void write(const Template &t) const | ||
| 26 | + { | ||
| 27 | + BEE::writeMatrix(t, file); | ||
| 28 | + } | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +BR_REGISTER(Format, mtxFormat) | ||
| 32 | + | ||
| 33 | +/*! | ||
| 34 | + * \ingroup formats | ||
| 35 | + * \brief Reads a NIST BEE mask matrix. | ||
| 36 | + * \author Josh Klontz \cite jklontz | ||
| 37 | + */ | ||
| 38 | +class maskFormat : public mtxFormat | ||
| 39 | +{ | ||
| 40 | + Q_OBJECT | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +BR_REGISTER(Format, maskFormat) | ||
| 44 | + | ||
| 45 | +} // namespace br | ||
| 46 | + | ||
| 47 | +#include "mtx.moc" |
openbr/plugins/format/null.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup formats | ||
| 8 | + * \brief Returns an empty matrix. | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class nullFormat : public Format | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + | ||
| 15 | + Template read() const | ||
| 16 | + { | ||
| 17 | + return Template(file, cv::Mat()); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + void write(const Template &t) const | ||
| 21 | + { | ||
| 22 | + (void)t; | ||
| 23 | + } | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +BR_REGISTER(Format, nullFormat) | ||
| 27 | + | ||
| 28 | +} // namespace br | ||
| 29 | + | ||
| 30 | +#include "null.moc" |
openbr/plugins/format/raw.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/qtutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup formats | ||
| 11 | + * \brief RAW format | ||
| 12 | + * | ||
| 13 | + * http://www.nist.gov/srd/nistsd27.cfm | ||
| 14 | + * \author Josh Klontz \cite jklontz | ||
| 15 | + */ | ||
| 16 | +class rawFormat : public Format | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + static QHash<QString, QHash<QString,QSize> > imageSizes; // QHash<Path, QHash<File,Size> > | ||
| 20 | + | ||
| 21 | + Template read() const | ||
| 22 | + { | ||
| 23 | + QString path = file.path(); | ||
| 24 | + if (!imageSizes.contains(path)) { | ||
| 25 | + static QMutex mutex; | ||
| 26 | + QMutexLocker locker(&mutex); | ||
| 27 | + | ||
| 28 | + if (!imageSizes.contains(path)) { | ||
| 29 | + const QString imageSize = path+"/ImageSize.txt"; | ||
| 30 | + QStringList lines; | ||
| 31 | + if (QFileInfo(imageSize).exists()) { | ||
| 32 | + lines = QtUtils::readLines(imageSize); | ||
| 33 | + lines.removeFirst(); // Remove header | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + QHash<QString,QSize> sizes; | ||
| 37 | + QRegExp whiteSpace("\\s+"); | ||
| 38 | + foreach (const QString &line, lines) { | ||
| 39 | + QStringList words = line.split(whiteSpace); | ||
| 40 | + if (words.size() != 3) continue; | ||
| 41 | + sizes.insert(words[0], QSize(words[2].toInt(), words[1].toInt())); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + imageSizes.insert(path, sizes); | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + QByteArray data; | ||
| 49 | + QtUtils::readFile(file, data); | ||
| 50 | + | ||
| 51 | + QSize size = imageSizes[path][file.baseName()]; | ||
| 52 | + if (!size.isValid()) size = QSize(800,768); | ||
| 53 | + if (data.size() != size.width() * size.height()) | ||
| 54 | + qFatal("Expected %d*%d bytes, got %d.", size.height(), size.width(), data.size()); | ||
| 55 | + return Template(file, Mat(size.height(), size.width(), CV_8UC1, data.data()).clone()); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + void write(const Template &t) const | ||
| 59 | + { | ||
| 60 | + QtUtils::writeFile(file, QByteArray().setRawData((const char*)t.m().data, t.m().total() * t.m().elemSize())); | ||
| 61 | + } | ||
| 62 | +}; | ||
| 63 | + | ||
| 64 | +QHash<QString, QHash<QString,QSize> > rawFormat::imageSizes; | ||
| 65 | + | ||
| 66 | +BR_REGISTER(Format, rawFormat) | ||
| 67 | + | ||
| 68 | +} // namespace br | ||
| 69 | + | ||
| 70 | +#include "raw.moc" |
openbr/plugins/format/scores.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/qtutils.h> | ||
| 3 | +#include <openbr/core/opencvutils.h> | ||
| 4 | +#include <openbr/core/bee.h> | ||
| 5 | + | ||
| 6 | +using namespace cv; | ||
| 7 | + | ||
| 8 | +namespace br | ||
| 9 | +{ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \ingroup formats | ||
| 13 | + * \brief Reads in scores or ground truth from a text table. | ||
| 14 | + * \author Josh Klontz \cite jklontz | ||
| 15 | + * | ||
| 16 | + * Example of the format: | ||
| 17 | + * \code | ||
| 18 | + * 2.2531514 FALSE 99990377 99990164 | ||
| 19 | + * 2.2549822 TRUE 99990101 99990101 | ||
| 20 | + * \endcode | ||
| 21 | + */ | ||
| 22 | +class scoresFormat : public Format | ||
| 23 | +{ | ||
| 24 | + Q_OBJECT | ||
| 25 | + Q_PROPERTY(int column READ get_column WRITE set_column RESET reset_column STORED false) | ||
| 26 | + Q_PROPERTY(bool groundTruth READ get_groundTruth WRITE set_groundTruth RESET reset_groundTruth STORED false) | ||
| 27 | + Q_PROPERTY(QString delimiter READ get_delimiter WRITE set_delimiter RESET reset_delimiter STORED false) | ||
| 28 | + BR_PROPERTY(int, column, 0) | ||
| 29 | + BR_PROPERTY(bool, groundTruth, false) | ||
| 30 | + BR_PROPERTY(QString, delimiter, "\t") | ||
| 31 | + | ||
| 32 | + Template read() const | ||
| 33 | + { | ||
| 34 | + QFile f(file.name); | ||
| 35 | + if (!f.open(QFile::ReadOnly | QFile::Text)) | ||
| 36 | + qFatal("Failed to open %s for reading.", qPrintable(f.fileName())); | ||
| 37 | + QList<float> values; | ||
| 38 | + while (!f.atEnd()) { | ||
| 39 | + const QStringList words = QString(f.readLine()).split(delimiter); | ||
| 40 | + if (words.size() <= column) qFatal("Expected file to have at least %d columns.", column+1); | ||
| 41 | + const QString &word = words[column]; | ||
| 42 | + bool ok; | ||
| 43 | + float value = word.toFloat(&ok); | ||
| 44 | + if (!ok) value = (QtUtils::toBool(word) ? BEE::Match : BEE::NonMatch); | ||
| 45 | + values.append(value); | ||
| 46 | + } | ||
| 47 | + if (values.size() == 1) | ||
| 48 | + qWarning("Only one value read, double check file line endings."); | ||
| 49 | + Mat result = OpenCVUtils::toMat(values); | ||
| 50 | + if (groundTruth) result.convertTo(result, CV_8U); | ||
| 51 | + return result; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + void write(const Template &t) const | ||
| 55 | + { | ||
| 56 | + (void) t; | ||
| 57 | + qFatal("Not implemented."); | ||
| 58 | + } | ||
| 59 | +}; | ||
| 60 | + | ||
| 61 | +BR_REGISTER(Format, scoresFormat) | ||
| 62 | + | ||
| 63 | +} // namespace br | ||
| 64 | + | ||
| 65 | +#include "scores.moc" |
openbr/plugins/format/video.cpp
0 → 100644
| 1 | +#include <opencv2/highgui/highgui.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | +#include <openbr/core/qtutils.h> | ||
| 5 | +#include <openbr/core/opencvutils.h> | ||
| 6 | + | ||
| 7 | +using namespace cv; | ||
| 8 | + | ||
| 9 | +namespace br | ||
| 10 | +{ | ||
| 11 | + | ||
| 12 | +/*! | ||
| 13 | + * \ingroup formats | ||
| 14 | + * \brief Read all frames of a video using OpenCV | ||
| 15 | + * \author Charles Otto \cite caotto | ||
| 16 | + */ | ||
| 17 | +class videoFormat : public Format | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + | ||
| 21 | +public: | ||
| 22 | + Template read() const | ||
| 23 | + { | ||
| 24 | + if (!file.exists() ) | ||
| 25 | + return Template(); | ||
| 26 | + | ||
| 27 | + VideoCapture videoSource(file.name.toStdString()); | ||
| 28 | + videoSource.open(file.name.toStdString() ); | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + Template frames; | ||
| 32 | + if (!videoSource.isOpened()) { | ||
| 33 | + qWarning("video file open failed"); | ||
| 34 | + return frames; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + bool open = true; | ||
| 38 | + while (open) { | ||
| 39 | + cv::Mat frame; | ||
| 40 | + open = videoSource.read(frame); | ||
| 41 | + if (!open) break; | ||
| 42 | + | ||
| 43 | + frames.append(cv::Mat()); | ||
| 44 | + frames.back() = frame.clone(); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + return frames; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + void write(const Template &t) const | ||
| 51 | + { | ||
| 52 | + int fourcc = OpenCVUtils::getFourcc(); | ||
| 53 | + VideoWriter videoSink(file.name.toStdString(), fourcc, 30, t.begin()->size()); | ||
| 54 | + | ||
| 55 | + // Did we successfully open the output file? | ||
| 56 | + if (!videoSink.isOpened() ) qFatal("Failed to open output file"); | ||
| 57 | + | ||
| 58 | + for (Template::const_iterator it = t.begin(); it!= t.end(); ++it) { | ||
| 59 | + videoSink << *it; | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | +}; | ||
| 63 | + | ||
| 64 | +BR_REGISTER(Format, videoFormat) | ||
| 65 | + | ||
| 66 | +/*! | ||
| 67 | + * \ingroup formats | ||
| 68 | + * \brief Retrieves an image from a webcam. | ||
| 69 | + * \author Josh Klontz \cite jklontz | ||
| 70 | + */ | ||
| 71 | +class webcamFormat : public Format | ||
| 72 | +{ | ||
| 73 | + Q_OBJECT | ||
| 74 | + | ||
| 75 | + Template read() const | ||
| 76 | + { | ||
| 77 | + static QScopedPointer<VideoCapture> videoCapture; | ||
| 78 | + | ||
| 79 | + if (videoCapture.isNull()) | ||
| 80 | + videoCapture.reset(new VideoCapture(0)); | ||
| 81 | + | ||
| 82 | + Mat m; | ||
| 83 | + videoCapture->read(m); | ||
| 84 | + return Template(m); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + void write(const Template &t) const | ||
| 88 | + { | ||
| 89 | + (void) t; | ||
| 90 | + qFatal("Not supported."); | ||
| 91 | + } | ||
| 92 | +}; | ||
| 93 | + | ||
| 94 | +BR_REGISTER(Format, webcamFormat) | ||
| 95 | + | ||
| 96 | +/*! | ||
| 97 | + * \ingroup formats | ||
| 98 | + * \brief Reads image files. | ||
| 99 | + * \author Josh Klontz \cite jklontz | ||
| 100 | + */ | ||
| 101 | +class DefaultFormat : public Format | ||
| 102 | +{ | ||
| 103 | + Q_OBJECT | ||
| 104 | + | ||
| 105 | + Template read() const | ||
| 106 | + { | ||
| 107 | + Template t; | ||
| 108 | + | ||
| 109 | + if (file.name.startsWith("http://") || file.name.startsWith("https://") || file.name.startsWith("www.")) { | ||
| 110 | + if (Factory<Format>::names().contains("url")) { | ||
| 111 | + File urlFile = file; | ||
| 112 | + urlFile.name.append(".url"); | ||
| 113 | + QScopedPointer<Format> url(Factory<Format>::make(urlFile)); | ||
| 114 | + t = url->read(); | ||
| 115 | + } | ||
| 116 | + } else { | ||
| 117 | + Mat m = imread(file.resolved().toStdString()); | ||
| 118 | + if (m.data) { | ||
| 119 | + t.append(m); | ||
| 120 | + } else { | ||
| 121 | + videoFormat videoReader; | ||
| 122 | + videoReader.file = file; | ||
| 123 | + t = videoReader.read(); | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + return t; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + void write(const Template &t) const | ||
| 131 | + { | ||
| 132 | + if (t.size() > 1) { | ||
| 133 | + videoFormat videoWriter; | ||
| 134 | + videoWriter.file = file; | ||
| 135 | + videoWriter.write(t); | ||
| 136 | + } else if (t.size() == 1) { | ||
| 137 | + QtUtils::touchDir(QDir(file.path())); | ||
| 138 | + imwrite(file.name.toStdString(), t); | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | +}; | ||
| 142 | + | ||
| 143 | +BR_REGISTER(Format, DefaultFormat) | ||
| 144 | + | ||
| 145 | +} // namespace br | ||
| 146 | + | ||
| 147 | +#include "video.moc" |
openbr/plugins/format/xml.cpp
0 → 100644
| 1 | +#ifndef BR_EMBEDDED | ||
| 2 | +#include <QtXml> | ||
| 3 | +#endif // BR_EMBEDDED | ||
| 4 | +#include <opencv2/highgui/highgui.hpp> | ||
| 5 | + | ||
| 6 | +#include <openbr/plugins/openbr_internal.h> | ||
| 7 | +#include <openbr/core/qtutils.h> | ||
| 8 | + | ||
| 9 | +using namespace cv; | ||
| 10 | + | ||
| 11 | +namespace br | ||
| 12 | +{ | ||
| 13 | + | ||
| 14 | +/*! | ||
| 15 | + * \ingroup formats | ||
| 16 | + * \brief Decodes images from Base64 xml | ||
| 17 | + * \author Scott Klum \cite sklum | ||
| 18 | + * \author Josh Klontz \cite jklontz | ||
| 19 | + */ | ||
| 20 | +class xmlFormat : public Format | ||
| 21 | +{ | ||
| 22 | + Q_OBJECT | ||
| 23 | + | ||
| 24 | + Template read() const | ||
| 25 | + { | ||
| 26 | + Template t; | ||
| 27 | + | ||
| 28 | +#ifndef BR_EMBEDDED | ||
| 29 | + QString fileName = file.get<QString>("path") + file.name; | ||
| 30 | + | ||
| 31 | + QDomDocument doc(fileName); | ||
| 32 | + QFile f(fileName); | ||
| 33 | + | ||
| 34 | + if (!f.open(QIODevice::ReadOnly)) qFatal("Unable to open %s for reading.", qPrintable(file.flat())); | ||
| 35 | + if (!doc.setContent(&f)) qWarning("Unable to parse %s.", qPrintable(file.flat())); | ||
| 36 | + f.close(); | ||
| 37 | + | ||
| 38 | + QDomElement docElem = doc.documentElement(); | ||
| 39 | + QDomNode subject = docElem.firstChild(); | ||
| 40 | + while (!subject.isNull()) { | ||
| 41 | + QDomNode fileNode = subject.firstChild(); | ||
| 42 | + | ||
| 43 | + while (!fileNode.isNull()) { | ||
| 44 | + QDomElement e = fileNode.toElement(); | ||
| 45 | + | ||
| 46 | + if (e.tagName() == "FORMAL_IMG") { | ||
| 47 | + QByteArray byteArray = QByteArray::fromBase64(qPrintable(e.text())); | ||
| 48 | + Mat m = imdecode(Mat(3, byteArray.size(), CV_8UC3, byteArray.data()), CV_LOAD_IMAGE_COLOR); | ||
| 49 | + if (!m.data) qWarning("xmlFormat::read failed to decode image data."); | ||
| 50 | + t.append(m); | ||
| 51 | + } else if ((e.tagName() == "RELEASE_IMG") || | ||
| 52 | + (e.tagName() == "PREBOOK_IMG") || | ||
| 53 | + (e.tagName() == "LPROFILE") || | ||
| 54 | + (e.tagName() == "RPROFILE")) { | ||
| 55 | + // Ignore these other image fields for now | ||
| 56 | + } else { | ||
| 57 | + t.file.set(e.tagName(), e.text()); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + fileNode = fileNode.nextSibling(); | ||
| 61 | + } | ||
| 62 | + subject = subject.nextSibling(); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + // Calculate age | ||
| 66 | + if (t.file.contains("DOB")) { | ||
| 67 | + const QDate dob = QDate::fromString(t.file.get<QString>("DOB").left(10), "yyyy-MM-dd"); | ||
| 68 | + const QDate current = QDate::currentDate(); | ||
| 69 | + int age = current.year() - dob.year(); | ||
| 70 | + if (current.month() < dob.month()) age--; | ||
| 71 | + t.file.set("Age", age); | ||
| 72 | + } | ||
| 73 | +#endif // BR_EMBEDDED | ||
| 74 | + | ||
| 75 | + return t; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + void write(const Template &t) const | ||
| 79 | + { | ||
| 80 | + QStringList lines; | ||
| 81 | + lines.append("<?xml version=\"1.0\" standalone=\"yes\"?>"); | ||
| 82 | + lines.append("<openbr-xml-format>"); | ||
| 83 | + lines.append("\t<xml-data>"); | ||
| 84 | + foreach (const QString &key, t.file.localKeys()) { | ||
| 85 | + if ((key == "Index") || (key == "Label")) continue; | ||
| 86 | + lines.append("\t\t<"+key+">"+QtUtils::toString(t.file.value(key))+"</"+key+">"); | ||
| 87 | + } | ||
| 88 | + std::vector<uchar> data; | ||
| 89 | + imencode(".jpg",t.m(),data); | ||
| 90 | + QByteArray byteArray = QByteArray::fromRawData((const char*)data.data(), data.size()); | ||
| 91 | + lines.append("\t\t<FORMAL_IMG>"+byteArray.toBase64()+"</FORMAL_IMG>"); | ||
| 92 | + lines.append("\t</xml-data>"); | ||
| 93 | + lines.append("</openbr-xml-format>"); | ||
| 94 | + QtUtils::writeFile(file, lines); | ||
| 95 | + } | ||
| 96 | +}; | ||
| 97 | + | ||
| 98 | +BR_REGISTER(Format, xmlFormat) | ||
| 99 | + | ||
| 100 | +} // namespace br | ||
| 101 | + | ||
| 102 | +#include "xml.moc" |
openbr/plugins/gui.cpp
| @@ -928,6 +928,54 @@ public: | @@ -928,6 +928,54 @@ public: | ||
| 928 | 928 | ||
| 929 | BR_REGISTER(Transform, SurveyTransform) | 929 | BR_REGISTER(Transform, SurveyTransform) |
| 930 | 930 | ||
| 931 | +class FilterTransform : public ShowTransform | ||
| 932 | +{ | ||
| 933 | + Q_OBJECT | ||
| 934 | + | ||
| 935 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 936 | + { | ||
| 937 | + if (Globals->parallelism > 1) | ||
| 938 | + qFatal("FilterTransform cannot execute in parallel."); | ||
| 939 | + | ||
| 940 | + if (src.empty()) | ||
| 941 | + return; | ||
| 942 | + | ||
| 943 | + foreach (const Template &t, src) { | ||
| 944 | + Template u(t.file); | ||
| 945 | + foreach (const cv::Mat &m, t) { | ||
| 946 | + qImageBuffer = toQImage(m); | ||
| 947 | + displayBuffer->convertFromImage(qImageBuffer); | ||
| 948 | + | ||
| 949 | + emit updateImage(displayBuffer->copy(displayBuffer->rect())); | ||
| 950 | + | ||
| 951 | + // Blocking wait for a key-press | ||
| 952 | + if (this->waitInput) { | ||
| 953 | + QString answer = p_window->waitForKeyPress(); | ||
| 954 | + qDebug() << answer; | ||
| 955 | + if (answer == "y") | ||
| 956 | + u.append(m); | ||
| 957 | + } | ||
| 958 | + } | ||
| 959 | + if (!u.empty()) | ||
| 960 | + dst.append(u); | ||
| 961 | + } | ||
| 962 | + } | ||
| 963 | + PromptWindow *p_window; | ||
| 964 | + | ||
| 965 | + | ||
| 966 | + void init() | ||
| 967 | + { | ||
| 968 | + if (!Globals->useGui) | ||
| 969 | + return; | ||
| 970 | + | ||
| 971 | + initActual<PromptWindow>(); | ||
| 972 | + p_window = (PromptWindow *) window; | ||
| 973 | + | ||
| 974 | + emit changeTitle("Keep: y Discard: n"); | ||
| 975 | + } | ||
| 976 | +}; | ||
| 977 | + | ||
| 978 | +BR_REGISTER(Transform, FilterTransform) | ||
| 931 | 979 | ||
| 932 | /*! | 980 | /*! |
| 933 | * \ingroup transforms | 981 | * \ingroup transforms |
openbr/plugins/gui/adjacentoverlay.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Load the image named in the specified property, draw it on the current matrix adjacent to the rect specified in the other property. | ||
| 13 | + * \author Charles Otto \cite caotto | ||
| 14 | + */ | ||
| 15 | +class AdjacentOverlayTransform : public Transform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + | ||
| 19 | + Q_PROPERTY(QString imgName READ get_imgName WRITE set_imgName RESET reset_imgName STORED false) | ||
| 20 | + Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false) | ||
| 21 | + BR_PROPERTY(QString, imgName, "") | ||
| 22 | + BR_PROPERTY(QString, targetName, "") | ||
| 23 | + | ||
| 24 | + QSharedPointer<Transform> opener; | ||
| 25 | + void project(const Template &src, Template &dst) const | ||
| 26 | + { | ||
| 27 | + dst = src; | ||
| 28 | + | ||
| 29 | + if (imgName.isEmpty() || targetName.isEmpty() || !dst.file.contains(imgName) || !dst.file.contains(targetName)) | ||
| 30 | + return; | ||
| 31 | + | ||
| 32 | + QVariant temp = src.file.value(imgName); | ||
| 33 | + cv::Mat im; | ||
| 34 | + // is this a filename? | ||
| 35 | + if (temp.canConvert<QString>()) { | ||
| 36 | + QString im_name = temp.toString(); | ||
| 37 | + Template temp_im; | ||
| 38 | + opener->project(File(im_name), temp_im); | ||
| 39 | + im = temp_im.m(); | ||
| 40 | + } | ||
| 41 | + // a cv::Mat ? | ||
| 42 | + else if (temp.canConvert<cv::Mat>()) | ||
| 43 | + im = src.file.get<cv::Mat>(imgName); | ||
| 44 | + else | ||
| 45 | + qDebug() << "Unrecognized property type " << imgName << "for" << src.file.name; | ||
| 46 | + | ||
| 47 | + // Location of detected face in source image | ||
| 48 | + QRectF target_location = src.file.get<QRectF>(targetName); | ||
| 49 | + | ||
| 50 | + // match width with target region | ||
| 51 | + qreal target_width = target_location.width(); | ||
| 52 | + qreal current_width = im.cols; | ||
| 53 | + qreal current_height = im.rows; | ||
| 54 | + | ||
| 55 | + qreal aspect_ratio = current_height / current_width; | ||
| 56 | + qreal target_height = target_width * aspect_ratio; | ||
| 57 | + | ||
| 58 | + cv::resize(im, im, cv::Size(target_width, target_height)); | ||
| 59 | + | ||
| 60 | + // ROI used to maybe crop the matched image | ||
| 61 | + cv::Rect clip_roi; | ||
| 62 | + clip_roi.x = 0; | ||
| 63 | + clip_roi.y = 0; | ||
| 64 | + clip_roi.width = im.cols; | ||
| 65 | + clip_roi.height= im.rows <= dst.m().rows ? im.rows : dst.m().rows; | ||
| 66 | + | ||
| 67 | + int half_width = src.m().cols / 2; | ||
| 68 | + int out_x = 0; | ||
| 69 | + | ||
| 70 | + // place in the source image we will copy the matched image to. | ||
| 71 | + cv::Rect target_roi; | ||
| 72 | + bool left_side = false; | ||
| 73 | + int width_adjust = 0; | ||
| 74 | + // Place left | ||
| 75 | + if (target_location.center().rx() > half_width) { | ||
| 76 | + out_x = target_location.left() - im.cols; | ||
| 77 | + if (out_x < 0) { | ||
| 78 | + width_adjust = abs(out_x); | ||
| 79 | + out_x = 0; | ||
| 80 | + } | ||
| 81 | + left_side = true; | ||
| 82 | + } | ||
| 83 | + // place right | ||
| 84 | + else { | ||
| 85 | + out_x = target_location.right(); | ||
| 86 | + int high = out_x + im.cols; | ||
| 87 | + if (high >= src.m().cols) { | ||
| 88 | + width_adjust = abs(high - src.m().cols + 1); | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + cv::Mat outIm; | ||
| 93 | + if (width_adjust) | ||
| 94 | + { | ||
| 95 | + outIm.create(dst.m().rows, dst.m().cols + width_adjust, CV_8UC3); | ||
| 96 | + memset(outIm.data, 127, outIm.rows * outIm.cols * outIm.channels()); | ||
| 97 | + | ||
| 98 | + Rect temp; | ||
| 99 | + | ||
| 100 | + if (left_side) | ||
| 101 | + temp = Rect(abs(width_adjust), 0, dst.m().cols, dst.m().rows); | ||
| 102 | + | ||
| 103 | + else | ||
| 104 | + temp = Rect(0, 0, dst.m().cols, dst.m().rows); | ||
| 105 | + | ||
| 106 | + dst.m().copyTo(outIm(temp)); | ||
| 107 | + | ||
| 108 | + } | ||
| 109 | + else | ||
| 110 | + outIm = dst.m(); | ||
| 111 | + | ||
| 112 | + if (clip_roi.height + target_location.top() >= outIm.rows) | ||
| 113 | + { | ||
| 114 | + clip_roi.height -= abs(outIm.rows - (clip_roi.height + target_location.top() )); | ||
| 115 | + } | ||
| 116 | + if (clip_roi.x + clip_roi.width >= im.cols) { | ||
| 117 | + clip_roi.width -= abs(im.cols - (clip_roi.x + clip_roi.width + 1)); | ||
| 118 | + if (clip_roi.width < 0) | ||
| 119 | + clip_roi.width = 1; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + if (clip_roi.y + clip_roi.height >= im.rows) { | ||
| 123 | + clip_roi.height -= abs(im.rows - (clip_roi.y + clip_roi.height + 1)); | ||
| 124 | + } | ||
| 125 | + if (clip_roi.x < 0) | ||
| 126 | + clip_roi.x = 0; | ||
| 127 | + if (clip_roi.y < 0) | ||
| 128 | + clip_roi.y = 0; | ||
| 129 | + | ||
| 130 | + if (clip_roi.height < 0) | ||
| 131 | + clip_roi.height = 0; | ||
| 132 | + | ||
| 133 | + if (clip_roi.width < 0) | ||
| 134 | + clip_roi.width = 0; | ||
| 135 | + | ||
| 136 | + | ||
| 137 | + if (clip_roi.y + clip_roi.height >= im.rows) | ||
| 138 | + { | ||
| 139 | + qDebug() << "Bad clip y" << clip_roi.y + clip_roi.height << im.rows; | ||
| 140 | + } | ||
| 141 | + if (clip_roi.x + clip_roi.width >= im.cols) | ||
| 142 | + { | ||
| 143 | + qDebug() << "Bad clip x" << clip_roi.x + clip_roi.width << im.cols; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + if (clip_roi.y < 0 || clip_roi.height < 0) | ||
| 147 | + { | ||
| 148 | + qDebug() << "bad clip y, low" << clip_roi.y << clip_roi.height; | ||
| 149 | + qFatal("die"); | ||
| 150 | + } | ||
| 151 | + if (clip_roi.x < 0 || clip_roi.width < 0) | ||
| 152 | + { | ||
| 153 | + qDebug() << "bad clip x, low" << clip_roi.x << clip_roi.width; | ||
| 154 | + qFatal("die"); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + target_roi.x = out_x; | ||
| 158 | + target_roi.width = clip_roi.width; | ||
| 159 | + target_roi.y = target_location.top(); | ||
| 160 | + target_roi.height = clip_roi.height; | ||
| 161 | + | ||
| 162 | + | ||
| 163 | + im = im(clip_roi); | ||
| 164 | + | ||
| 165 | + if (target_roi.x < 0 || target_roi.x >= outIm.cols) | ||
| 166 | + { | ||
| 167 | + qDebug() << "Bad xdim in targetROI!" << target_roi.x << " out im x: " << outIm.cols; | ||
| 168 | + qFatal("die"); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + if (target_roi.x + target_roi.width < 0 || (target_roi.x + target_roi.width) >= outIm.cols) | ||
| 172 | + { | ||
| 173 | + qDebug() << "Bad xdim in targetROI!" << target_roi.x + target_roi.width; | ||
| 174 | + qFatal("die"); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + if (target_roi.y < 0 || target_roi.y >= outIm.rows) | ||
| 178 | + { | ||
| 179 | + qDebug() << "Bad ydim in targetROI!" << target_roi.y; | ||
| 180 | + qFatal("die"); | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + if ((target_roi.y + target_roi.height) < 0 || (target_roi.y + target_roi.height) > outIm.rows) | ||
| 184 | + { | ||
| 185 | + qDebug() << "Bad ydim in targetROI!" << target_roi.y + target_roi.height; | ||
| 186 | + qDebug() << "target_roi.y: " << target_roi.y << " height: " << target_roi.height; | ||
| 187 | + qFatal("die"); | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + | ||
| 191 | + std::vector<cv::Mat> channels; | ||
| 192 | + cv::split(outIm, channels); | ||
| 193 | + | ||
| 194 | + std::vector<cv::Mat> patch_channels; | ||
| 195 | + cv::split(im, patch_channels); | ||
| 196 | + | ||
| 197 | + for (size_t i=0; i < channels.size(); i++) | ||
| 198 | + { | ||
| 199 | + cv::addWeighted(channels[i](target_roi), 0, patch_channels[i % patch_channels.size()], 1, 0,channels[i](target_roi)); | ||
| 200 | + } | ||
| 201 | + cv::merge(channels, outIm); | ||
| 202 | + dst.m() = outIm; | ||
| 203 | + | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + void init() | ||
| 207 | + { | ||
| 208 | + opener = QSharedPointer<br::Transform>(br::Transform::make("Cache(Open)", NULL)); | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | +}; | ||
| 212 | + | ||
| 213 | +BR_REGISTER(Transform, AdjacentOverlayTransform) | ||
| 214 | + | ||
| 215 | +} // namespace br | ||
| 216 | + | ||
| 217 | +#include "adjacentoverlay.moc" |
openbr/plugins/gui/draw.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Renders metadata onto the image. | ||
| 12 | + * | ||
| 13 | + * The inPlace argument controls whether or not the image is cloned before the metadata is drawn. | ||
| 14 | + * | ||
| 15 | + * \author Josh Klontz \cite jklontz | ||
| 16 | + */ | ||
| 17 | +class DrawTransform : public UntrainableTransform | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + Q_PROPERTY(bool verbose READ get_verbose WRITE set_verbose RESET reset_verbose STORED false) | ||
| 21 | + Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) | ||
| 22 | + Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) | ||
| 23 | + Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | ||
| 24 | + Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false) | ||
| 25 | + Q_PROPERTY(bool named READ get_named WRITE set_named RESET reset_named STORED false) | ||
| 26 | + Q_PROPERTY(bool location READ get_location WRITE set_location RESET reset_location STORED false) | ||
| 27 | + BR_PROPERTY(bool, verbose, false) | ||
| 28 | + BR_PROPERTY(bool, points, true) | ||
| 29 | + BR_PROPERTY(bool, rects, true) | ||
| 30 | + BR_PROPERTY(bool, inPlace, false) | ||
| 31 | + BR_PROPERTY(int, lineThickness, 1) | ||
| 32 | + BR_PROPERTY(bool, named, true) | ||
| 33 | + BR_PROPERTY(bool, location, true) | ||
| 34 | + | ||
| 35 | + void project(const Template &src, Template &dst) const | ||
| 36 | + { | ||
| 37 | + const Scalar color(0,255,0); | ||
| 38 | + const Scalar verboseColor(255, 255, 0); | ||
| 39 | + dst.m() = inPlace ? src.m() : src.m().clone(); | ||
| 40 | + | ||
| 41 | + if (points) { | ||
| 42 | + const QList<Point2f> pointsList = (named) ? OpenCVUtils::toPoints(src.file.points()+src.file.namedPoints()) : OpenCVUtils::toPoints(src.file.points()); | ||
| 43 | + for (int i=0; i<pointsList.size(); i++) { | ||
| 44 | + const Point2f &point = pointsList[i]; | ||
| 45 | + circle(dst, point, 3, color, -1); | ||
| 46 | + QString label = (location) ? QString("%1,(%2,%3)").arg(QString::number(i),QString::number(point.x),QString::number(point.y)) : QString("%1").arg(QString::number(i)); | ||
| 47 | + if (verbose) putText(dst, label.toStdString(), point, FONT_HERSHEY_SIMPLEX, 0.5, verboseColor, 1); | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | + if (rects) { | ||
| 51 | + foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects())) | ||
| 52 | + rectangle(dst, rect, color, lineThickness); | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | +}; | ||
| 56 | + | ||
| 57 | +BR_REGISTER(Transform, DrawTransform) | ||
| 58 | + | ||
| 59 | +} // namespace br | ||
| 60 | + | ||
| 61 | +#include "draw.moc" |
openbr/plugins/gui/drawgridlines.cpp
0 → 100644
| 1 | +#include <opencv2/highgui/highgui.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Draws a grid on the image | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class DrawGridLinesTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | ||
| 19 | + Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | ||
| 20 | + Q_PROPERTY(int r READ get_r WRITE set_r RESET reset_r STORED false) | ||
| 21 | + Q_PROPERTY(int g READ get_g WRITE set_g RESET reset_g STORED false) | ||
| 22 | + Q_PROPERTY(int b READ get_b WRITE set_b RESET reset_b STORED false) | ||
| 23 | + BR_PROPERTY(int, rows, 0) | ||
| 24 | + BR_PROPERTY(int, columns, 0) | ||
| 25 | + BR_PROPERTY(int, r, 196) | ||
| 26 | + BR_PROPERTY(int, g, 196) | ||
| 27 | + BR_PROPERTY(int, b, 196) | ||
| 28 | + | ||
| 29 | + void project(const Template &src, Template &dst) const | ||
| 30 | + { | ||
| 31 | + Mat m = src.m().clone(); | ||
| 32 | + float rowStep = 1.f * m.rows / (rows+1); | ||
| 33 | + float columnStep = 1.f * m.cols / (columns+1); | ||
| 34 | + int thickness = qMin(m.rows, m.cols) / 256; | ||
| 35 | + for (float row = rowStep/2; row < m.rows; row += rowStep) | ||
| 36 | + line(m, Point(0, row), Point(m.cols, row), Scalar(r, g, b), thickness, CV_AA); | ||
| 37 | + for (float column = columnStep/2; column < m.cols; column += columnStep) | ||
| 38 | + line(m, Point(column, 0), Point(column, m.rows), Scalar(r, g, b), thickness, CV_AA); | ||
| 39 | + dst = m; | ||
| 40 | + } | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +BR_REGISTER(Transform, DrawGridLinesTransform) | ||
| 44 | + | ||
| 45 | +} // namespace br | ||
| 46 | + | ||
| 47 | +#include "drawgridlines.moc" |
openbr/plugins/gui/drawopticalflow.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Draw a line representing the direction and magnitude of optical flow at the specified points. | ||
| 12 | + * \author Austin Blanton \cite imaus10 | ||
| 13 | + */ | ||
| 14 | +class DrawOpticalFlow : public UntrainableTransform | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + Q_PROPERTY(QString original READ get_original WRITE set_original RESET reset_original STORED false) | ||
| 18 | + BR_PROPERTY(QString, original, "original") | ||
| 19 | + | ||
| 20 | + void project(const Template &src, Template &dst) const | ||
| 21 | + { | ||
| 22 | + const Scalar color(0,255,0); | ||
| 23 | + Mat flow = src.m(); | ||
| 24 | + dst = src; | ||
| 25 | + if (!dst.file.contains(original)) qFatal("The original img must be saved in the metadata with SaveMat."); | ||
| 26 | + dst.m() = dst.file.get<Mat>(original); | ||
| 27 | + dst.file.remove(original); | ||
| 28 | + foreach (const Point2f &pt, OpenCVUtils::toPoints(dst.file.points())) { | ||
| 29 | + Point2f dxy = flow.at<Point2f>(pt.y, pt.x); | ||
| 30 | + Point2f newPt(pt.x+dxy.x, pt.y+dxy.y); | ||
| 31 | + line(dst, pt, newPt, color); | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +BR_REGISTER(Transform, DrawOpticalFlow) | ||
| 37 | + | ||
| 38 | +} // namespace br | ||
| 39 | + | ||
| 40 | +#include "drawopticalflow.moc" |
openbr/plugins/gui/drawpropertiespoint.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Draw the values of a list of properties at the specified point on the image | ||
| 12 | + * | ||
| 13 | + * The inPlace argument controls whether or not the image is cloned before it is drawn on. | ||
| 14 | + * | ||
| 15 | + * \author Charles Otto \cite caotto | ||
| 16 | + */ | ||
| 17 | +class DrawPropertiesPointTransform : public UntrainableTransform | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + Q_PROPERTY(QStringList propNames READ get_propNames WRITE set_propNames RESET reset_propNames STORED false) | ||
| 21 | + Q_PROPERTY(QString pointName READ get_pointName WRITE set_pointName RESET reset_pointName STORED false) | ||
| 22 | + Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | ||
| 23 | + BR_PROPERTY(QStringList, propNames, QStringList()) | ||
| 24 | + BR_PROPERTY(QString, pointName, "") | ||
| 25 | + BR_PROPERTY(bool, inPlace, false) | ||
| 26 | + | ||
| 27 | + void project(const Template &src, Template &dst) const | ||
| 28 | + { | ||
| 29 | + dst = src; | ||
| 30 | + if (propNames.isEmpty() || pointName.isEmpty()) | ||
| 31 | + return; | ||
| 32 | + | ||
| 33 | + dst.m() = inPlace ? src.m() : src.m().clone(); | ||
| 34 | + | ||
| 35 | + QVariant point = dst.file.value(pointName); | ||
| 36 | + | ||
| 37 | + if (!point.canConvert(QVariant::PointF)) | ||
| 38 | + return; | ||
| 39 | + | ||
| 40 | + QPointF targetPoint = point.toPointF(); | ||
| 41 | + | ||
| 42 | + Point2f cvPoint = OpenCVUtils::toPoint(targetPoint); | ||
| 43 | + | ||
| 44 | + | ||
| 45 | + const Scalar textColor(255, 255, 0); | ||
| 46 | + | ||
| 47 | + std::string outString = ""; | ||
| 48 | + foreach (const QString &propName, propNames) | ||
| 49 | + { | ||
| 50 | + QVariant prop = dst.file.value(propName); | ||
| 51 | + | ||
| 52 | + if (!prop.canConvert(QVariant::String)) | ||
| 53 | + continue; | ||
| 54 | + QString propString = prop.toString(); | ||
| 55 | + outString += propName.toStdString() + ": " + propString.toStdString() + " "; | ||
| 56 | + | ||
| 57 | + } | ||
| 58 | + if (outString.empty()) | ||
| 59 | + return; | ||
| 60 | + | ||
| 61 | + putText(dst, outString, cvPoint, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +BR_REGISTER(Transform, DrawPropertiesPointTransform) | ||
| 67 | + | ||
| 68 | +} // namespace br | ||
| 69 | + | ||
| 70 | +#include "drawpropertiespoint.moc" |
openbr/plugins/gui/drawpropertypoint.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Draw the value of the specified property at the specified point on the image | ||
| 12 | + * | ||
| 13 | + * The inPlace argument controls whether or not the image is cloned before it is drawn on. | ||
| 14 | + * | ||
| 15 | + * \author Charles Otto \cite caotto | ||
| 16 | + */ | ||
| 17 | +class DrawPropertyPointTransform : public UntrainableTransform | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | ||
| 21 | + Q_PROPERTY(QString pointName READ get_pointName WRITE set_pointName RESET reset_pointName STORED false) | ||
| 22 | + Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | ||
| 23 | + BR_PROPERTY(QString, propName, "") | ||
| 24 | + BR_PROPERTY(QString, pointName, "") | ||
| 25 | + BR_PROPERTY(bool, inPlace, false) | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + void project(const Template &src, Template &dst) const | ||
| 29 | + { | ||
| 30 | + dst = src; | ||
| 31 | + if (propName.isEmpty() || pointName.isEmpty()) | ||
| 32 | + return; | ||
| 33 | + | ||
| 34 | + dst.m() = inPlace ? src.m() : src.m().clone(); | ||
| 35 | + | ||
| 36 | + const Scalar textColor(255, 255, 0); | ||
| 37 | + | ||
| 38 | + QVariant prop = dst.file.value(propName); | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + if (!prop.canConvert(QVariant::String)) | ||
| 42 | + return; | ||
| 43 | + QString propString = prop.toString(); | ||
| 44 | + | ||
| 45 | + QVariant point = dst.file.value(pointName); | ||
| 46 | + | ||
| 47 | + if (!point.canConvert(QVariant::PointF)) | ||
| 48 | + return; | ||
| 49 | + | ||
| 50 | + QPointF targetPoint = point.toPointF(); | ||
| 51 | + | ||
| 52 | + Point2f cvPoint = OpenCVUtils::toPoint(targetPoint); | ||
| 53 | + | ||
| 54 | + std::string text = propName.toStdString() + ": " + propString.toStdString(); | ||
| 55 | + putText(dst, text, cvPoint, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | +}; | ||
| 59 | +BR_REGISTER(Transform, DrawPropertyPointTransform) | ||
| 60 | + | ||
| 61 | +} // namespace br | ||
| 62 | + | ||
| 63 | +#include "drawpropertypoint.moc" |
openbr/plugins/gui/drawsegmentation.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace std; | ||
| 6 | +using namespace cv; | ||
| 7 | + | ||
| 8 | +namespace br | ||
| 9 | +{ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \ingroup transforms | ||
| 13 | + * \brief Fill in the segmentations or draw a line between intersecting segments. | ||
| 14 | + * \author Austin Blanton \cite imaus10 | ||
| 15 | + */ | ||
| 16 | +class DrawSegmentation : public UntrainableTransform | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + Q_PROPERTY(bool fillSegment READ get_fillSegment WRITE set_fillSegment RESET reset_fillSegment STORED false) | ||
| 20 | + BR_PROPERTY(bool, fillSegment, true) | ||
| 21 | + | ||
| 22 | + void project(const Template &src, Template &dst) const | ||
| 23 | + { | ||
| 24 | + if (!src.file.contains("SegmentsMask") || !src.file.contains("NumSegments")) qFatal("Must supply a Contours object in the metadata to drawContours."); | ||
| 25 | + Mat segments = src.file.get<Mat>("SegmentsMask"); | ||
| 26 | + int numSegments = src.file.get<int>("NumSegments"); | ||
| 27 | + | ||
| 28 | + dst.file = src.file; | ||
| 29 | + Mat drawn = fillSegment ? Mat(segments.size(), CV_8UC3, Scalar::all(0)) : src.m(); | ||
| 30 | + | ||
| 31 | + for (int i=1; i<numSegments+1; i++) { | ||
| 32 | + Mat mask = segments == i; | ||
| 33 | + if (fillSegment) { // color the whole segment | ||
| 34 | + // set to a random color - get ready for a craaaazy acid trip | ||
| 35 | + int b = theRNG().uniform(0, 255); | ||
| 36 | + int g = theRNG().uniform(0, 255); | ||
| 37 | + int r = theRNG().uniform(0, 255); | ||
| 38 | + drawn.setTo(Scalar(r,g,b), mask); | ||
| 39 | + } else { // draw lines where there's a color change | ||
| 40 | + vector<vector<Point> > contours; | ||
| 41 | + Scalar color(0,255,0); | ||
| 42 | + findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); | ||
| 43 | + drawContours(drawn, contours, -1, color); | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + dst.m() = drawn; | ||
| 48 | + } | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +BR_REGISTER(Transform, DrawSegmentation) | ||
| 52 | + | ||
| 53 | +} // namespace br | ||
| 54 | + | ||
| 55 | +#include "drawsegmentation.moc" |
openbr/plugins/imgproc/abs.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief Computes the absolute value of each element. | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class AbsTransform : public UntrainableTransform | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + | ||
| 15 | + void project(const Template &src, Template &dst) const | ||
| 16 | + { | ||
| 17 | + dst = cv::abs(src); | ||
| 18 | + } | ||
| 19 | +}; | ||
| 20 | + | ||
| 21 | +BR_REGISTER(Transform, AbsTransform) | ||
| 22 | + | ||
| 23 | +} // namespace br | ||
| 24 | + | ||
| 25 | +#include "abs.moc" |
openbr/plugins/imgproc/blend.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Alpha-blend two matrices | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class BlendTransform : public UntrainableMetaTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | ||
| 17 | + BR_PROPERTY(float, alpha, 0.5) | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + if (src.size() != 2) qFatal("Expected two source matrices."); | ||
| 22 | + addWeighted(src[0], alpha, src[1], 1-alpha, 0, dst); | ||
| 23 | + } | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +BR_REGISTER(Transform, BlendTransform) | ||
| 27 | + | ||
| 28 | +} // namespace br | ||
| 29 | + | ||
| 30 | +#include "blend.moc" |
openbr/plugins/imgproc/blur.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Gaussian blur | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class BlurTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(float sigma READ get_sigma WRITE set_sigma RESET reset_sigma STORED false) | ||
| 19 | + Q_PROPERTY(bool ROI READ get_ROI WRITE set_ROI RESET reset_ROI STORED false) | ||
| 20 | + BR_PROPERTY(float, sigma, 1) | ||
| 21 | + BR_PROPERTY(bool, ROI, false) | ||
| 22 | + | ||
| 23 | + void project(const Template &src, Template &dst) const | ||
| 24 | + { | ||
| 25 | + if (!ROI) GaussianBlur(src, dst, Size(0,0), sigma); | ||
| 26 | + else { | ||
| 27 | + dst.m() = src.m(); | ||
| 28 | + foreach (const QRectF &rect, src.file.rects()) { | ||
| 29 | + Rect region(rect.x(), rect.y(), rect.width(), rect.height()); | ||
| 30 | + Mat input = dst.m(); | ||
| 31 | + Mat output = input.clone(); | ||
| 32 | + GaussianBlur(input(region), output(region), Size(0,0), sigma); | ||
| 33 | + dst.m() = output; | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | +}; | ||
| 38 | + | ||
| 39 | +BR_REGISTER(Transform, BlurTransform) | ||
| 40 | + | ||
| 41 | +} // namespace br | ||
| 42 | + | ||
| 43 | +#include "blur.moc" |
openbr/plugins/imgproc/contrasteq.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/tanh_sse.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Xiaoyang Tan; Triggs, B.; | ||
| 12 | + * "Enhanced Local Texture Feature Sets for Face Recognition Under Difficult Lighting Conditions," | ||
| 13 | + * Image Processing, IEEE Transactions on , vol.19, no.6, pp.1635-1650, June 2010 | ||
| 14 | + * \author Josh Klontz \cite jklontz | ||
| 15 | + */ | ||
| 16 | +class ContrastEqTransform : public UntrainableTransform | ||
| 17 | +{ | ||
| 18 | + Q_OBJECT | ||
| 19 | + Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a STORED false) | ||
| 20 | + Q_PROPERTY(float t READ get_t WRITE set_t RESET reset_t STORED false) | ||
| 21 | + BR_PROPERTY(float, a, 1) | ||
| 22 | + BR_PROPERTY(float, t, 0.1) | ||
| 23 | + | ||
| 24 | + void project(const Template &src, Template &dst) const | ||
| 25 | + { | ||
| 26 | + if (src.m().channels() != 1) qFatal("Expected single channel source matrix."); | ||
| 27 | + | ||
| 28 | + // Stage 1 | ||
| 29 | + Mat stage1; | ||
| 30 | + { | ||
| 31 | + Mat abs_dst; | ||
| 32 | + absdiff(src, Scalar(0), abs_dst); | ||
| 33 | + Mat pow_dst; | ||
| 34 | + pow(abs_dst, a, pow_dst); | ||
| 35 | + float denominator = pow((float)mean(pow_dst)[0], 1.f/a); | ||
| 36 | + src.m().convertTo(stage1, CV_32F, 1/denominator); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + // Stage 2 | ||
| 40 | + Mat stage2; | ||
| 41 | + { | ||
| 42 | + Mat abs_dst; | ||
| 43 | + absdiff(stage1, Scalar(0), abs_dst); | ||
| 44 | + Mat min_dst; | ||
| 45 | + min(abs_dst, t, min_dst); | ||
| 46 | + Mat pow_dst; | ||
| 47 | + pow(min_dst, a, pow_dst); | ||
| 48 | + float denominator = pow((float)mean(pow_dst)[0], 1.f/a); | ||
| 49 | + stage1.convertTo(stage2, CV_32F, 1/denominator); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // Hyperbolic tangent | ||
| 53 | + const int nRows = src.m().rows; | ||
| 54 | + const int nCols = src.m().cols; | ||
| 55 | + const float* p = (const float*)stage2.ptr(); | ||
| 56 | + Mat m(nRows, nCols, CV_32FC1); | ||
| 57 | + for (int i=0; i<nRows; i++) | ||
| 58 | + for (int j=0; j<nCols; j++) | ||
| 59 | + m.at<float>(i, j) = fast_tanh(p[i*nCols+j]); | ||
| 60 | + // TODO: m.at<float>(i, j) = t * fast_tanh(p[i*nCols+j] / t); | ||
| 61 | + | ||
| 62 | + dst = m; | ||
| 63 | + } | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +BR_REGISTER(Transform, ContrastEqTransform) | ||
| 67 | + | ||
| 68 | +} // namespace br | ||
| 69 | + | ||
| 70 | +#include "contrasteq.moc" |
openbr/plugins/imgproc/crop.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Crops about the specified region of interest. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class CropTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(int x READ get_x WRITE set_x RESET reset_x STORED false) | ||
| 17 | + Q_PROPERTY(int y READ get_y WRITE set_y RESET reset_y STORED false) | ||
| 18 | + Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | ||
| 19 | + Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | ||
| 20 | + BR_PROPERTY(int, x, 0) | ||
| 21 | + BR_PROPERTY(int, y, 0) | ||
| 22 | + BR_PROPERTY(int, width, -1) | ||
| 23 | + BR_PROPERTY(int, height, -1) | ||
| 24 | + | ||
| 25 | + void project(const Template &src, Template &dst) const | ||
| 26 | + { | ||
| 27 | + dst = Mat(src, Rect(x, y, width < 1 ? src.m().cols-x-abs(width) : width, height < 1 ? src.m().rows-y-abs(height) : height)); | ||
| 28 | + } | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +BR_REGISTER(Transform, CropTransform) | ||
| 32 | + | ||
| 33 | +} // namespace br | ||
| 34 | + | ||
| 35 | +#include "crop.moc" |
openbr/plugins/imgproc/cropblack.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Crop out black borders | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + */ | ||
| 14 | +class CropBlackTransform : public UntrainableTransform | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + | ||
| 18 | + void project(const Template &src, Template &dst) const | ||
| 19 | + { | ||
| 20 | + Mat gray; | ||
| 21 | + OpenCVUtils::cvtGray(src, gray); | ||
| 22 | + | ||
| 23 | + int xStart = 0; | ||
| 24 | + while (xStart < gray.cols) { | ||
| 25 | + if (mean(gray.col(xStart))[0] >= 1) break; | ||
| 26 | + xStart++; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + int xEnd = gray.cols - 1; | ||
| 30 | + while (xEnd >= 0) { | ||
| 31 | + if (mean(gray.col(xEnd))[0] >= 1) break; | ||
| 32 | + xEnd--; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + int yStart = 0; | ||
| 36 | + while (yStart < gray.rows) { | ||
| 37 | + if (mean(gray.col(yStart))[0] >= 1) break; | ||
| 38 | + yStart++; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + int yEnd = gray.rows - 1; | ||
| 42 | + while (yEnd >= 0) { | ||
| 43 | + if (mean(gray.col(yEnd))[0] >= 1) break; | ||
| 44 | + yEnd--; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + dst = src.m()(Rect(xStart, yStart, xEnd-xStart, yEnd-yStart)); | ||
| 48 | + } | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +BR_REGISTER(Transform, CropBlackTransform) | ||
| 52 | + | ||
| 53 | +} // namespace br | ||
| 54 | + | ||
| 55 | +#include "cropblack.moc" |
openbr/plugins/imgproc/cropsquare.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Trim the image so the width and the height are the same size. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class CropSquareTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + const Mat &m = src; | ||
| 20 | + const int newSize = min(m.rows, m.cols); | ||
| 21 | + dst = Mat(m, Rect((m.cols-newSize)/2, (m.rows-newSize)/2, newSize, newSize)); | ||
| 22 | + } | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +BR_REGISTER(Transform, CropSquareTransform) | ||
| 26 | + | ||
| 27 | +} // namespace br | ||
| 28 | + | ||
| 29 | +#include "cropsquare.moc" |
openbr/plugins/imgproc/csdn.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace std; | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Meyers, E.; Wolf, L. | ||
| 12 | + * “Using biologically inspired features for face processing,” | ||
| 13 | + * Int. Journal of Computer Vision, vol. 76, no. 1, pp 93–104, 2008. | ||
| 14 | + * \author Scott Klum \cite sklum | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +class CSDNTransform : public UntrainableTransform | ||
| 18 | +{ | ||
| 19 | + Q_OBJECT | ||
| 20 | + | ||
| 21 | + Q_PROPERTY(float s READ get_s WRITE set_s RESET reset_s STORED false) | ||
| 22 | + BR_PROPERTY(int, s, 16) | ||
| 23 | + | ||
| 24 | + void project(const Template &src, Template &dst) const | ||
| 25 | + { | ||
| 26 | + if (src.m().channels() != 1) qFatal("Expected single channel source matrix."); | ||
| 27 | + | ||
| 28 | + const int nRows = src.m().rows; | ||
| 29 | + const int nCols = src.m().cols; | ||
| 30 | + | ||
| 31 | + Mat m; | ||
| 32 | + src.m().convertTo(m, CV_32FC1); | ||
| 33 | + | ||
| 34 | + const int surround = s/2; | ||
| 35 | + | ||
| 36 | + for ( int i = 0; i < nRows; i++ ) { | ||
| 37 | + for ( int j = 0; j < nCols; j++ ) { | ||
| 38 | + int width = min( j+surround, nCols ) - max( 0, j-surround ); | ||
| 39 | + int height = min( i+surround, nRows ) - max( 0, i-surround ); | ||
| 40 | + | ||
| 41 | + Rect_<int> ROI(max(0, j-surround), max(0, i-surround), width, height); | ||
| 42 | + | ||
| 43 | + Scalar_<float> avg = mean(m(ROI)); | ||
| 44 | + | ||
| 45 | + m.at<float>(i,j) = m.at<float>(i,j) - avg[0]; | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + dst = m; | ||
| 50 | + | ||
| 51 | + } | ||
| 52 | +}; | ||
| 53 | + | ||
| 54 | +BR_REGISTER(Transform, CSDNTransform) | ||
| 55 | + | ||
| 56 | +} // namespace br | ||
| 57 | + | ||
| 58 | +#include "csdn.moc" |
openbr/plugins/imgproc/cvtcolor.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Colorspace conversion. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class CvtColorTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_ENUMS(ColorSpace) | ||
| 19 | + Q_PROPERTY(ColorSpace colorSpace READ get_colorSpace WRITE set_colorSpace RESET reset_colorSpace STORED false) | ||
| 20 | + Q_PROPERTY(int channel READ get_channel WRITE set_channel RESET reset_channel STORED false) | ||
| 21 | + | ||
| 22 | +public: | ||
| 23 | + enum ColorSpace { Gray = CV_BGR2GRAY, | ||
| 24 | + RGBGray = CV_RGB2GRAY, | ||
| 25 | + HLS = CV_BGR2HLS, | ||
| 26 | + HSV = CV_BGR2HSV, | ||
| 27 | + Lab = CV_BGR2Lab, | ||
| 28 | + Luv = CV_BGR2Luv, | ||
| 29 | + RGB = CV_BGR2RGB, | ||
| 30 | + XYZ = CV_BGR2XYZ, | ||
| 31 | + YCrCb = CV_BGR2YCrCb, | ||
| 32 | + Color = CV_GRAY2BGR }; | ||
| 33 | + | ||
| 34 | +private: | ||
| 35 | + BR_PROPERTY(ColorSpace, colorSpace, Gray) | ||
| 36 | + BR_PROPERTY(int, channel, -1) | ||
| 37 | + | ||
| 38 | + void project(const Template &src, Template &dst) const | ||
| 39 | + { | ||
| 40 | + if (src.m().channels() > 1 || colorSpace == CV_GRAY2BGR) cvtColor(src, dst, colorSpace); | ||
| 41 | + else dst = src; | ||
| 42 | + | ||
| 43 | + if (channel != -1) { | ||
| 44 | + std::vector<Mat> mv; | ||
| 45 | + split(dst, mv); | ||
| 46 | + dst = mv[channel % (int)mv.size()]; | ||
| 47 | + } | ||
| 48 | + } | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +BR_REGISTER(Transform, CvtColorTransform) | ||
| 52 | + | ||
| 53 | +} // namespace br | ||
| 54 | + | ||
| 55 | +#include "cvtcolor.moc" |
openbr/plugins/imgproc/cvtfloat.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Convert to floating point format. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class CvtFloatTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + src.m().convertTo(dst, CV_32F); | ||
| 20 | + } | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +BR_REGISTER(Transform, CvtFloatTransform) | ||
| 24 | + | ||
| 25 | +} // namespace br | ||
| 26 | + | ||
| 27 | +#include "cvtfloat.moc" |
openbr/plugins/imgproc/cvtuchar.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +namespace br | ||
| 5 | +{ | ||
| 6 | + | ||
| 7 | +/*! | ||
| 8 | + * \ingroup transforms | ||
| 9 | + * \brief Convert to uchar format | ||
| 10 | + * \author Josh Klontz \cite jklontz | ||
| 11 | + */ | ||
| 12 | +class CvtUCharTransform : public UntrainableTransform | ||
| 13 | +{ | ||
| 14 | + Q_OBJECT | ||
| 15 | + | ||
| 16 | + void project(const Template &src, Template &dst) const | ||
| 17 | + { | ||
| 18 | + OpenCVUtils::cvtUChar(src, dst); | ||
| 19 | + } | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +BR_REGISTER(Transform, CvtUCharTransform) | ||
| 23 | + | ||
| 24 | +} // namespace br | ||
| 25 | + | ||
| 26 | +#include "cvtuchar.moc" |
openbr/plugins/denoising.cpp renamed to openbr/plugins/imgproc/denoising.cpp
| @@ -15,7 +15,8 @@ | @@ -15,7 +15,8 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/photo/photo.hpp> | 17 | #include <opencv2/photo/photo.hpp> |
| 18 | -#include "openbr_internal.h" | 18 | + |
| 19 | +#include <openbr/plugins/openbr_internal.h> | ||
| 19 | 20 | ||
| 20 | using namespace cv; | 21 | using namespace cv; |
| 21 | 22 |
openbr/plugins/imgproc/discardalpha.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Drop the alpha channel (if exists). | ||
| 13 | + * \author Austin Blanton \cite imaus10 | ||
| 14 | + */ | ||
| 15 | +class DiscardAlphaTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + if (src.m().channels() > 4 || src.m().channels() == 2) { | ||
| 22 | + dst.file.fte = true; | ||
| 23 | + return; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + dst = src; | ||
| 27 | + if (src.m().channels() == 4) { | ||
| 28 | + std::vector<Mat> mv; | ||
| 29 | + split(src, mv); | ||
| 30 | + mv.pop_back(); | ||
| 31 | + merge(mv, dst); | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +BR_REGISTER(Transform, DiscardAlphaTransform) | ||
| 37 | + | ||
| 38 | +} // namespace br | ||
| 39 | + | ||
| 40 | +#include "discardalpha.moc" |
openbr/plugins/imgproc/div.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Enforce a multiple of \em n columns. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class DivTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | ||
| 17 | + BR_PROPERTY(int, n, 1) | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + dst = Mat(src, Rect(0,0,n*(src.m().cols/n),src.m().rows)); | ||
| 22 | + } | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +BR_REGISTER(Transform, DivTransform) | ||
| 26 | + | ||
| 27 | +} // namespace br | ||
| 28 | + | ||
| 29 | +#include "div.moc" |
openbr/plugins/imgproc/dog.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Difference of gaussians | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class DoGTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(float sigma0 READ get_sigma0 WRITE set_sigma0 RESET reset_sigma0 STORED false) | ||
| 19 | + Q_PROPERTY(float sigma1 READ get_sigma1 WRITE set_sigma1 RESET reset_sigma1 STORED false) | ||
| 20 | + BR_PROPERTY(float, sigma0, 1) | ||
| 21 | + BR_PROPERTY(float, sigma1, 2) | ||
| 22 | + | ||
| 23 | + Size ksize0, ksize1; | ||
| 24 | + | ||
| 25 | + static Size getKernelSize(double sigma) | ||
| 26 | + { | ||
| 27 | + // Inverts OpenCV's conversion from kernel size to sigma: | ||
| 28 | + // sigma = ((ksize-1)*0.5 - 1)*0.3 + 0.8 | ||
| 29 | + // See documentation for cv::getGaussianKernel() | ||
| 30 | + int ksize = ((sigma - 0.8) / 0.3 + 1) * 2 + 1; | ||
| 31 | + if (ksize % 2 == 0) ksize++; | ||
| 32 | + return Size(ksize, ksize); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + void init() | ||
| 36 | + { | ||
| 37 | + ksize0 = getKernelSize(sigma0); | ||
| 38 | + ksize1 = getKernelSize(sigma1); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + void project(const Template &src, Template &dst) const | ||
| 42 | + { | ||
| 43 | + Mat g0, g1; | ||
| 44 | + GaussianBlur(src, g0, ksize0, 0); | ||
| 45 | + GaussianBlur(src, g1, ksize1, 0); | ||
| 46 | + subtract(g0, g1, dst); | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +BR_REGISTER(Transform, DoGTransform) | ||
| 51 | + | ||
| 52 | +} // namespace br | ||
| 53 | + | ||
| 54 | +#include "dog.moc" |
openbr/plugins/imgproc/ensurechannels.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Enforce the matrix has a certain number of channels by adding or removing channels. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class EnsureChannelsTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | ||
| 19 | + BR_PROPERTY(int, n, 1) | ||
| 20 | + | ||
| 21 | + void project(const Template &src, Template &dst) const | ||
| 22 | + { | ||
| 23 | + if (src.m().channels() == n) { | ||
| 24 | + dst = src; | ||
| 25 | + } else { | ||
| 26 | + std::vector<Mat> mv; | ||
| 27 | + split(src, mv); | ||
| 28 | + | ||
| 29 | + // Add extra channels | ||
| 30 | + while ((int)mv.size() < n) { | ||
| 31 | + for (int i=0; i<src.m().channels(); i++) { | ||
| 32 | + mv.push_back(mv[i]); | ||
| 33 | + if ((int)mv.size() == n) | ||
| 34 | + break; | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + // Remove extra channels | ||
| 39 | + while ((int)mv.size() > n) | ||
| 40 | + mv.pop_back(); | ||
| 41 | + | ||
| 42 | + merge(mv, dst); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | +}; | ||
| 46 | + | ||
| 47 | +BR_REGISTER(Transform, EnsureChannelsTransform) | ||
| 48 | + | ||
| 49 | +} // namespace br | ||
| 50 | + | ||
| 51 | +#include "ensurechannels.moc" |
openbr/plugins/imgproc/flood.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Fill black pixels with the specified color. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class FloodTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(int r READ get_r WRITE set_r RESET reset_r STORED false) | ||
| 17 | + Q_PROPERTY(int g READ get_g WRITE set_g RESET reset_g STORED false) | ||
| 18 | + Q_PROPERTY(int b READ get_b WRITE set_b RESET reset_b STORED false) | ||
| 19 | + Q_PROPERTY(bool all READ get_all WRITE set_all RESET reset_all STORED false) | ||
| 20 | + BR_PROPERTY(int, r, 0) | ||
| 21 | + BR_PROPERTY(int, g, 0) | ||
| 22 | + BR_PROPERTY(int, b, 0) | ||
| 23 | + BR_PROPERTY(bool, all, false) | ||
| 24 | + | ||
| 25 | + void project(const Template &src, Template &dst) const | ||
| 26 | + { | ||
| 27 | + dst = src.m().clone(); | ||
| 28 | + dst.m().setTo(Scalar(r, g, b), all ? Mat() : dst.m()==0); | ||
| 29 | + } | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +BR_REGISTER(Transform, FloodTransform) | ||
| 33 | + | ||
| 34 | +} // namespace br | ||
| 35 | + | ||
| 36 | +#include "flood.moc" |
openbr/plugins/imgproc/gamma.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Gamma correction | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class GammaTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(float gamma READ get_gamma WRITE set_gamma RESET reset_gamma STORED false) | ||
| 17 | + BR_PROPERTY(float, gamma, 0.2) | ||
| 18 | + | ||
| 19 | + Mat lut; | ||
| 20 | + | ||
| 21 | + void init() | ||
| 22 | + { | ||
| 23 | + lut.create(256, 1, CV_32FC1); | ||
| 24 | + if (gamma == 0) for (int i=0; i<256; i++) lut.at<float>(i,0) = log((float)i); | ||
| 25 | + else for (int i=0; i<256; i++) lut.at<float>(i,0) = pow(i, gamma); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + void project(const Template &src, Template &dst) const | ||
| 29 | + { | ||
| 30 | + if (src.m().depth() == CV_8U) LUT(src, lut, dst); | ||
| 31 | + else pow(src, gamma, dst); | ||
| 32 | + } | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +BR_REGISTER(Transform, GammaTransform) | ||
| 36 | + | ||
| 37 | +} // namespace br | ||
| 38 | + | ||
| 39 | +#include "gamma.moc" |
openbr/plugins/imgproc/gradient.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Computes magnitude and/or angle of image. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class GradientTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_ENUMS(Channel) | ||
| 19 | + Q_PROPERTY(Channel channel READ get_channel WRITE set_channel RESET reset_channel STORED false) | ||
| 20 | + | ||
| 21 | +public: | ||
| 22 | + enum Channel { Magnitude, Angle, MagnitudeAndAngle }; | ||
| 23 | + | ||
| 24 | +private: | ||
| 25 | + BR_PROPERTY(Channel, channel, Angle) | ||
| 26 | + | ||
| 27 | + void project(const Template &src, Template &dst) const | ||
| 28 | + { | ||
| 29 | + Mat dx, dy, magnitude, angle; | ||
| 30 | + Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); | ||
| 31 | + Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); | ||
| 32 | + cartToPolar(dx, dy, magnitude, angle, true); | ||
| 33 | + std::vector<Mat> mv; | ||
| 34 | + if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { | ||
| 35 | + const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); | ||
| 36 | + mv.push_back(magnitude / theoreticalMaxMagnitude); | ||
| 37 | + } | ||
| 38 | + if ((channel == Angle) || (channel == MagnitudeAndAngle)) | ||
| 39 | + mv.push_back(angle); | ||
| 40 | + Mat result; | ||
| 41 | + merge(mv, result); | ||
| 42 | + dst.append(result); | ||
| 43 | + } | ||
| 44 | +}; | ||
| 45 | + | ||
| 46 | +BR_REGISTER(Transform, GradientTransform) | ||
| 47 | + | ||
| 48 | +} // namespace br | ||
| 49 | + | ||
| 50 | +#include "gradient.moc" |
openbr/plugins/imgproc/hist.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Histograms the matrix | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class HistTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(float max READ get_max WRITE set_max RESET reset_max STORED false) | ||
| 19 | + Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min STORED false) | ||
| 20 | + Q_PROPERTY(int dims READ get_dims WRITE set_dims RESET reset_dims STORED false) | ||
| 21 | + BR_PROPERTY(float, max, 256) | ||
| 22 | + BR_PROPERTY(float, min, 0) | ||
| 23 | + BR_PROPERTY(int, dims, -1) | ||
| 24 | + | ||
| 25 | + void project(const Template &src, Template &dst) const | ||
| 26 | + { | ||
| 27 | + const int dims = this->dims == -1 ? max - min : this->dims; | ||
| 28 | + | ||
| 29 | + std::vector<Mat> mv; | ||
| 30 | + split(src, mv); | ||
| 31 | + Mat m(mv.size(), dims, CV_32FC1); | ||
| 32 | + | ||
| 33 | + for (size_t i=0; i<mv.size(); i++) { | ||
| 34 | + int channels[] = {0}; | ||
| 35 | + int histSize[] = {dims}; | ||
| 36 | + float range[] = {min, max}; | ||
| 37 | + const float* ranges[] = {range}; | ||
| 38 | + Mat hist, chan = mv[i]; | ||
| 39 | + // calcHist requires F or U, might as well convert just in case | ||
| 40 | + if (mv[i].depth() != CV_8U && mv[i].depth() != CV_32F) | ||
| 41 | + mv[i].convertTo(chan, CV_32F); | ||
| 42 | + calcHist(&chan, 1, channels, Mat(), hist, 1, histSize, ranges); | ||
| 43 | + memcpy(m.ptr(i), hist.ptr(), dims * sizeof(float)); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + dst += m; | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +BR_REGISTER(Transform, HistTransform) | ||
| 51 | + | ||
| 52 | +} // namespace br | ||
| 53 | + | ||
| 54 | +#include "hist.moc" |
openbr/plugins/hist.cpp renamed to openbr/plugins/imgproc/histbin.cpp
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 18 | -#include "openbr_internal.h" | ||
| 19 | -#include "openbr/core/common.h" | ||
| 20 | -#include "openbr/core/opencvutils.h" | 1 | +#include <openbr/plugins/openbr_internal.h> |
| 21 | 2 | ||
| 22 | using namespace cv; | 3 | using namespace cv; |
| 23 | 4 | ||
| @@ -26,52 +7,10 @@ namespace br | @@ -26,52 +7,10 @@ namespace br | ||
| 26 | 7 | ||
| 27 | /*! | 8 | /*! |
| 28 | * \ingroup transforms | 9 | * \ingroup transforms |
| 29 | - * \brief Histograms the matrix | ||
| 30 | - * \author Josh Klontz \cite jklontz | ||
| 31 | - */ | ||
| 32 | -class HistTransform : public UntrainableTransform | ||
| 33 | -{ | ||
| 34 | - Q_OBJECT | ||
| 35 | - Q_PROPERTY(float max READ get_max WRITE set_max RESET reset_max STORED false) | ||
| 36 | - Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min STORED false) | ||
| 37 | - Q_PROPERTY(int dims READ get_dims WRITE set_dims RESET reset_dims STORED false) | ||
| 38 | - BR_PROPERTY(float, max, 256) | ||
| 39 | - BR_PROPERTY(float, min, 0) | ||
| 40 | - BR_PROPERTY(int, dims, -1) | ||
| 41 | - | ||
| 42 | - void project(const Template &src, Template &dst) const | ||
| 43 | - { | ||
| 44 | - const int dims = this->dims == -1 ? max - min : this->dims; | ||
| 45 | - | ||
| 46 | - std::vector<Mat> mv; | ||
| 47 | - split(src, mv); | ||
| 48 | - Mat m(mv.size(), dims, CV_32FC1); | ||
| 49 | - | ||
| 50 | - for (size_t i=0; i<mv.size(); i++) { | ||
| 51 | - int channels[] = {0}; | ||
| 52 | - int histSize[] = {dims}; | ||
| 53 | - float range[] = {min, max}; | ||
| 54 | - const float* ranges[] = {range}; | ||
| 55 | - Mat hist, chan = mv[i]; | ||
| 56 | - // calcHist requires F or U, might as well convert just in case | ||
| 57 | - if (mv[i].depth() != CV_8U && mv[i].depth() != CV_32F) | ||
| 58 | - mv[i].convertTo(chan, CV_32F); | ||
| 59 | - calcHist(&chan, 1, channels, Mat(), hist, 1, histSize, ranges); | ||
| 60 | - memcpy(m.ptr(i), hist.ptr(), dims * sizeof(float)); | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - dst += m; | ||
| 64 | - } | ||
| 65 | -}; | ||
| 66 | - | ||
| 67 | -BR_REGISTER(Transform, HistTransform) | ||
| 68 | - | ||
| 69 | -/*! | ||
| 70 | - * \ingroup transforms | ||
| 71 | * \brief Quantizes the values into bins. | 10 | * \brief Quantizes the values into bins. |
| 72 | * \author Josh Klontz \cite jklontz | 11 | * \author Josh Klontz \cite jklontz |
| 73 | */ | 12 | */ |
| 74 | -class BinTransform : public UntrainableTransform | 13 | +class HistBinTransform : public UntrainableTransform |
| 75 | { | 14 | { |
| 76 | Q_OBJECT | 15 | Q_OBJECT |
| 77 | Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min STORED false) | 16 | Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min STORED false) |
| @@ -120,76 +59,8 @@ class BinTransform : public UntrainableTransform | @@ -120,76 +59,8 @@ class BinTransform : public UntrainableTransform | ||
| 120 | } | 59 | } |
| 121 | }; | 60 | }; |
| 122 | 61 | ||
| 123 | -BR_REGISTER(Transform, BinTransform) | ||
| 124 | - | ||
| 125 | -/*! | ||
| 126 | - * \ingroup transforms | ||
| 127 | - * \brief Converts each element to its rank-ordered value. | ||
| 128 | - * \author Josh Klontz \cite jklontz | ||
| 129 | - */ | ||
| 130 | -class RankTransform : public UntrainableTransform | ||
| 131 | -{ | ||
| 132 | - Q_OBJECT | ||
| 133 | - | ||
| 134 | - void project(const Template &src, Template &dst) const | ||
| 135 | - { | ||
| 136 | - const Mat &m = src; | ||
| 137 | - assert(m.channels() == 1); | ||
| 138 | - dst = Mat(m.rows, m.cols, CV_32FC1); | ||
| 139 | - typedef QPair<float,int> Tuple; | ||
| 140 | - QList<Tuple> tuples = Common::Sort(OpenCVUtils::matrixToVector<float>(m)); | ||
| 141 | - | ||
| 142 | - float prevValue = 0; | ||
| 143 | - int prevRank = 0; | ||
| 144 | - for (int i=0; i<tuples.size(); i++) { | ||
| 145 | - int rank; | ||
| 146 | - if (tuples[i].first == prevValue) rank = prevRank; | ||
| 147 | - else rank = i; | ||
| 148 | - dst.m().at<float>(tuples[i].second / m.cols, tuples[i].second % m.cols) = rank; | ||
| 149 | - prevValue = tuples[i].first; | ||
| 150 | - prevRank = rank; | ||
| 151 | - } | ||
| 152 | - } | ||
| 153 | -}; | ||
| 154 | - | ||
| 155 | -BR_REGISTER(Transform, RankTransform) | ||
| 156 | - | ||
| 157 | -/*! | ||
| 158 | - * \ingroup transforms | ||
| 159 | - * \brief An integral histogram | ||
| 160 | - * \author Josh Klontz \cite jklontz | ||
| 161 | - */ | ||
| 162 | -class IntegralHistTransform : public UntrainableTransform | ||
| 163 | -{ | ||
| 164 | - Q_OBJECT | ||
| 165 | - Q_PROPERTY(int bins READ get_bins WRITE set_bins RESET reset_bins STORED false) | ||
| 166 | - Q_PROPERTY(int radius READ get_radius WRITE set_radius RESET reset_radius STORED false) | ||
| 167 | - BR_PROPERTY(int, bins, 256) | ||
| 168 | - BR_PROPERTY(int, radius, 16) | ||
| 169 | - | ||
| 170 | - void project(const Template &src, Template &dst) const | ||
| 171 | - { | ||
| 172 | - const Mat &m = src.m(); | ||
| 173 | - if (m.type() != CV_8UC1) qFatal("IntegralHist requires 8UC1 matrices."); | ||
| 174 | - | ||
| 175 | - Mat integral(m.rows/radius+1, (m.cols/radius+1)*bins, CV_32SC1); | ||
| 176 | - integral.setTo(0); | ||
| 177 | - for (int i=1; i<integral.rows; i++) { | ||
| 178 | - for (int j=1; j<integral.cols; j+=bins) { | ||
| 179 | - for (int k=0; k<bins; k++) integral.at<qint32>(i, j+k) += integral.at<qint32>(i-1, j +k); | ||
| 180 | - for (int k=0; k<bins; k++) integral.at<qint32>(i, j+k) += integral.at<qint32>(i , j-bins+k); | ||
| 181 | - for (int k=0; k<bins; k++) integral.at<qint32>(i, j+k) -= integral.at<qint32>(i-1, j-bins+k); | ||
| 182 | - for (int k=0; k<radius; k++) | ||
| 183 | - for (int l=0; l<radius; l++) | ||
| 184 | - integral.at<qint32>(i, j+m.at<quint8>((i-1)*radius+k,(j/bins-1)*radius+l))++; | ||
| 185 | - } | ||
| 186 | - } | ||
| 187 | - dst = integral; | ||
| 188 | - } | ||
| 189 | -}; | ||
| 190 | - | ||
| 191 | -BR_REGISTER(Transform, IntegralHistTransform) | 62 | +BR_REGISTER(Transform, HistBinTransform) |
| 192 | 63 | ||
| 193 | } // namespace br | 64 | } // namespace br |
| 194 | 65 | ||
| 195 | -#include "hist.moc" | 66 | +#include "histbin.moc" |
openbr/plugins/imgproc/inpaint.cpp
0 → 100644
| 1 | +#include <opencv2/photo/photo.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Wraps OpenCV inpainting | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class InpaintTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_ENUMS(Method) | ||
| 19 | + Q_PROPERTY(int radius READ get_radius WRITE set_radius RESET reset_radius STORED false) | ||
| 20 | + Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) | ||
| 21 | + | ||
| 22 | +public: | ||
| 23 | + /*!< */ | ||
| 24 | + enum Method { NavierStokes = INPAINT_NS, | ||
| 25 | + Telea = INPAINT_TELEA }; | ||
| 26 | + | ||
| 27 | +private: | ||
| 28 | + BR_PROPERTY(int, radius, 1) | ||
| 29 | + BR_PROPERTY(Method, method, NavierStokes) | ||
| 30 | + Transform *cvtGray; | ||
| 31 | + | ||
| 32 | + void init() | ||
| 33 | + { | ||
| 34 | + cvtGray = make("Cvt(Gray)"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + void project(const Template &src, Template &dst) const | ||
| 38 | + { | ||
| 39 | + inpaint(src, (*cvtGray)(src)<5, dst, radius, method); | ||
| 40 | + } | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +} // namespace br | ||
| 44 | + | ||
| 45 | +#include "inpaint.moc" |
openbr/plugins/imgproc/integral.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Computes integral image. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class IntegralTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + cv::integral(src, dst); | ||
| 20 | + } | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +BR_REGISTER(Transform, IntegralTransform) | ||
| 24 | + | ||
| 25 | +} // namespace br | ||
| 26 | + | ||
| 27 | +#include "integral.moc" |
openbr/plugins/imgproc/integralhist.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief An integral histogram | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class IntegralHistTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(int bins READ get_bins WRITE set_bins RESET reset_bins STORED false) | ||
| 17 | + Q_PROPERTY(int radius READ get_radius WRITE set_radius RESET reset_radius STORED false) | ||
| 18 | + BR_PROPERTY(int, bins, 256) | ||
| 19 | + BR_PROPERTY(int, radius, 16) | ||
| 20 | + | ||
| 21 | + void project(const Template &src, Template &dst) const | ||
| 22 | + { | ||
| 23 | + const Mat &m = src.m(); | ||
| 24 | + if (m.type() != CV_8UC1) qFatal("IntegralHist requires 8UC1 matrices."); | ||
| 25 | + | ||
| 26 | + Mat integral(m.rows/radius+1, (m.cols/radius+1)*bins, CV_32SC1); | ||
| 27 | + integral.setTo(0); | ||
| 28 | + for (int i=1; i<integral.rows; i++) { | ||
| 29 | + for (int j=1; j<integral.cols; j+=bins) { | ||
| 30 | + for (int k=0; k<bins; k++) integral.at<qint32>(i, j+k) += integral.at<qint32>(i-1, j +k); | ||
| 31 | + for (int k=0; k<bins; k++) integral.at<qint32>(i, j+k) += integral.at<qint32>(i , j-bins+k); | ||
| 32 | + for (int k=0; k<bins; k++) integral.at<qint32>(i, j+k) -= integral.at<qint32>(i-1, j-bins+k); | ||
| 33 | + for (int k=0; k<radius; k++) | ||
| 34 | + for (int l=0; l<radius; l++) | ||
| 35 | + integral.at<qint32>(i, j+m.at<quint8>((i-1)*radius+k,(j/bins-1)*radius+l))++; | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + dst = integral; | ||
| 39 | + } | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +BR_REGISTER(Transform, IntegralHistTransform) | ||
| 43 | + | ||
| 44 | +} // namespace br | ||
| 45 | + | ||
| 46 | +#include "integralhist.moc" |
openbr/plugins/integral.cpp renamed to openbr/plugins/imgproc/integralsampler.cpp
| 1 | -#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | -#include <opencv2/imgproc/imgproc_c.h> | ||
| 3 | -#include <Eigen/Core> | ||
| 4 | -#include "openbr_internal.h" | 1 | +#include <Eigen/Dense> |
| 5 | 2 | ||
| 6 | -#include "openbr/core/opencvutils.h" | 3 | +#include <openbr/plugins/openbr_internal.h> |
| 7 | 4 | ||
| 8 | using namespace cv; | 5 | using namespace cv; |
| 9 | 6 | ||
| @@ -12,23 +9,6 @@ namespace br | @@ -12,23 +9,6 @@ namespace br | ||
| 12 | 9 | ||
| 13 | /*! | 10 | /*! |
| 14 | * \ingroup transforms | 11 | * \ingroup transforms |
| 15 | - * \brief Computes integral image. | ||
| 16 | - * \author Josh Klontz \cite jklontz | ||
| 17 | - */ | ||
| 18 | -class IntegralTransform : public UntrainableTransform | ||
| 19 | -{ | ||
| 20 | - Q_OBJECT | ||
| 21 | - | ||
| 22 | - void project(const Template &src, Template &dst) const | ||
| 23 | - { | ||
| 24 | - integral(src, dst); | ||
| 25 | - } | ||
| 26 | -}; | ||
| 27 | - | ||
| 28 | -BR_REGISTER(Transform, IntegralTransform) | ||
| 29 | - | ||
| 30 | -/*! | ||
| 31 | - * \ingroup transforms | ||
| 32 | * \brief Sliding window feature extraction from a multi-channel integral image. | 12 | * \brief Sliding window feature extraction from a multi-channel integral image. |
| 33 | * \author Josh Klontz \cite jklontz | 13 | * \author Josh Klontz \cite jklontz |
| 34 | */ | 14 | */ |
| @@ -121,254 +101,6 @@ class IntegralSamplerTransform : public UntrainableTransform | @@ -121,254 +101,6 @@ class IntegralSamplerTransform : public UntrainableTransform | ||
| 121 | 101 | ||
| 122 | BR_REGISTER(Transform, IntegralSamplerTransform) | 102 | BR_REGISTER(Transform, IntegralSamplerTransform) |
| 123 | 103 | ||
| 124 | -/*! | ||
| 125 | - * \ingroup transforms | ||
| 126 | - * \brief Construct template in a recursive decent manner. | ||
| 127 | - * \author Josh Klontz \cite jklontz | ||
| 128 | - */ | ||
| 129 | -class RecursiveIntegralSamplerTransform : public Transform | ||
| 130 | -{ | ||
| 131 | - Q_OBJECT | ||
| 132 | - Q_PROPERTY(int scales READ get_scales WRITE set_scales RESET reset_scales STORED false) | ||
| 133 | - Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) | ||
| 134 | - Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) | ||
| 135 | - Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform) | ||
| 136 | - BR_PROPERTY(int, scales, 6) | ||
| 137 | - BR_PROPERTY(float, scaleFactor, 2) | ||
| 138 | - BR_PROPERTY(int, minSize, 8) | ||
| 139 | - BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 140 | - | ||
| 141 | - Transform *subTransform; | ||
| 142 | - | ||
| 143 | - typedef Eigen::Map< const Eigen::Matrix<qint32,Eigen::Dynamic,1> > InputDescriptor; | ||
| 144 | - typedef Eigen::Map< Eigen::Matrix<float,Eigen::Dynamic,1> > OutputDescriptor; | ||
| 145 | - typedef Eigen::Map< const Eigen::Matrix<float,Eigen::Dynamic,1> > SecondOrderInputDescriptor; | ||
| 146 | - | ||
| 147 | - void init() | ||
| 148 | - { | ||
| 149 | - if (scales >= 2) { | ||
| 150 | - File subFile = file; | ||
| 151 | - subFile.set("scales", scales-1); | ||
| 152 | - subTransform = make(subFile.flat()); | ||
| 153 | - } else { | ||
| 154 | - subTransform = NULL; | ||
| 155 | - } | ||
| 156 | - } | ||
| 157 | - | ||
| 158 | - static void integralHistogram(const Mat &src, const int x, const int y, const int width, const int height, Mat &dst, int index) | ||
| 159 | - { | ||
| 160 | - const int channels = src.channels(); | ||
| 161 | - OutputDescriptor(dst.ptr<float>(index), channels, 1) = | ||
| 162 | - ( InputDescriptor(src.ptr<qint32>(y+height, x+width), channels, 1) | ||
| 163 | - - InputDescriptor(src.ptr<qint32>(y, x+width), channels, 1) | ||
| 164 | - - InputDescriptor(src.ptr<qint32>(y+height, x), channels, 1) | ||
| 165 | - + InputDescriptor(src.ptr<qint32>(y, x), channels, 1)).cast<float>()/(height*width); | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - void computeDescriptor(const Mat &src, Mat &dst) const | ||
| 169 | - { | ||
| 170 | - const int channels = src.channels(); | ||
| 171 | - const int rows = src.rows-1; // Integral images have an extra row and column | ||
| 172 | - const int columns = src.cols-1; | ||
| 173 | - | ||
| 174 | - Mat tmp(5, channels, CV_32FC1); | ||
| 175 | - integralHistogram(src, 0, 0, columns/2, rows/2, tmp, 0); | ||
| 176 | - integralHistogram(src, columns/2, 0, columns/2, rows/2, tmp, 1); | ||
| 177 | - integralHistogram(src, 0, rows/2, columns/2, rows/2, tmp, 2); | ||
| 178 | - integralHistogram(src, columns/2, rows/2, columns/2, rows/2, tmp, 3); | ||
| 179 | - integralHistogram(src, columns/4, rows/4, columns/2, rows/2, tmp, 4); | ||
| 180 | - const SecondOrderInputDescriptor a(tmp.ptr<float>(0), channels, 1); | ||
| 181 | - const SecondOrderInputDescriptor b(tmp.ptr<float>(1), channels, 1); | ||
| 182 | - const SecondOrderInputDescriptor c(tmp.ptr<float>(2), channels, 1); | ||
| 183 | - const SecondOrderInputDescriptor d(tmp.ptr<float>(3), channels, 1); | ||
| 184 | - const SecondOrderInputDescriptor e(tmp.ptr<float>(4), channels, 1); | ||
| 185 | - | ||
| 186 | - dst = Mat(5, channels, CV_32FC1); | ||
| 187 | - OutputDescriptor(dst.ptr<float>(0), channels, 1) = (a+b+c+d)/4.f; | ||
| 188 | - OutputDescriptor(dst.ptr<float>(1), channels, 1) = ((a+b+c+d)/4.f-e); | ||
| 189 | - OutputDescriptor(dst.ptr<float>(2), channels, 1) = ((a+b)-(c+d))/2.f; | ||
| 190 | - OutputDescriptor(dst.ptr<float>(3), channels, 1) = ((a+c)-(b+d))/2.f; | ||
| 191 | - OutputDescriptor(dst.ptr<float>(4), channels, 1) = ((a+d)-(b+c))/2.f; | ||
| 192 | - dst = dst.reshape(1, 1); | ||
| 193 | - } | ||
| 194 | - | ||
| 195 | - Template subdivide(const Template &src) const | ||
| 196 | - { | ||
| 197 | - // Integral images have an extra row and column | ||
| 198 | - int subWidth = (src.m().cols-1) / scaleFactor + 1; | ||
| 199 | - int subHeight = (src.m().rows-1) / scaleFactor + 1; | ||
| 200 | - return Template(src.file, QList<Mat>() << Mat(src, Rect(0, 0, subWidth, subHeight)) | ||
| 201 | - << Mat(src, Rect(src.m().cols-subWidth, 0, subWidth, subHeight)) | ||
| 202 | - << Mat(src, Rect(0, src.m().rows-subHeight, subWidth, subHeight)) | ||
| 203 | - << Mat(src, Rect(src.m().cols-subWidth, src.m().rows-subHeight, subWidth, subHeight))); | ||
| 204 | - } | ||
| 205 | - | ||
| 206 | - bool canSubdivide(const Template &t) const | ||
| 207 | - { | ||
| 208 | - // Integral images have an extra row and column | ||
| 209 | - const int subWidth = (t.m().cols-1) / scaleFactor; | ||
| 210 | - const int subHeight = (t.m().rows-1) / scaleFactor; | ||
| 211 | - return ((subWidth >= minSize) && (subHeight >= minSize)); | ||
| 212 | - } | ||
| 213 | - | ||
| 214 | - void train(const TemplateList &src) | ||
| 215 | - { | ||
| 216 | - if (src.first().m().depth() != CV_32S) | ||
| 217 | - qFatal("Expected CV_32S depth!"); | ||
| 218 | - | ||
| 219 | - if (subTransform != NULL) { | ||
| 220 | - TemplateList subSrc; subSrc.reserve(src.size()); | ||
| 221 | - foreach (const Template &t, src) | ||
| 222 | - if (canSubdivide(t)) | ||
| 223 | - subSrc.append(subdivide(t)); | ||
| 224 | - | ||
| 225 | - if (subSrc.isEmpty()) { | ||
| 226 | - delete subTransform; | ||
| 227 | - subTransform = NULL; | ||
| 228 | - } else { | ||
| 229 | - subTransform->train(subSrc); | ||
| 230 | - } | ||
| 231 | - } | ||
| 232 | - | ||
| 233 | - TemplateList dst; dst.reserve(src.size()); | ||
| 234 | - foreach (const Template &t, src) { | ||
| 235 | - Template u(t.file); | ||
| 236 | - computeDescriptor(t, u); | ||
| 237 | - dst.append(u); | ||
| 238 | - } | ||
| 239 | - transform->train(dst); | ||
| 240 | - } | ||
| 241 | - | ||
| 242 | - void project(const Template &src, Template &dst) const | ||
| 243 | - { | ||
| 244 | - computeDescriptor(src, dst); | ||
| 245 | - transform->project(dst, dst); | ||
| 246 | - | ||
| 247 | - if ((subTransform != NULL) && canSubdivide(src)) { | ||
| 248 | - Template subDst; | ||
| 249 | - subTransform->project(subdivide(src), subDst); | ||
| 250 | - dst.append(subDst); | ||
| 251 | - } | ||
| 252 | - } | ||
| 253 | - | ||
| 254 | - void store(QDataStream &stream) const | ||
| 255 | - { | ||
| 256 | - transform->store(stream); | ||
| 257 | - stream << (subTransform != NULL); | ||
| 258 | - if (subTransform != NULL) | ||
| 259 | - subTransform->store(stream); | ||
| 260 | - } | ||
| 261 | - | ||
| 262 | - void load(QDataStream &stream) | ||
| 263 | - { | ||
| 264 | - transform->load(stream); | ||
| 265 | - bool hasSubTransform; | ||
| 266 | - stream >> hasSubTransform; | ||
| 267 | - if (hasSubTransform) subTransform->load(stream); | ||
| 268 | - else { delete subTransform; subTransform = NULL; } | ||
| 269 | - } | ||
| 270 | -}; | ||
| 271 | - | ||
| 272 | -BR_REGISTER(Transform, RecursiveIntegralSamplerTransform) | ||
| 273 | - | ||
| 274 | -/*! | ||
| 275 | - * \ingroup transforms | ||
| 276 | - * \brief Computes magnitude and/or angle of image. | ||
| 277 | - * \author Josh Klontz \cite jklontz | ||
| 278 | - */ | ||
| 279 | -class GradientTransform : public UntrainableTransform | ||
| 280 | -{ | ||
| 281 | - Q_OBJECT | ||
| 282 | - Q_ENUMS(Channel) | ||
| 283 | - Q_PROPERTY(Channel channel READ get_channel WRITE set_channel RESET reset_channel STORED false) | ||
| 284 | - | ||
| 285 | -public: | ||
| 286 | - enum Channel { Magnitude, Angle, MagnitudeAndAngle }; | ||
| 287 | - | ||
| 288 | -private: | ||
| 289 | - BR_PROPERTY(Channel, channel, Angle) | ||
| 290 | - | ||
| 291 | - void project(const Template &src, Template &dst) const | ||
| 292 | - { | ||
| 293 | - Mat dx, dy, magnitude, angle; | ||
| 294 | - Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); | ||
| 295 | - Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); | ||
| 296 | - cartToPolar(dx, dy, magnitude, angle, true); | ||
| 297 | - std::vector<Mat> mv; | ||
| 298 | - if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { | ||
| 299 | - const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); | ||
| 300 | - mv.push_back(magnitude / theoreticalMaxMagnitude); | ||
| 301 | - } | ||
| 302 | - if ((channel == Angle) || (channel == MagnitudeAndAngle)) | ||
| 303 | - mv.push_back(angle); | ||
| 304 | - Mat result; | ||
| 305 | - merge(mv, result); | ||
| 306 | - dst.append(result); | ||
| 307 | - } | ||
| 308 | -}; | ||
| 309 | - | ||
| 310 | -BR_REGISTER(Transform, GradientTransform) | ||
| 311 | - | ||
| 312 | -/*! | ||
| 313 | - * \ingroup transforms | ||
| 314 | - * \brief Projects each row based on a computed word. | ||
| 315 | - * \author Josh Klontz \cite jklontz | ||
| 316 | - */ | ||
| 317 | -class WordWiseTransform : public Transform | ||
| 318 | -{ | ||
| 319 | - Q_OBJECT | ||
| 320 | - Q_PROPERTY(br::Transform* getWords READ get_getWords WRITE set_getWords RESET reset_getWords) | ||
| 321 | - Q_PROPERTY(br::Transform* byWord READ get_byWord WRITE set_byWord RESET reset_byWord) | ||
| 322 | - Q_PROPERTY(int numWords READ get_numWords WRITE set_numWords RESET reset_numWords) | ||
| 323 | - BR_PROPERTY(br::Transform*, getWords, NULL) | ||
| 324 | - BR_PROPERTY(br::Transform*, byWord, NULL) | ||
| 325 | - BR_PROPERTY(int, numWords, 0) | ||
| 326 | - | ||
| 327 | - void train(const TemplateList &data) | ||
| 328 | - { | ||
| 329 | - getWords->train(data); | ||
| 330 | - TemplateList bins; | ||
| 331 | - getWords->project(data, bins); | ||
| 332 | - | ||
| 333 | - numWords = 0; | ||
| 334 | - foreach (const Template &t, bins) { | ||
| 335 | - double minVal, maxVal; | ||
| 336 | - minMaxLoc(t, &minVal, &maxVal); | ||
| 337 | - numWords = max(numWords, int(maxVal)+1); | ||
| 338 | - } | ||
| 339 | - | ||
| 340 | - TemplateList reworded; reworded.reserve(data.size()); | ||
| 341 | - foreach (const Template &t, data) | ||
| 342 | - reworded.append(reword(t)); | ||
| 343 | - byWord->train(reworded); | ||
| 344 | - } | ||
| 345 | - | ||
| 346 | - void project(const Template &src, Template &dst) const | ||
| 347 | - { | ||
| 348 | - byWord->project(reword(src), dst); | ||
| 349 | - } | ||
| 350 | - | ||
| 351 | - Template reword(const Template &src) const | ||
| 352 | - { | ||
| 353 | - Template words; | ||
| 354 | - getWords->project(src, words); | ||
| 355 | - QVector<int> wordCounts(numWords, 0); | ||
| 356 | - for (int i=0; i<words.m().rows; i++) | ||
| 357 | - wordCounts[words.m().at<uchar>(i,0)]++; | ||
| 358 | - Template reworded(src.file); reworded.reserve(numWords); | ||
| 359 | - for (int i=0; i<numWords; i++) | ||
| 360 | - reworded.append(Mat(wordCounts[i], src.m().cols, src.m().type())); | ||
| 361 | - QVector<int> indicies(numWords, 0); | ||
| 362 | - for (int i=0; i<src.m().rows; i++) { | ||
| 363 | - const int word = words.m().at<uchar>(i,0); | ||
| 364 | - src.m().row(i).copyTo(reworded[word].row(indicies[word]++)); | ||
| 365 | - } | ||
| 366 | - return reworded; | ||
| 367 | - } | ||
| 368 | -}; | ||
| 369 | - | ||
| 370 | -BR_REGISTER(Transform, WordWiseTransform) | ||
| 371 | - | ||
| 372 | } // namespace br | 104 | } // namespace br |
| 373 | 105 | ||
| 374 | -#include "integral.moc" | 106 | +#include "integralsampler.moc" |
openbr/plugins/imgproc/limitsize.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Limit the size of the template | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class LimitSizeTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(int max READ get_max WRITE set_max RESET reset_max STORED false) | ||
| 19 | + BR_PROPERTY(int, max, -1) | ||
| 20 | + | ||
| 21 | + void project(const Template &src, Template &dst) const | ||
| 22 | + { | ||
| 23 | + const Mat &m = src; | ||
| 24 | + if (m.rows > m.cols) | ||
| 25 | + if (m.rows > max) resize(m, dst, Size(std::max(1, m.cols * max / m.rows), max)); | ||
| 26 | + else dst = m; | ||
| 27 | + else | ||
| 28 | + if (m.cols > max) resize(m, dst, Size(max, std::max(1, m.rows * max / m.cols))); | ||
| 29 | + else dst = m; | ||
| 30 | + } | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +BR_REGISTER(Transform, LimitSizeTransform) | ||
| 34 | + | ||
| 35 | +} // namespace br | ||
| 36 | + | ||
| 37 | +#include "limitsize.moc" |
openbr/plugins/imgproc/madd.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief dst = a*src+b | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class MAddTransform : public UntrainableTransform | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(double a READ get_a WRITE set_a RESET reset_a STORED false) | ||
| 15 | + Q_PROPERTY(double b READ get_b WRITE set_b RESET reset_b STORED false) | ||
| 16 | + BR_PROPERTY(double, a, 1) | ||
| 17 | + BR_PROPERTY(double, b, 0) | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + src.m().convertTo(dst.m(), src.m().depth(), a, b); | ||
| 22 | + } | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +BR_REGISTER(Transform, MAddTransform) | ||
| 26 | + | ||
| 27 | +} // namespace br | ||
| 28 | + | ||
| 29 | +#include "madd.moc" |
openbr/plugins/imgproc/mean.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Computes the mean of a set of templates. | ||
| 11 | + * \note Suitable for visualization only as it sets every projected template to the mean template. | ||
| 12 | + * \author Scott Klum \cite sklum | ||
| 13 | + */ | ||
| 14 | +class MeanTransform : public Transform | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + | ||
| 18 | + Mat mean; | ||
| 19 | + | ||
| 20 | + void train(const TemplateList &data) | ||
| 21 | + { | ||
| 22 | + mean = Mat::zeros(data[0].m().rows,data[0].m().cols,CV_32F); | ||
| 23 | + | ||
| 24 | + for (int i = 0; i < data.size(); i++) { | ||
| 25 | + Mat converted; | ||
| 26 | + data[i].m().convertTo(converted, CV_32F); | ||
| 27 | + mean += converted; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + mean /= data.size(); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + void project(const Template &src, Template &dst) const | ||
| 34 | + { | ||
| 35 | + dst = src; | ||
| 36 | + dst.m() = mean; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | +}; | ||
| 40 | + | ||
| 41 | +BR_REGISTER(Transform, MeanTransform) | ||
| 42 | + | ||
| 43 | +} // namespace br | ||
| 44 | + | ||
| 45 | +#include "mean.moc" |
openbr/plugins/imgproc/meanfill.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Fill 0 pixels with the mean of non-0 pixels. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class MeanFillTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + dst = src.m().clone(); | ||
| 20 | + dst.m().setTo(mean(dst, dst.m()!=0), dst.m()==0); | ||
| 21 | + } | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +BR_REGISTER(Transform, MeanFillTransform) | ||
| 25 | + | ||
| 26 | +} // namespace br | ||
| 27 | + | ||
| 28 | +#include "meanfill.moc" |
openbr/plugins/imgproc/pow.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Raise each element to the specified power. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class PowTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(float power READ get_power WRITE set_power RESET reset_power STORED false) | ||
| 17 | + Q_PROPERTY(bool preserveSign READ get_preserveSign WRITE set_preserveSign RESET reset_preserveSign STORED false) | ||
| 18 | + BR_PROPERTY(float, power, 2) | ||
| 19 | + BR_PROPERTY(bool, preserveSign, false) | ||
| 20 | + | ||
| 21 | + void project(const Template &src, Template &dst) const | ||
| 22 | + { | ||
| 23 | + pow(preserveSign ? abs(src) : src.m(), power, dst); | ||
| 24 | + if (preserveSign) subtract(Scalar::all(0), dst, dst, src.m() < 0); | ||
| 25 | + } | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +BR_REGISTER(Transform, PowTransform) | ||
| 29 | + | ||
| 30 | +} // namespace br | ||
| 31 | + | ||
| 32 | +#include "pow.moc" |
openbr/plugins/imgproc/rank.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/common.h> | ||
| 3 | +#include <openbr/core/opencvutils.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Converts each element to its rank-ordered value. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class RankTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + const Mat &m = src; | ||
| 22 | + assert(m.channels() == 1); | ||
| 23 | + dst = Mat(m.rows, m.cols, CV_32FC1); | ||
| 24 | + typedef QPair<float,int> Tuple; | ||
| 25 | + QList<Tuple> tuples = Common::Sort(OpenCVUtils::matrixToVector<float>(m)); | ||
| 26 | + | ||
| 27 | + float prevValue = 0; | ||
| 28 | + int prevRank = 0; | ||
| 29 | + for (int i=0; i<tuples.size(); i++) { | ||
| 30 | + int rank; | ||
| 31 | + if (tuples[i].first == prevValue) rank = prevRank; | ||
| 32 | + else rank = i; | ||
| 33 | + dst.m().at<float>(tuples[i].second / m.cols, tuples[i].second % m.cols) = rank; | ||
| 34 | + prevValue = tuples[i].first; | ||
| 35 | + prevRank = rank; | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | +}; | ||
| 39 | + | ||
| 40 | +BR_REGISTER(Transform, RankTransform) | ||
| 41 | + | ||
| 42 | +} // namespace br | ||
| 43 | + | ||
| 44 | +#include "rank.moc" |
openbr/plugins/imgproc/recursiveintegralsampler.cpp
0 → 100644
| 1 | +#include <Eigen/Dense> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Construct template in a recursive decent manner. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class RecursiveIntegralSamplerTransform : public Transform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(int scales READ get_scales WRITE set_scales RESET reset_scales STORED false) | ||
| 19 | + Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) | ||
| 20 | + Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) | ||
| 21 | + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform) | ||
| 22 | + BR_PROPERTY(int, scales, 6) | ||
| 23 | + BR_PROPERTY(float, scaleFactor, 2) | ||
| 24 | + BR_PROPERTY(int, minSize, 8) | ||
| 25 | + BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 26 | + | ||
| 27 | + Transform *subTransform; | ||
| 28 | + | ||
| 29 | + typedef Eigen::Map< const Eigen::Matrix<qint32,Eigen::Dynamic,1> > InputDescriptor; | ||
| 30 | + typedef Eigen::Map< Eigen::Matrix<float,Eigen::Dynamic,1> > OutputDescriptor; | ||
| 31 | + typedef Eigen::Map< const Eigen::Matrix<float,Eigen::Dynamic,1> > SecondOrderInputDescriptor; | ||
| 32 | + | ||
| 33 | + void init() | ||
| 34 | + { | ||
| 35 | + if (scales >= 2) { | ||
| 36 | + File subFile = file; | ||
| 37 | + subFile.set("scales", scales-1); | ||
| 38 | + subTransform = make(subFile.flat()); | ||
| 39 | + } else { | ||
| 40 | + subTransform = NULL; | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + static void integralHistogram(const Mat &src, const int x, const int y, const int width, const int height, Mat &dst, int index) | ||
| 45 | + { | ||
| 46 | + const int channels = src.channels(); | ||
| 47 | + OutputDescriptor(dst.ptr<float>(index), channels, 1) = | ||
| 48 | + ( InputDescriptor(src.ptr<qint32>(y+height, x+width), channels, 1) | ||
| 49 | + - InputDescriptor(src.ptr<qint32>(y, x+width), channels, 1) | ||
| 50 | + - InputDescriptor(src.ptr<qint32>(y+height, x), channels, 1) | ||
| 51 | + + InputDescriptor(src.ptr<qint32>(y, x), channels, 1)).cast<float>()/(height*width); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + void computeDescriptor(const Mat &src, Mat &dst) const | ||
| 55 | + { | ||
| 56 | + const int channels = src.channels(); | ||
| 57 | + const int rows = src.rows-1; // Integral images have an extra row and column | ||
| 58 | + const int columns = src.cols-1; | ||
| 59 | + | ||
| 60 | + Mat tmp(5, channels, CV_32FC1); | ||
| 61 | + integralHistogram(src, 0, 0, columns/2, rows/2, tmp, 0); | ||
| 62 | + integralHistogram(src, columns/2, 0, columns/2, rows/2, tmp, 1); | ||
| 63 | + integralHistogram(src, 0, rows/2, columns/2, rows/2, tmp, 2); | ||
| 64 | + integralHistogram(src, columns/2, rows/2, columns/2, rows/2, tmp, 3); | ||
| 65 | + integralHistogram(src, columns/4, rows/4, columns/2, rows/2, tmp, 4); | ||
| 66 | + const SecondOrderInputDescriptor a(tmp.ptr<float>(0), channels, 1); | ||
| 67 | + const SecondOrderInputDescriptor b(tmp.ptr<float>(1), channels, 1); | ||
| 68 | + const SecondOrderInputDescriptor c(tmp.ptr<float>(2), channels, 1); | ||
| 69 | + const SecondOrderInputDescriptor d(tmp.ptr<float>(3), channels, 1); | ||
| 70 | + const SecondOrderInputDescriptor e(tmp.ptr<float>(4), channels, 1); | ||
| 71 | + | ||
| 72 | + dst = Mat(5, channels, CV_32FC1); | ||
| 73 | + OutputDescriptor(dst.ptr<float>(0), channels, 1) = (a+b+c+d)/4.f; | ||
| 74 | + OutputDescriptor(dst.ptr<float>(1), channels, 1) = ((a+b+c+d)/4.f-e); | ||
| 75 | + OutputDescriptor(dst.ptr<float>(2), channels, 1) = ((a+b)-(c+d))/2.f; | ||
| 76 | + OutputDescriptor(dst.ptr<float>(3), channels, 1) = ((a+c)-(b+d))/2.f; | ||
| 77 | + OutputDescriptor(dst.ptr<float>(4), channels, 1) = ((a+d)-(b+c))/2.f; | ||
| 78 | + dst = dst.reshape(1, 1); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + Template subdivide(const Template &src) const | ||
| 82 | + { | ||
| 83 | + // Integral images have an extra row and column | ||
| 84 | + int subWidth = (src.m().cols-1) / scaleFactor + 1; | ||
| 85 | + int subHeight = (src.m().rows-1) / scaleFactor + 1; | ||
| 86 | + return Template(src.file, QList<Mat>() << Mat(src, Rect(0, 0, subWidth, subHeight)) | ||
| 87 | + << Mat(src, Rect(src.m().cols-subWidth, 0, subWidth, subHeight)) | ||
| 88 | + << Mat(src, Rect(0, src.m().rows-subHeight, subWidth, subHeight)) | ||
| 89 | + << Mat(src, Rect(src.m().cols-subWidth, src.m().rows-subHeight, subWidth, subHeight))); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + bool canSubdivide(const Template &t) const | ||
| 93 | + { | ||
| 94 | + // Integral images have an extra row and column | ||
| 95 | + const int subWidth = (t.m().cols-1) / scaleFactor; | ||
| 96 | + const int subHeight = (t.m().rows-1) / scaleFactor; | ||
| 97 | + return ((subWidth >= minSize) && (subHeight >= minSize)); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + void train(const TemplateList &src) | ||
| 101 | + { | ||
| 102 | + if (src.first().m().depth() != CV_32S) | ||
| 103 | + qFatal("Expected CV_32S depth!"); | ||
| 104 | + | ||
| 105 | + if (subTransform != NULL) { | ||
| 106 | + TemplateList subSrc; subSrc.reserve(src.size()); | ||
| 107 | + foreach (const Template &t, src) | ||
| 108 | + if (canSubdivide(t)) | ||
| 109 | + subSrc.append(subdivide(t)); | ||
| 110 | + | ||
| 111 | + if (subSrc.isEmpty()) { | ||
| 112 | + delete subTransform; | ||
| 113 | + subTransform = NULL; | ||
| 114 | + } else { | ||
| 115 | + subTransform->train(subSrc); | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + TemplateList dst; dst.reserve(src.size()); | ||
| 120 | + foreach (const Template &t, src) { | ||
| 121 | + Template u(t.file); | ||
| 122 | + computeDescriptor(t, u); | ||
| 123 | + dst.append(u); | ||
| 124 | + } | ||
| 125 | + transform->train(dst); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + void project(const Template &src, Template &dst) const | ||
| 129 | + { | ||
| 130 | + computeDescriptor(src, dst); | ||
| 131 | + transform->project(dst, dst); | ||
| 132 | + | ||
| 133 | + if ((subTransform != NULL) && canSubdivide(src)) { | ||
| 134 | + Template subDst; | ||
| 135 | + subTransform->project(subdivide(src), subDst); | ||
| 136 | + dst.append(subDst); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + void store(QDataStream &stream) const | ||
| 141 | + { | ||
| 142 | + transform->store(stream); | ||
| 143 | + stream << (subTransform != NULL); | ||
| 144 | + if (subTransform != NULL) | ||
| 145 | + subTransform->store(stream); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + void load(QDataStream &stream) | ||
| 149 | + { | ||
| 150 | + transform->load(stream); | ||
| 151 | + bool hasSubTransform; | ||
| 152 | + stream >> hasSubTransform; | ||
| 153 | + if (hasSubTransform) subTransform->load(stream); | ||
| 154 | + else { delete subTransform; subTransform = NULL; } | ||
| 155 | + } | ||
| 156 | +}; | ||
| 157 | + | ||
| 158 | +BR_REGISTER(Transform, RecursiveIntegralSamplerTransform) | ||
| 159 | + | ||
| 160 | +} // namespace br | ||
| 161 | + | ||
| 162 | +#include "recursiveintegralsampler.moc" |
openbr/plugins/imgproc/resize.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Resize the template | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + * \note Method: Area should be used for shrinking an image, Cubic for slow but accurate enlargment, Bilin for fast enlargement. | ||
| 15 | + * \param preserveAspect If true, the image will be sized per specification, but | ||
| 16 | + * a border will be applied to preserve aspect ratio. | ||
| 17 | + */ | ||
| 18 | +class ResizeTransform : public UntrainableTransform | ||
| 19 | +{ | ||
| 20 | + Q_OBJECT | ||
| 21 | + Q_ENUMS(Method) | ||
| 22 | + | ||
| 23 | +public: | ||
| 24 | + /*!< */ | ||
| 25 | + enum Method { Near = INTER_NEAREST, | ||
| 26 | + Area = INTER_AREA, | ||
| 27 | + Bilin = INTER_LINEAR, | ||
| 28 | + Cubic = INTER_CUBIC, | ||
| 29 | + Lanczo = INTER_LANCZOS4}; | ||
| 30 | + | ||
| 31 | +private: | ||
| 32 | + Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | ||
| 33 | + Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | ||
| 34 | + Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) | ||
| 35 | + Q_PROPERTY(bool preserveAspect READ get_preserveAspect WRITE set_preserveAspect RESET reset_preserveAspect STORED false) | ||
| 36 | + BR_PROPERTY(int, rows, -1) | ||
| 37 | + BR_PROPERTY(int, columns, -1) | ||
| 38 | + BR_PROPERTY(Method, method, Bilin) | ||
| 39 | + BR_PROPERTY(bool, preserveAspect, false) | ||
| 40 | + | ||
| 41 | + void project(const Template &src, Template &dst) const | ||
| 42 | + { | ||
| 43 | + if (!preserveAspect) | ||
| 44 | + resize(src, dst, Size((columns == -1) ? src.m().cols*rows/src.m().rows : columns, rows), 0, 0, method); | ||
| 45 | + else { | ||
| 46 | + float inRatio = (float) src.m().rows / src.m().cols; | ||
| 47 | + float outRatio = (float) rows / columns; | ||
| 48 | + dst = Mat::zeros(rows, columns, src.m().type()); | ||
| 49 | + if (outRatio > inRatio) { | ||
| 50 | + float heightAR = src.m().rows * inRatio / outRatio; | ||
| 51 | + Mat buffer; | ||
| 52 | + resize(src, buffer, Size(columns, heightAR), 0, 0, method); | ||
| 53 | + buffer.copyTo(dst.m()(Rect(0, (rows - heightAR) / 2, columns, heightAR))); | ||
| 54 | + } else { | ||
| 55 | + float widthAR = src.m().cols / inRatio * outRatio; | ||
| 56 | + Mat buffer; | ||
| 57 | + resize(src, buffer, Size(widthAR, rows), 0, 0, method); | ||
| 58 | + buffer.copyTo(dst.m()(Rect((columns - widthAR) / 2, 0, widthAR, rows))); | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | +}; | ||
| 63 | + | ||
| 64 | +BR_REGISTER(Transform, ResizeTransform) | ||
| 65 | + | ||
| 66 | +} // namespace br | ||
| 67 | + | ||
| 68 | +#include "resize.moc" |
openbr/plugins/imgproc/rg.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Normalized RG color space. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class RGTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + if (src.m().type() != CV_8UC3) | ||
| 20 | + qFatal("Expected CV_8UC3 images."); | ||
| 21 | + | ||
| 22 | + const Mat &m = src.m(); | ||
| 23 | + Mat R(m.size(), CV_8UC1); // R / (R+G+B) | ||
| 24 | + Mat G(m.size(), CV_8UC1); // G / (R+G+B) | ||
| 25 | + | ||
| 26 | + for (int i=0; i<m.rows; i++) | ||
| 27 | + for (int j=0; j<m.cols; j++) { | ||
| 28 | + Vec3b v = m.at<Vec3b>(i,j); | ||
| 29 | + const int b = v[0]; | ||
| 30 | + const int g = v[1]; | ||
| 31 | + const int r = v[2]; | ||
| 32 | + const int sum = b + g + r; | ||
| 33 | + if (sum > 0) { | ||
| 34 | + R.at<uchar>(i, j) = saturate_cast<uchar>(255.0*r/(r+g+b)); | ||
| 35 | + G.at<uchar>(i, j) = saturate_cast<uchar>(255.0*g/(r+g+b)); | ||
| 36 | + } else { | ||
| 37 | + R.at<uchar>(i, j) = 0; | ||
| 38 | + G.at<uchar>(i, j) = 0; | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + dst.append(R); | ||
| 43 | + dst.append(G); | ||
| 44 | + } | ||
| 45 | +}; | ||
| 46 | + | ||
| 47 | +BR_REGISTER(Transform, RGTransform) | ||
| 48 | + | ||
| 49 | +} // namespace br | ||
| 50 | + | ||
| 51 | +#include "rg.moc" |
openbr/plugins/imgproc/roi.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Crops the rectangular regions of interest. | ||
| 12 | + * \author Josh Klontz \cite jklontz | ||
| 13 | + */ | ||
| 14 | +class ROITransform : public UntrainableTransform | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | ||
| 18 | + BR_PROPERTY(QString, propName, "") | ||
| 19 | + | ||
| 20 | + void project(const Template &src, Template &dst) const | ||
| 21 | + { | ||
| 22 | + if (!propName.isEmpty()) { | ||
| 23 | + QRectF rect = src.file.get<QRectF>(propName); | ||
| 24 | + dst += src.m()(OpenCVUtils::toRect(rect)); | ||
| 25 | + } else if (!src.file.rects().empty()) { | ||
| 26 | + foreach (const QRectF &rect, src.file.rects()) | ||
| 27 | + dst += src.m()(OpenCVUtils::toRect(rect)); | ||
| 28 | + } else if (src.file.contains(QStringList() << "X" << "Y" << "Width" << "Height")) { | ||
| 29 | + dst += src.m()(Rect(src.file.get<int>("X"), | ||
| 30 | + src.file.get<int>("Y"), | ||
| 31 | + src.file.get<int>("Width"), | ||
| 32 | + src.file.get<int>("Height"))); | ||
| 33 | + } else { | ||
| 34 | + dst = src; | ||
| 35 | + if (Globals->verbose) | ||
| 36 | + qWarning("No rects present in file."); | ||
| 37 | + } | ||
| 38 | + dst.file.clearRects(); | ||
| 39 | + } | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +BR_REGISTER(Transform, ROITransform) | ||
| 43 | + | ||
| 44 | +} // namespace br | ||
| 45 | + | ||
| 46 | +#include "roi.moc" |
openbr/plugins/imgproc/roifrompoints.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Crops the rectangular regions of interest from given points and sizes. | ||
| 11 | + * \author Austin Blanton \cite imaus10 | ||
| 12 | + */ | ||
| 13 | +class ROIFromPtsTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | ||
| 17 | + Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | ||
| 18 | + BR_PROPERTY(int, width, 1) | ||
| 19 | + BR_PROPERTY(int, height, 1) | ||
| 20 | + | ||
| 21 | + void project(const Template &src, Template &dst) const | ||
| 22 | + { | ||
| 23 | + foreach (const QPointF &pt, src.file.points()) { | ||
| 24 | + int x = pt.x() - (width/2); | ||
| 25 | + int y = pt.y() - (height/2); | ||
| 26 | + dst += src.m()(Rect(x, y, width, height)); | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +BR_REGISTER(Transform, ROIFromPtsTransform) | ||
| 32 | + | ||
| 33 | +} // namespace br | ||
| 34 | + | ||
| 35 | +#include "roifrompoints.moc" |
openbr/plugins/imgproc/scale.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Scales using the given factor | ||
| 13 | + * \author Scott Klum \cite sklum | ||
| 14 | + */ | ||
| 15 | +class ScaleTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + | ||
| 19 | + Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) | ||
| 20 | + BR_PROPERTY(float, scaleFactor, 1.) | ||
| 21 | + | ||
| 22 | + void project(const Template &src, Template &dst) const | ||
| 23 | + { | ||
| 24 | + resize(src, dst, Size(src.m().cols*scaleFactor,src.m().rows*scaleFactor)); | ||
| 25 | + } | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +BR_REGISTER(Transform, ScaleTransform) | ||
| 29 | + | ||
| 30 | +} // namespace br | ||
| 31 | + | ||
| 32 | +#include "scale.moc" |
openbr/plugins/imgproc/splitchannels.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Split a multi-channel matrix into several single-channel matrices. | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class SplitChannelsTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + std::vector<Mat> mv; | ||
| 22 | + split(src, mv); | ||
| 23 | + foreach (const Mat &m, mv) | ||
| 24 | + dst += m; | ||
| 25 | + } | ||
| 26 | +}; | ||
| 27 | + | ||
| 28 | +BR_REGISTER(Transform, SplitChannelsTransform) | ||
| 29 | + | ||
| 30 | +} // namespace br | ||
| 31 | + | ||
| 32 | +#include "splitchannels.moc" |
openbr/plugins/imgproc/subdivide.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Divide the matrix into 4 smaller matricies of equal size. | ||
| 11 | + * \author Josh Klontz \cite jklontz | ||
| 12 | + */ | ||
| 13 | +class SubdivideTransform : public UntrainableTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + const Mat &m = src; | ||
| 20 | + const int subrows = m.rows/2; | ||
| 21 | + const int subcolumns = m.cols/2; | ||
| 22 | + dst.append(Mat(m,Rect(0, 0, subcolumns, subrows)).clone()); | ||
| 23 | + dst.append(Mat(m,Rect(subcolumns, 0, subcolumns, subrows)).clone()); | ||
| 24 | + dst.append(Mat(m,Rect(0, subrows, subcolumns, subrows)).clone()); | ||
| 25 | + dst.append(Mat(m,Rect(subcolumns, subrows, subcolumns, subrows)).clone()); | ||
| 26 | + } | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +BR_REGISTER(Transform, SubdivideTransform) | ||
| 30 | + | ||
| 31 | +} // namespace br | ||
| 32 | + | ||
| 33 | +#include "subdivide.moc" |
openbr/plugins/io/write.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | + | ||
| 4 | +using namespace cv; | ||
| 5 | + | ||
| 6 | +namespace br | ||
| 7 | +{ | ||
| 8 | + | ||
| 9 | +/*! | ||
| 10 | + * \ingroup transforms | ||
| 11 | + * \brief Write all mats to disk as images. | ||
| 12 | + * \author Brendan Klare \cite bklare | ||
| 13 | + */ | ||
| 14 | +class WriteTransform : public TimeVaryingTransform | ||
| 15 | +{ | ||
| 16 | + Q_OBJECT | ||
| 17 | + Q_PROPERTY(QString outputDirectory READ get_outputDirectory WRITE set_outputDirectory RESET reset_outputDirectory STORED false) | ||
| 18 | + Q_PROPERTY(QString imageName READ get_imageName WRITE set_imageName RESET reset_imageName STORED false) | ||
| 19 | + Q_PROPERTY(QString imgExtension READ get_imgExtension WRITE set_imgExtension RESET reset_imgExtension STORED false) | ||
| 20 | + BR_PROPERTY(QString, outputDirectory, "Temp") | ||
| 21 | + BR_PROPERTY(QString, imageName, "image") | ||
| 22 | + BR_PROPERTY(QString, imgExtension, "jpg") | ||
| 23 | + | ||
| 24 | + int cnt; | ||
| 25 | + | ||
| 26 | + void init() { | ||
| 27 | + cnt = 0; | ||
| 28 | + if (! QDir(outputDirectory).exists()) | ||
| 29 | + QDir().mkdir(outputDirectory); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + void projectUpdate(const Template &src, Template &dst) | ||
| 33 | + { | ||
| 34 | + dst = src; | ||
| 35 | + OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, 10, QChar('0')).arg(imgExtension)); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | +}; | ||
| 39 | + | ||
| 40 | +BR_REGISTER(Transform, WriteTransform) | ||
| 41 | + | ||
| 42 | +} // namespace br | ||
| 43 | + | ||
| 44 | +#include "write.moc" |
openbr/plugins/keypoint.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | - * Copyright 2012 The MITRE Corporation * | ||
| 3 | - * * | ||
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | ||
| 5 | - * you may not use this file except in compliance with the License. * | ||
| 6 | - * You may obtain a copy of the License at * | ||
| 7 | - * * | ||
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | ||
| 9 | - * * | ||
| 10 | - * Unless required by applicable law or agreed to in writing, software * | ||
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | ||
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | ||
| 13 | - * See the License for the specific language governing permissions and * | ||
| 14 | - * limitations under the License. * | ||
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 16 | - | ||
| 17 | -#include <opencv2/features2d/features2d.hpp> | ||
| 18 | -#include <opencv2/objdetect/objdetect.hpp> | ||
| 19 | -#include <opencv2/nonfree/nonfree.hpp> | ||
| 20 | -#include "openbr_internal.h" | ||
| 21 | -#include "openbr/core/opencvutils.h" | ||
| 22 | - | ||
| 23 | -using namespace cv; | ||
| 24 | - | ||
| 25 | -namespace br | ||
| 26 | -{ | ||
| 27 | - | ||
| 28 | -/*! | ||
| 29 | - * \ingroup transforms | ||
| 30 | - * \brief Wraps OpenCV Key Point Detector | ||
| 31 | - * \author Josh Klontz \cite jklontz | ||
| 32 | - */ | ||
| 33 | -class KeyPointDetectorTransform : public UntrainableTransform | ||
| 34 | -{ | ||
| 35 | - Q_OBJECT | ||
| 36 | - Q_PROPERTY(QString detector READ get_detector WRITE set_detector RESET reset_detector STORED false) | ||
| 37 | - BR_PROPERTY(QString, detector, "SIFT") | ||
| 38 | - | ||
| 39 | - Ptr<FeatureDetector> featureDetector; | ||
| 40 | - | ||
| 41 | - void init() | ||
| 42 | - { | ||
| 43 | - featureDetector = FeatureDetector::create(detector.toStdString()); | ||
| 44 | - if (featureDetector.empty()) | ||
| 45 | - qFatal("Failed to create KeyPointDetector: %s", qPrintable(detector)); | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - void project(const Template &src, Template &dst) const | ||
| 49 | - { | ||
| 50 | - dst = src; | ||
| 51 | - | ||
| 52 | - std::vector<KeyPoint> keyPoints; | ||
| 53 | - try { | ||
| 54 | - featureDetector->detect(src, keyPoints); | ||
| 55 | - } catch (...) { | ||
| 56 | - qWarning("Key point detection failed for file %s", qPrintable(src.file.name)); | ||
| 57 | - dst.file.fte = true; | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - QList<Rect> rects; | ||
| 61 | - foreach (const KeyPoint &keyPoint, keyPoints) | ||
| 62 | - rects.append(Rect(keyPoint.pt.x-keyPoint.size/2, keyPoint.pt.y-keyPoint.size/2, keyPoint.size, keyPoint.size)); | ||
| 63 | - dst.file.setRects(OpenCVUtils::fromRects(rects)); | ||
| 64 | - } | ||
| 65 | -}; | ||
| 66 | - | ||
| 67 | -BR_REGISTER(Transform, KeyPointDetectorTransform) | ||
| 68 | - | ||
| 69 | -/*! | ||
| 70 | - * \ingroup transforms | ||
| 71 | - * \brief Wraps OpenCV Key Point Descriptor | ||
| 72 | - * \author Josh Klontz \cite jklontz | ||
| 73 | - */ | ||
| 74 | -class KeyPointDescriptorTransform : public UntrainableTransform | ||
| 75 | -{ | ||
| 76 | - Q_OBJECT | ||
| 77 | - Q_PROPERTY(QString descriptor READ get_descriptor WRITE set_descriptor RESET reset_descriptor STORED false) | ||
| 78 | - Q_PROPERTY(int size READ get_size WRITE set_size RESET reset_size STORED false) | ||
| 79 | - BR_PROPERTY(QString, descriptor, "SIFT") | ||
| 80 | - BR_PROPERTY(int, size, -1) | ||
| 81 | - | ||
| 82 | - Ptr<DescriptorExtractor> descriptorExtractor; | ||
| 83 | - | ||
| 84 | - void init() | ||
| 85 | - { | ||
| 86 | - descriptorExtractor = DescriptorExtractor::create(descriptor.toStdString()); | ||
| 87 | - if (descriptorExtractor.empty()) | ||
| 88 | - qFatal("Failed to create DescriptorExtractor: %s", qPrintable(descriptor)); | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - void project(const Template &src, Template &dst) const | ||
| 92 | - { | ||
| 93 | - std::vector<KeyPoint> keyPoints; | ||
| 94 | - if (size == -1) | ||
| 95 | - foreach (const QRectF &ROI, src.file.rects()) | ||
| 96 | - keyPoints.push_back(KeyPoint(ROI.x()+ROI.width()/2, ROI.y()+ROI.height()/2, (ROI.width() + ROI.height())/2)); | ||
| 97 | - else | ||
| 98 | - foreach (const QPointF &landmark, src.file.points()) | ||
| 99 | - keyPoints.push_back(KeyPoint(landmark.x(), landmark.y(), size)); | ||
| 100 | - if (keyPoints.empty()) return; | ||
| 101 | - descriptorExtractor->compute(src, keyPoints, dst); | ||
| 102 | - } | ||
| 103 | -}; | ||
| 104 | - | ||
| 105 | -BR_REGISTER(Transform, KeyPointDescriptorTransform) | ||
| 106 | - | ||
| 107 | -/*! | ||
| 108 | - * \ingroup transforms | ||
| 109 | - * \brief Wraps OpenCV Key Point Matcher | ||
| 110 | - * \author Josh Klontz \cite jklontz | ||
| 111 | - */ | ||
| 112 | -class KeyPointMatcherDistance : public UntrainableDistance | ||
| 113 | -{ | ||
| 114 | - Q_OBJECT | ||
| 115 | - Q_PROPERTY(QString matcher READ get_matcher WRITE set_matcher RESET reset_matcher STORED false) | ||
| 116 | - Q_PROPERTY(float maxRatio READ get_maxRatio WRITE set_maxRatio RESET reset_maxRatio STORED false) | ||
| 117 | - BR_PROPERTY(QString, matcher, "BruteForce") | ||
| 118 | - BR_PROPERTY(float, maxRatio, 0.8) | ||
| 119 | - | ||
| 120 | - Ptr<DescriptorMatcher> descriptorMatcher; | ||
| 121 | - | ||
| 122 | - void init() | ||
| 123 | - { | ||
| 124 | - descriptorMatcher = DescriptorMatcher::create(matcher.toStdString()); | ||
| 125 | - if (descriptorMatcher.empty()) | ||
| 126 | - qFatal("Failed to create DescriptorMatcher: %s", qPrintable(matcher)); | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - float compare(const Mat &a, const Mat &b) const | ||
| 130 | - { | ||
| 131 | - if ((a.rows < 2) || (b.rows < 2)) return 0; | ||
| 132 | - | ||
| 133 | - std::vector< std::vector<DMatch> > matches; | ||
| 134 | - if (a.rows < b.rows) descriptorMatcher->knnMatch(a, b, matches, 2); | ||
| 135 | - else descriptorMatcher->knnMatch(b, a, matches, 2); | ||
| 136 | - | ||
| 137 | - QList<float> distances; | ||
| 138 | - foreach (const std::vector<DMatch> &match, matches) { | ||
| 139 | - if (match[0].distance / match[1].distance > maxRatio) continue; | ||
| 140 | - distances.append(match[0].distance); | ||
| 141 | - } | ||
| 142 | - qSort(distances); | ||
| 143 | - | ||
| 144 | - float similarity = 0; | ||
| 145 | - for (int i=0; i<distances.size(); i++) | ||
| 146 | - similarity += 1.f/(1+distances[i])/(i+1); | ||
| 147 | - return similarity; | ||
| 148 | - } | ||
| 149 | -}; | ||
| 150 | - | ||
| 151 | -BR_REGISTER(Distance, KeyPointMatcherDistance) | ||
| 152 | - | ||
| 153 | -/*! | ||
| 154 | - * \ingroup transforms | ||
| 155 | - * \brief Specialize wrapper OpenCV SIFT wrapper | ||
| 156 | - * \author Josh Klontz \cite jklontz | ||
| 157 | - */ | ||
| 158 | -class SIFTDescriptorTransform : public UntrainableTransform | ||
| 159 | -{ | ||
| 160 | - Q_OBJECT | ||
| 161 | - Q_PROPERTY(int size READ get_size WRITE set_size RESET reset_size STORED false) | ||
| 162 | - Q_PROPERTY(QList<int> sizes READ get_sizes WRITE set_sizes RESET reset_sizes STORED false) | ||
| 163 | - Q_PROPERTY(int nFeatures READ get_nFeatures WRITE set_nFeatures RESET reset_nFeatures STORED false) | ||
| 164 | - Q_PROPERTY(int nOctaveLayers READ get_nOctaveLayers WRITE set_nOctaveLayers RESET reset_nOctaveLayers STORED false) | ||
| 165 | - Q_PROPERTY(double contrastThreshold READ get_contrastThreshold WRITE set_contrastThreshold RESET reset_contrastThreshold STORED false) | ||
| 166 | - Q_PROPERTY(double edgeThreshold READ get_edgeThreshold WRITE set_edgeThreshold RESET reset_edgeThreshold STORED false) | ||
| 167 | - Q_PROPERTY(double sigma READ get_sigma WRITE set_sigma RESET reset_sigma STORED false) | ||
| 168 | - BR_PROPERTY(int, size, 1) | ||
| 169 | - BR_PROPERTY(QList<int>, sizes, QList<int>()) | ||
| 170 | - BR_PROPERTY(int, nFeatures, 0) | ||
| 171 | - BR_PROPERTY(int, nOctaveLayers, 3) | ||
| 172 | - BR_PROPERTY(double, contrastThreshold, 0.04) | ||
| 173 | - BR_PROPERTY(double, edgeThreshold, 10) | ||
| 174 | - BR_PROPERTY(double, sigma, 1.6) | ||
| 175 | - | ||
| 176 | - SIFT sift; | ||
| 177 | - | ||
| 178 | - void init() | ||
| 179 | - { | ||
| 180 | - if (sizes.empty()) | ||
| 181 | - sizes.append(size); | ||
| 182 | - sift = SIFT(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma); | ||
| 183 | - } | ||
| 184 | - | ||
| 185 | - void project(const Template &src, Template &dst) const | ||
| 186 | - { | ||
| 187 | - std::vector<KeyPoint> keyPoints; | ||
| 188 | - foreach (const QPointF &val, src.file.points()) | ||
| 189 | - foreach (const int r, sizes) | ||
| 190 | - keyPoints.push_back(KeyPoint(val.x(), val.y(), r)); | ||
| 191 | - | ||
| 192 | - Mat m; | ||
| 193 | - sift(src, Mat(), keyPoints, m, true); | ||
| 194 | - m.setTo(0, m<0); // SIFT returns large negative values when it goes off the edge of the image. | ||
| 195 | - dst += m; | ||
| 196 | - } | ||
| 197 | -}; | ||
| 198 | - | ||
| 199 | -BR_REGISTER(Transform, SIFTDescriptorTransform) | ||
| 200 | - | ||
| 201 | -/*! | ||
| 202 | - * \ingroup transforms | ||
| 203 | - * \brief OpenCV HOGDescriptor wrapper | ||
| 204 | - * \author Austin Blanton \cite imaus10 | ||
| 205 | - */ | ||
| 206 | -class HoGDescriptorTransform : public UntrainableTransform | ||
| 207 | -{ | ||
| 208 | - Q_OBJECT | ||
| 209 | - | ||
| 210 | - HOGDescriptor hog; | ||
| 211 | - | ||
| 212 | - void project(const Template &src, Template &dst) const | ||
| 213 | - { | ||
| 214 | - std::vector<float> descriptorVals; | ||
| 215 | - std::vector<Point> locations; | ||
| 216 | - Size winStride = Size(0,0); | ||
| 217 | - Size padding = Size(0,0); | ||
| 218 | - foreach (const Mat &rect, src) { | ||
| 219 | - hog.compute(rect, descriptorVals, winStride, padding, locations); | ||
| 220 | - Mat HoGFeats(descriptorVals, true); | ||
| 221 | - dst += HoGFeats; | ||
| 222 | - } | ||
| 223 | - } | ||
| 224 | -}; | ||
| 225 | - | ||
| 226 | -BR_REGISTER(Transform, HoGDescriptorTransform) | ||
| 227 | - | ||
| 228 | -/*! | ||
| 229 | - * \ingroup transforms | ||
| 230 | - * \brief Add landmarks to the template in a grid layout | ||
| 231 | - * \author Josh Klontz \cite jklontz | ||
| 232 | - */ | ||
| 233 | -class GridTransform : public UntrainableTransform | ||
| 234 | -{ | ||
| 235 | - Q_OBJECT | ||
| 236 | - Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | ||
| 237 | - Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | ||
| 238 | - BR_PROPERTY(int, rows, 1) | ||
| 239 | - BR_PROPERTY(int, columns, 1) | ||
| 240 | - | ||
| 241 | - void project(const Template &src, Template &dst) const | ||
| 242 | - { | ||
| 243 | - QList<QPointF> landmarks; | ||
| 244 | - const float row_step = 1.f * src.m().rows / rows; | ||
| 245 | - const float column_step = 1.f * src.m().cols / columns; | ||
| 246 | - for (float y=row_step/2; y<src.m().rows; y+=row_step) | ||
| 247 | - for (float x=column_step/2; x<src.m().cols; x+=column_step) | ||
| 248 | - landmarks.append(QPointF(x,y)); | ||
| 249 | - dst = src; | ||
| 250 | - dst.file.setPoints(landmarks); | ||
| 251 | - } | ||
| 252 | -}; | ||
| 253 | - | ||
| 254 | -BR_REGISTER(Transform, GridTransform) | ||
| 255 | - | ||
| 256 | -} // namespace br | ||
| 257 | - | ||
| 258 | -#include "keypoint.moc" |
openbr/plugins/landmarks.cpp
| @@ -498,6 +498,30 @@ class NormalizePointsTransform : public UntrainableTransform | @@ -498,6 +498,30 @@ class NormalizePointsTransform : public UntrainableTransform | ||
| 498 | 498 | ||
| 499 | BR_REGISTER(Transform, NormalizePointsTransform) | 499 | BR_REGISTER(Transform, NormalizePointsTransform) |
| 500 | 500 | ||
| 501 | +class SetPointsInRectTransform : public UntrainableMetadataTransform | ||
| 502 | +{ | ||
| 503 | + Q_OBJECT | ||
| 504 | + | ||
| 505 | + void projectMetadata(const File &src, File &dst) const | ||
| 506 | + { | ||
| 507 | + dst = src; | ||
| 508 | + | ||
| 509 | + QList<QRectF> rects = src.rects(); | ||
| 510 | + if (rects.size() != 1) | ||
| 511 | + qFatal("Must have one and only one rect per template"); | ||
| 512 | + QRectF rect = rects.first(); | ||
| 513 | + | ||
| 514 | + QList<QPointF> srcPoints = src.points(); | ||
| 515 | + QList<QPointF> dstPoints; | ||
| 516 | + foreach (const QPointF &point, srcPoints) | ||
| 517 | + dstPoints.append(QPointF(point.x() - rect.x(), point.y() - rect.y())); | ||
| 518 | + | ||
| 519 | + dst.setPoints(dstPoints); | ||
| 520 | + } | ||
| 521 | +}; | ||
| 522 | + | ||
| 523 | +BR_REGISTER(Transform, SetPointsInRectTransform) | ||
| 524 | + | ||
| 501 | /*! | 525 | /*! |
| 502 | * \ingroup transforms | 526 | * \ingroup transforms |
| 503 | * \brief Normalize points to be relative to a single point | 527 | * \brief Normalize points to be relative to a single point |
openbr/plugins/lbp.cpp
| @@ -46,8 +46,6 @@ class LBPTransform : public UntrainableTransform | @@ -46,8 +46,6 @@ class LBPTransform : public UntrainableTransform | ||
| 46 | uchar lut[256]; | 46 | uchar lut[256]; |
| 47 | uchar null; | 47 | uchar null; |
| 48 | 48 | ||
| 49 | - friend class ColoredU2Transform; | ||
| 50 | - | ||
| 51 | /* Returns the number of 0->1 or 1->0 transitions in i */ | 49 | /* Returns the number of 0->1 or 1->0 transitions in i */ |
| 52 | static int numTransitions(int i) | 50 | static int numTransitions(int i) |
| 53 | { | 51 | { |
| @@ -125,74 +123,6 @@ class LBPTransform : public UntrainableTransform | @@ -125,74 +123,6 @@ class LBPTransform : public UntrainableTransform | ||
| 125 | 123 | ||
| 126 | BR_REGISTER(Transform, LBPTransform) | 124 | BR_REGISTER(Transform, LBPTransform) |
| 127 | 125 | ||
| 128 | -/*! | ||
| 129 | - * \ingroup transforms | ||
| 130 | - * \brief For visualization of LBP patterns. | ||
| 131 | - * \author Josh Klontz \cite jklontz | ||
| 132 | - */ | ||
| 133 | -class ColoredU2Transform : public UntrainableTransform | ||
| 134 | -{ | ||
| 135 | - Q_OBJECT | ||
| 136 | - | ||
| 137 | - /* Returns the number of 1 bits in i */ | ||
| 138 | - static int bitCount(int i) | ||
| 139 | - { | ||
| 140 | - int count = 0; | ||
| 141 | - for (int j=0; j<8; j++) | ||
| 142 | - count += (i>>j)%2; | ||
| 143 | - return count; | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | - void project(const Template &src, Template &dst) const | ||
| 147 | - { | ||
| 148 | - static Mat hueLUT, saturationLUT, valueLUT; | ||
| 149 | - | ||
| 150 | - if (!hueLUT.data) { | ||
| 151 | - const int NUM_COLORS = 10; | ||
| 152 | - hueLUT.create(1, 256, CV_8UC1); | ||
| 153 | - hueLUT.setTo(0); | ||
| 154 | - | ||
| 155 | - uchar uid = 0; | ||
| 156 | - for (int i=0; i<256; i++) { | ||
| 157 | - const int transitions = LBPTransform::numTransitions(i); | ||
| 158 | - int u2; | ||
| 159 | - if (transitions <= 2) u2 = uid++; | ||
| 160 | - else u2 = 58; | ||
| 161 | - | ||
| 162 | - // Assign hue based on bit count | ||
| 163 | - int color = bitCount(i); | ||
| 164 | - if (transitions > 2) color = NUM_COLORS-1; | ||
| 165 | - hueLUT.at<uchar>(0, u2) = 255*color/NUM_COLORS; | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - saturationLUT.create(1, 256, CV_8UC1); | ||
| 169 | - saturationLUT.setTo(255); | ||
| 170 | - | ||
| 171 | - valueLUT.create(1, 256, CV_8UC1); | ||
| 172 | - valueLUT.setTo(255*3/4); | ||
| 173 | - } | ||
| 174 | - | ||
| 175 | - if (src.m().type() != CV_8UC1) | ||
| 176 | - qFatal("Expected 8UC1 source type."); | ||
| 177 | - | ||
| 178 | - Mat hue, saturation, value; | ||
| 179 | - LUT(src, hueLUT, hue); | ||
| 180 | - LUT(src, saturationLUT, saturation); | ||
| 181 | - LUT(src, valueLUT, value); | ||
| 182 | - | ||
| 183 | - std::vector<Mat> mv; | ||
| 184 | - mv.push_back(hue); | ||
| 185 | - mv.push_back(saturation); | ||
| 186 | - mv.push_back(value); | ||
| 187 | - | ||
| 188 | - Mat coloredU2; | ||
| 189 | - merge(mv, coloredU2); | ||
| 190 | - cvtColor(coloredU2, dst, CV_HSV2BGR); | ||
| 191 | - } | ||
| 192 | -}; | ||
| 193 | - | ||
| 194 | -BR_REGISTER(Transform, ColoredU2Transform) | ||
| 195 | - | ||
| 196 | } // namespace br | 126 | } // namespace br |
| 197 | 127 | ||
| 198 | #include "lbp.moc" | 128 | #include "lbp.moc" |
openbr/plugins/metadata/grid.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief Add landmarks to the template in a grid layout | ||
| 9 | + * \author Josh Klontz \cite jklontz | ||
| 10 | + */ | ||
| 11 | +class GridTransform : public UntrainableTransform | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(int rows READ get_rows WRITE set_rows RESET reset_rows STORED false) | ||
| 15 | + Q_PROPERTY(int columns READ get_columns WRITE set_columns RESET reset_columns STORED false) | ||
| 16 | + BR_PROPERTY(int, rows, 1) | ||
| 17 | + BR_PROPERTY(int, columns, 1) | ||
| 18 | + | ||
| 19 | + void project(const Template &src, Template &dst) const | ||
| 20 | + { | ||
| 21 | + QList<QPointF> landmarks; | ||
| 22 | + const float row_step = 1.f * src.m().rows / rows; | ||
| 23 | + const float column_step = 1.f * src.m().cols / columns; | ||
| 24 | + for (float y=row_step/2; y<src.m().rows; y+=row_step) | ||
| 25 | + for (float x=column_step/2; x<src.m().cols; x+=column_step) | ||
| 26 | + landmarks.append(QPointF(x,y)); | ||
| 27 | + dst = src; | ||
| 28 | + dst.file.setPoints(landmarks); | ||
| 29 | + } | ||
| 30 | +}; | ||
| 31 | + | ||
| 32 | +BR_REGISTER(Transform, GridTransform) | ||
| 33 | + | ||
| 34 | +} // namespace br | ||
| 35 | + | ||
| 36 | +#include "grid.moc" |
openbr/plugins/metadata/keytorect.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief Convert values of key_X, key_Y, key_Width, key_Height to a rect. | ||
| 9 | + * \author Jordan Cheney \cite JordanCheney | ||
| 10 | + */ | ||
| 11 | +class KeyToRectTransform : public UntrainableMetadataTransform | ||
| 12 | +{ | ||
| 13 | + Q_OBJECT | ||
| 14 | + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false) | ||
| 15 | + BR_PROPERTY(QString, key, "") | ||
| 16 | + | ||
| 17 | + void projectMetadata(const File &src, File &dst) const | ||
| 18 | + { | ||
| 19 | + dst = src; | ||
| 20 | + | ||
| 21 | + if (src.contains(QStringList() << key + "_X" << key + "_Y" << key + "_Width" << key + "_Height")) | ||
| 22 | + dst.appendRect(QRectF(src.get<int>(key + "_X"), | ||
| 23 | + src.get<int>(key + "_Y"), | ||
| 24 | + src.get<int>(key + "_Width"), | ||
| 25 | + src.get<int>(key + "_Height"))); | ||
| 26 | + | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +BR_REGISTER(Transform, KeyToRectTransform) | ||
| 32 | + | ||
| 33 | +} // namespace br | ||
| 34 | + | ||
| 35 | +#include "keytorect.moc" |
openbr/plugins/metadata/procrustes.cpp
0 → 100644
| 1 | +#include <Eigen/Dense> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +/*! | ||
| 9 | + * \ingroup transforms | ||
| 10 | + * \brief Procrustes alignment of points | ||
| 11 | + * \author Scott Klum \cite sklum | ||
| 12 | + */ | ||
| 13 | +class ProcrustesTransform : public MetadataTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + | ||
| 17 | + Q_PROPERTY(bool warp READ get_warp WRITE set_warp RESET reset_warp STORED false) | ||
| 18 | + BR_PROPERTY(bool, warp, true) | ||
| 19 | + | ||
| 20 | + Eigen::MatrixXf meanShape; | ||
| 21 | + | ||
| 22 | + void train(const TemplateList &data) | ||
| 23 | + { | ||
| 24 | + QList< QList<QPointF> > normalizedPoints; | ||
| 25 | + | ||
| 26 | + // Normalize all sets of points | ||
| 27 | + foreach (br::Template datum, data) { | ||
| 28 | + QList<QPointF> points = datum.file.points(); | ||
| 29 | + QList<QRectF> rects = datum.file.rects(); | ||
| 30 | + | ||
| 31 | + if (points.empty() || rects.empty()) continue; | ||
| 32 | + | ||
| 33 | + // Assume rect appended last was bounding box | ||
| 34 | + points.append(rects.last().topLeft()); | ||
| 35 | + points.append(rects.last().topRight()); | ||
| 36 | + points.append(rects.last().bottomLeft()); | ||
| 37 | + points.append(rects.last().bottomRight()); | ||
| 38 | + | ||
| 39 | + // Center shape at origin | ||
| 40 | + Scalar mean = cv::mean(OpenCVUtils::toPoints(points).toVector().toStdVector()); | ||
| 41 | + for (int i = 0; i < points.size(); i++) points[i] -= QPointF(mean[0],mean[1]); | ||
| 42 | + | ||
| 43 | + // Remove scale component | ||
| 44 | + float norm = cv::norm(OpenCVUtils::toPoints(points).toVector().toStdVector()); | ||
| 45 | + for (int i = 0; i < points.size(); i++) points[i] /= norm; | ||
| 46 | + | ||
| 47 | + normalizedPoints.append(points); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + if (normalizedPoints.empty()) qFatal("Unable to calculate normalized points"); | ||
| 51 | + | ||
| 52 | + // Determine mean shape, assuming all shapes contain the same number of points | ||
| 53 | + meanShape = Eigen::MatrixXf(normalizedPoints[0].size(), 2); | ||
| 54 | + | ||
| 55 | + for (int i = 0; i < normalizedPoints[0].size(); i++) { | ||
| 56 | + double x = 0; | ||
| 57 | + double y = 0; | ||
| 58 | + | ||
| 59 | + for (int j = 0; j < normalizedPoints.size(); j++) { | ||
| 60 | + x += normalizedPoints[j][i].x(); | ||
| 61 | + y += normalizedPoints[j][i].y(); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + x /= (double)normalizedPoints.size(); | ||
| 65 | + y /= (double)normalizedPoints.size(); | ||
| 66 | + | ||
| 67 | + meanShape(i,0) = x; | ||
| 68 | + meanShape(i,1) = y; | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + void project(const Template &src, Template &dst) const | ||
| 73 | + { | ||
| 74 | + QList<QPointF> points = src.file.points(); | ||
| 75 | + QList<QRectF> rects = src.file.rects(); | ||
| 76 | + | ||
| 77 | + if (points.empty() || rects.empty()) { | ||
| 78 | + dst = src; | ||
| 79 | + if (Globals->verbose) qWarning("Procrustes alignment failed because points or rects are empty."); | ||
| 80 | + return; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // Assume rect appended last was bounding box | ||
| 84 | + points.append(rects.last().topLeft()); | ||
| 85 | + points.append(rects.last().topRight()); | ||
| 86 | + points.append(rects.last().bottomLeft()); | ||
| 87 | + points.append(rects.last().bottomRight()); | ||
| 88 | + | ||
| 89 | + Scalar mean = cv::mean(OpenCVUtils::toPoints(points).toVector().toStdVector()); | ||
| 90 | + for (int i = 0; i < points.size(); i++) points[i] -= QPointF(mean[0],mean[1]); | ||
| 91 | + | ||
| 92 | + Eigen::MatrixXf srcMat(points.size(), 2); | ||
| 93 | + float norm = cv::norm(OpenCVUtils::toPoints(points).toVector().toStdVector()); | ||
| 94 | + for (int i = 0; i < points.size(); i++) { | ||
| 95 | + points[i] /= norm; | ||
| 96 | + srcMat(i,0) = points[i].x(); | ||
| 97 | + srcMat(i,1) = points[i].y(); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + Eigen::JacobiSVD<Eigen::MatrixXf> svd(srcMat.transpose()*meanShape, Eigen::ComputeThinU | Eigen::ComputeThinV); | ||
| 101 | + Eigen::MatrixXf R = svd.matrixU()*svd.matrixV().transpose(); | ||
| 102 | + | ||
| 103 | + dst = src; | ||
| 104 | + | ||
| 105 | + // Store procrustes stats in the order: | ||
| 106 | + // R(0,0), R(1,0), R(1,1), R(0,1), mean_x, mean_y, norm | ||
| 107 | + QList<float> procrustesStats; | ||
| 108 | + procrustesStats << R(0,0) << R(1,0) << R(1,1) << R(0,1) << mean[0] << mean[1] << norm; | ||
| 109 | + dst.file.setList<float>("ProcrustesStats",procrustesStats); | ||
| 110 | + | ||
| 111 | + if (warp) { | ||
| 112 | + Eigen::MatrixXf dstMat = srcMat*R; | ||
| 113 | + for (int i = 0; i < dstMat.rows(); i++) { | ||
| 114 | + dst.file.appendPoint(QPointF(dstMat(i,0),dstMat(i,1))); | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + void store(QDataStream &stream) const | ||
| 120 | + { | ||
| 121 | + stream << meanShape; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + void load(QDataStream &stream) | ||
| 125 | + { | ||
| 126 | + stream >> meanShape; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | +}; | ||
| 130 | + | ||
| 131 | +BR_REGISTER(Transform, ProcrustesTransform) | ||
| 132 | + | ||
| 133 | +} // namespace br | ||
| 134 | + | ||
| 135 | +#include "procrustes.moc" |
openbr/plugins/motion.cpp
| @@ -59,48 +59,6 @@ class OpticalFlowTransform : public UntrainableMetaTransform | @@ -59,48 +59,6 @@ class OpticalFlowTransform : public UntrainableMetaTransform | ||
| 59 | 59 | ||
| 60 | BR_REGISTER(Transform, OpticalFlowTransform) | 60 | BR_REGISTER(Transform, OpticalFlowTransform) |
| 61 | 61 | ||
| 62 | -/*! | ||
| 63 | - * \ingroup transforms | ||
| 64 | - * \brief Wraps OpenCV's BackgroundSubtractorMOG2 and puts the foreground mask in the Template metadata. | ||
| 65 | - * \author Austin Blanton \cite imaus10 | ||
| 66 | - */ | ||
| 67 | -class SubtractBackgroundTransform : public TimeVaryingTransform | ||
| 68 | -{ | ||
| 69 | - Q_OBJECT | ||
| 70 | - | ||
| 71 | - // TODO: This is broken. | ||
| 72 | - // BackgroundSubtractorMOG2 mog; | ||
| 73 | - | ||
| 74 | -public: | ||
| 75 | - SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} | ||
| 76 | - | ||
| 77 | -private: | ||
| 78 | - void projectUpdate(const Template &src, Template &dst) | ||
| 79 | - { | ||
| 80 | - dst = src; | ||
| 81 | - Mat mask; | ||
| 82 | - // TODO: broken | ||
| 83 | - // mog(src, mask); | ||
| 84 | - erode(mask, mask, Mat()); | ||
| 85 | - dilate(mask, mask, Mat()); | ||
| 86 | - dst.file.set("Mask", QVariant::fromValue(mask)); | ||
| 87 | - } | ||
| 88 | - | ||
| 89 | - void project(const Template &src, Template &dst) const | ||
| 90 | - { | ||
| 91 | - (void) src; (void) dst; qFatal("no way"); | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - void finalize(TemplateList &output) | ||
| 95 | - { | ||
| 96 | - (void) output; | ||
| 97 | - // TODO: Broken | ||
| 98 | - // mog = BackgroundSubtractorMOG2(); | ||
| 99 | - } | ||
| 100 | -}; | ||
| 101 | - | ||
| 102 | -BR_REGISTER(Transform, SubtractBackgroundTransform) | ||
| 103 | - | ||
| 104 | } // namespace br | 62 | } // namespace br |
| 105 | 63 | ||
| 106 | #include "motion.moc" | 64 | #include "motion.moc" |
openbr/plugins/plugins.cmake
| @@ -12,8 +12,28 @@ foreach(DIR ${BR_THIRDPARTY_PLUGINS_DIR}) | @@ -12,8 +12,28 @@ foreach(DIR ${BR_THIRDPARTY_PLUGINS_DIR}) | ||
| 12 | set(BR_THIRDPARTY_PLUGINS ${BR_THIRDPARTY_PLUGINS} ${PLUGINS}) | 12 | set(BR_THIRDPARTY_PLUGINS ${BR_THIRDPARTY_PLUGINS} ${PLUGINS}) |
| 13 | endforeach() | 13 | endforeach() |
| 14 | 14 | ||
| 15 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} core) | ||
| 16 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} io) | ||
| 17 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} gui) | ||
| 18 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} imgproc) | ||
| 19 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} video) | ||
| 20 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} cluster) | ||
| 21 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} distance) | ||
| 22 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} format) | ||
| 23 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} representation) | ||
| 24 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} detection) | ||
| 25 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} classification) | ||
| 26 | +set(BR_PLUGINS_DIR ${BR_PLUGINS_DIR} metadata) | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +foreach(DIR ${BR_PLUGINS_DIR}) | ||
| 30 | + file(GLOB PLUGINS plugins/${DIR}/*.cpp plugins/${DIR}/*.h) | ||
| 31 | + set(BR_PLUGINS ${BR_PLUGINS} ${PLUGINS}) | ||
| 32 | +endforeach() | ||
| 33 | + | ||
| 15 | file(GLOB PLUGINS plugins/*.cpp plugins/*.h) | 34 | file(GLOB PLUGINS plugins/*.cpp plugins/*.h) |
| 16 | -foreach(PLUGIN ${PLUGINS} ${BR_THIRDPARTY_PLUGINS}) | 35 | +set(BR_PLUGINS ${BR_PLUGINS} ${PLUGINS}) |
| 36 | +foreach(PLUGIN ${BR_PLUGINS} ${BR_THIRDPARTY_PLUGINS}) | ||
| 17 | get_filename_component(PLUGIN_BASENAME ${PLUGIN} NAME_WE) | 37 | get_filename_component(PLUGIN_BASENAME ${PLUGIN} NAME_WE) |
| 18 | get_filename_component(PLUGIN_PATH ${PLUGIN} PATH) | 38 | get_filename_component(PLUGIN_PATH ${PLUGIN} PATH) |
| 19 | set(PLUGIN_CMAKE "${PLUGIN_PATH}/${PLUGIN_BASENAME}.cmake") | 39 | set(PLUGIN_CMAKE "${PLUGIN_PATH}/${PLUGIN_BASENAME}.cmake") |
openbr/plugins/quantize.cpp
| @@ -287,56 +287,6 @@ class ProductQuantizationDistance : public UntrainableDistance | @@ -287,56 +287,6 @@ class ProductQuantizationDistance : public UntrainableDistance | ||
| 287 | BR_REGISTER(Distance, ProductQuantizationDistance) | 287 | BR_REGISTER(Distance, ProductQuantizationDistance) |
| 288 | 288 | ||
| 289 | /*! | 289 | /*! |
| 290 | - * \ingroup distances | ||
| 291 | - * \brief Recurively computed distance in a product quantized space | ||
| 292 | - * \author Josh Klontz \cite jklontz | ||
| 293 | - */ | ||
| 294 | -class RecursiveProductQuantizationDistance : public UntrainableDistance | ||
| 295 | -{ | ||
| 296 | - Q_OBJECT | ||
| 297 | - Q_PROPERTY(float t READ get_t WRITE set_t RESET reset_t STORED false) | ||
| 298 | - BR_PROPERTY(float, t, -std::numeric_limits<float>::max()) | ||
| 299 | - | ||
| 300 | - float compare(const Template &a, const Template &b) const | ||
| 301 | - { | ||
| 302 | - return compareRecursive(a, b, 0, a.size(), 0); | ||
| 303 | - } | ||
| 304 | - | ||
| 305 | - float compareRecursive(const QList<cv::Mat> &a, const QList<cv::Mat> &b, int i, int size, float evidence) const | ||
| 306 | - { | ||
| 307 | - float similarity = 0; | ||
| 308 | - | ||
| 309 | - const int elements = a[i].total()-sizeof(quint16); | ||
| 310 | - uchar *aData = a[i].data; | ||
| 311 | - uchar *bData = b[i].data; | ||
| 312 | - quint16 index = *reinterpret_cast<quint16*>(aData); | ||
| 313 | - aData += sizeof(quint16); | ||
| 314 | - bData += sizeof(quint16); | ||
| 315 | - | ||
| 316 | - const float *lut = (const float*)ProductQuantizationLUTs[index].data; | ||
| 317 | - for (int j=0; j<elements; j++) { | ||
| 318 | - const int aj = aData[j]; | ||
| 319 | - const int bj = bData[j]; | ||
| 320 | - // http://stackoverflow.com/questions/4803180/mapping-elements-in-2d-upper-triangle-and-lower-triangle-to-linear-structure | ||
| 321 | - const int y = max(aj, bj); | ||
| 322 | - const int x = min(aj, bj); | ||
| 323 | - similarity += lut[j*256*(256+1)/2 + x + (y+1)*y/2]; | ||
| 324 | - } | ||
| 325 | - | ||
| 326 | - evidence += similarity; | ||
| 327 | - const int subSize = (size-1)/4; | ||
| 328 | - if ((evidence < t) || (subSize == 0)) return similarity; | ||
| 329 | - return similarity | ||
| 330 | - + compareRecursive(a, b, i+1+0*subSize, subSize, evidence) | ||
| 331 | - + compareRecursive(a, b, i+1+1*subSize, subSize, evidence) | ||
| 332 | - + compareRecursive(a, b, i+1+2*subSize, subSize, evidence) | ||
| 333 | - + compareRecursive(a, b, i+1+3*subSize, subSize, evidence); | ||
| 334 | - } | ||
| 335 | -}; | ||
| 336 | - | ||
| 337 | -BR_REGISTER(Distance, RecursiveProductQuantizationDistance) | ||
| 338 | - | ||
| 339 | -/*! | ||
| 340 | * \ingroup transforms | 290 | * \ingroup transforms |
| 341 | * \brief Product quantization \cite jegou11 | 291 | * \brief Product quantization \cite jegou11 |
| 342 | * \author Josh Klontz \cite jklontz | 292 | * \author Josh Klontz \cite jklontz |
openbr/plugins/random.cpp
| @@ -96,38 +96,61 @@ BR_REGISTER(Transform, RndSubspaceTransform) | @@ -96,38 +96,61 @@ BR_REGISTER(Transform, RndSubspaceTransform) | ||
| 96 | 96 | ||
| 97 | /*! | 97 | /*! |
| 98 | * \ingroup transforms | 98 | * \ingroup transforms |
| 99 | - * \brief Selects a random region. | ||
| 100 | - * \author Josh Klontz \cite jklontz | 99 | + * \brief Selects a number of random regions from a negative image. |
| 100 | + * \author Jordan Cheney \cite JordanCheney | ||
| 101 | */ | 101 | */ |
| 102 | -class RndRegionTransform : public Transform | 102 | +class RndNegSampleTransform : public UntrainableMetaTransform |
| 103 | { | 103 | { |
| 104 | Q_OBJECT | 104 | Q_OBJECT |
| 105 | - Q_PROPERTY(float x READ get_x WRITE set_x RESET reset_x) | ||
| 106 | - Q_PROPERTY(float y READ get_y WRITE set_y RESET reset_y) | ||
| 107 | - Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width) | ||
| 108 | - Q_PROPERTY(float height READ get_height WRITE set_height RESET reset_height) | ||
| 109 | - BR_PROPERTY(float, x, -1) | ||
| 110 | - BR_PROPERTY(float, y, -1) | ||
| 111 | - BR_PROPERTY(float, width, -1) | ||
| 112 | - BR_PROPERTY(float, height, -1) | 105 | + Q_PROPERTY(int numSamples READ get_numSamples WRITE set_numSamples RESET reset_numSamples STORED false) |
| 106 | + Q_PROPERTY(int width READ get_width WRITE set_width RESET reset_width STORED false) | ||
| 107 | + Q_PROPERTY(int height READ get_height WRITE set_height RESET reset_height STORED false) | ||
| 108 | + Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | ||
| 109 | + Q_PROPERTY(float negVal READ get_negVal WRITE set_negVal RESET reset_negVal STORED false) | ||
| 110 | + BR_PROPERTY(int, numSamples, 1) | ||
| 111 | + BR_PROPERTY(int, width, 24) | ||
| 112 | + BR_PROPERTY(int, height, 24) | ||
| 113 | + BR_PROPERTY(QString, propName, "Label") | ||
| 114 | + BR_PROPERTY(float, negVal, 0) | ||
| 113 | 115 | ||
| 114 | - void train(const TemplateList &data) | 116 | + void project(const Template &src, Template &dst) const |
| 115 | { | 117 | { |
| 116 | - (void) data; | 118 | + dst = src; |
| 119 | + | ||
| 120 | + if (src.file.get<float>(propName, negVal+1) == negVal) | ||
| 121 | + return; | ||
| 117 | 122 | ||
| 118 | RNG &rng = theRNG(); | 123 | RNG &rng = theRNG(); |
| 119 | - width = rng.uniform(0.f, 1.f); | ||
| 120 | - height = rng.uniform(0.f, 1.f); | ||
| 121 | - x = rng.uniform(0.f, 1.f-width); | ||
| 122 | - y = rng.uniform(0.f, 1.f-height); | 124 | + for (int n = 0; n < numSamples; n++) { |
| 125 | + int x = rng.uniform(0, src.m().cols - width - 1); | ||
| 126 | + int y = rng.uniform(0, src.m().rows - height - 1); | ||
| 127 | + dst.file.appendRect(Rect(x, y, width, height)); | ||
| 128 | + } | ||
| 123 | } | 129 | } |
| 130 | +}; | ||
| 131 | + | ||
| 132 | +BR_REGISTER(Transform, RndNegSampleTransform) | ||
| 133 | + | ||
| 134 | +/*! | ||
| 135 | + * \ingroup transforms | ||
| 136 | + * \brief Selects a random region. | ||
| 137 | + * \author Josh Klontz \cite jklontz | ||
| 138 | + */ | ||
| 139 | +class RndRegionTransform : public UntrainableTransform | ||
| 140 | +{ | ||
| 141 | + Q_OBJECT | ||
| 124 | 142 | ||
| 125 | void project(const Template &src, Template &dst) const | 143 | void project(const Template &src, Template &dst) const |
| 126 | { | 144 | { |
| 145 | + RNG &rng = theRNG(); | ||
| 146 | + float size = rng.uniform(0.2f, 1.f); | ||
| 147 | + float x = rng.uniform(0.f, 1.f-size); | ||
| 148 | + float y = rng.uniform(0.f, 1.f-size); | ||
| 149 | + | ||
| 127 | dst = src.m()(Rect(src.m().cols * x, | 150 | dst = src.m()(Rect(src.m().cols * x, |
| 128 | src.m().rows * y, | 151 | src.m().rows * y, |
| 129 | - src.m().cols * width, | ||
| 130 | - src.m().rows * height)); | 152 | + src.m().cols * size, |
| 153 | + src.m().rows * size)); | ||
| 131 | } | 154 | } |
| 132 | }; | 155 | }; |
| 133 | 156 |
openbr/plugins/regions.cpp
| @@ -374,8 +374,12 @@ class RectFromPointsTransform : public UntrainableTransform | @@ -374,8 +374,12 @@ class RectFromPointsTransform : public UntrainableTransform | ||
| 374 | 374 | ||
| 375 | QList<QPointF> points; | 375 | QList<QPointF> points; |
| 376 | 376 | ||
| 377 | - foreach (int index, indices) { | 377 | + int numPoints = (indices.empty() ? src.file.points().size() : indices.size()); |
| 378 | + for (int idx = 0; idx < numPoints; idx++) { | ||
| 379 | + int index = indices.empty() ? idx : indices[idx]; | ||
| 378 | if (src.file.points().size() > index) { | 380 | if (src.file.points().size() > index) { |
| 381 | + if (src.file.points()[index].x() <= 0 || | ||
| 382 | + src.file.points()[index].y() <= 0) continue; | ||
| 379 | if (src.file.points()[index].x() < minX) minX = src.file.points()[index].x(); | 383 | if (src.file.points()[index].x() < minX) minX = src.file.points()[index].x(); |
| 380 | if (src.file.points()[index].x() > maxX) maxX = src.file.points()[index].x(); | 384 | if (src.file.points()[index].x() > maxX) maxX = src.file.points()[index].x(); |
| 381 | if (src.file.points()[index].y() < minY) minY = src.file.points()[index].y(); | 385 | if (src.file.points()[index].y() < minY) minY = src.file.points()[index].y(); |
| @@ -390,8 +394,9 @@ class RectFromPointsTransform : public UntrainableTransform | @@ -390,8 +394,9 @@ class RectFromPointsTransform : public UntrainableTransform | ||
| 390 | width += deltaWidth; | 394 | width += deltaWidth; |
| 391 | 395 | ||
| 392 | double height = maxY-minY; | 396 | double height = maxY-minY; |
| 393 | - double deltaHeight = width/aspectRatio - height; | ||
| 394 | - height += deltaHeight; | 397 | + //double deltaHeight = width/aspectRatio - height; |
| 398 | + double deltaHeight = height*padding; | ||
| 399 | + height += deltaHeight; | ||
| 395 | 400 | ||
| 396 | const int x = std::max(0.0, minX - deltaWidth/2.0); | 401 | const int x = std::max(0.0, minX - deltaWidth/2.0); |
| 397 | const int y = std::max(0.0, minY - deltaHeight/2.0); | 402 | const int y = std::max(0.0, minY - deltaHeight/2.0); |
openbr/plugins/representation/hogdescriptor.cpp
0 → 100644
| 1 | +#include <opencv2/objdetect/objdetect.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief OpenCV HOGDescriptor wrapper | ||
| 13 | + * \author Austin Blanton \cite imaus10 | ||
| 14 | + */ | ||
| 15 | +class HoGDescriptorTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + | ||
| 19 | + HOGDescriptor hog; | ||
| 20 | + | ||
| 21 | + void project(const Template &src, Template &dst) const | ||
| 22 | + { | ||
| 23 | + std::vector<float> descriptorVals; | ||
| 24 | + std::vector<Point> locations; | ||
| 25 | + Size winStride = Size(0,0); | ||
| 26 | + Size padding = Size(0,0); | ||
| 27 | + foreach (const Mat &rect, src) { | ||
| 28 | + hog.compute(rect, descriptorVals, winStride, padding, locations); | ||
| 29 | + Mat HoGFeats(descriptorVals, true); | ||
| 30 | + dst += HoGFeats; | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +BR_REGISTER(Transform, HoGDescriptorTransform) | ||
| 36 | + | ||
| 37 | +} // namespace br | ||
| 38 | + | ||
| 39 | +#include "hogdescriptor.moc" |
openbr/plugins/representation/keypointdescriptor.cpp
0 → 100644
| 1 | +#include <opencv2/features2d/features2d.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Wraps OpenCV Key Point Descriptor | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class KeyPointDescriptorTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(QString descriptor READ get_descriptor WRITE set_descriptor RESET reset_descriptor STORED false) | ||
| 19 | + Q_PROPERTY(int size READ get_size WRITE set_size RESET reset_size STORED false) | ||
| 20 | + BR_PROPERTY(QString, descriptor, "SIFT") | ||
| 21 | + BR_PROPERTY(int, size, -1) | ||
| 22 | + | ||
| 23 | + Ptr<DescriptorExtractor> descriptorExtractor; | ||
| 24 | + | ||
| 25 | + void init() | ||
| 26 | + { | ||
| 27 | + descriptorExtractor = DescriptorExtractor::create(descriptor.toStdString()); | ||
| 28 | + if (descriptorExtractor.empty()) | ||
| 29 | + qFatal("Failed to create DescriptorExtractor: %s", qPrintable(descriptor)); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + void project(const Template &src, Template &dst) const | ||
| 33 | + { | ||
| 34 | + std::vector<KeyPoint> keyPoints; | ||
| 35 | + if (size == -1) | ||
| 36 | + foreach (const QRectF &ROI, src.file.rects()) | ||
| 37 | + keyPoints.push_back(KeyPoint(ROI.x()+ROI.width()/2, ROI.y()+ROI.height()/2, (ROI.width() + ROI.height())/2)); | ||
| 38 | + else | ||
| 39 | + foreach (const QPointF &landmark, src.file.points()) | ||
| 40 | + keyPoints.push_back(KeyPoint(landmark.x(), landmark.y(), size)); | ||
| 41 | + if (keyPoints.empty()) return; | ||
| 42 | + descriptorExtractor->compute(src, keyPoints, dst); | ||
| 43 | + } | ||
| 44 | +}; | ||
| 45 | + | ||
| 46 | +BR_REGISTER(Transform, KeyPointDescriptorTransform) | ||
| 47 | + | ||
| 48 | +} // namespace br | ||
| 49 | + | ||
| 50 | +#include "keypointdescriptor.moc" |
openbr/plugins/representation/siftdescriptor.cpp
0 → 100644
| 1 | +#include <opencv2/nonfree/nonfree.hpp> | ||
| 2 | + | ||
| 3 | +#include <openbr/plugins/openbr_internal.h> | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Specialize wrapper OpenCV SIFT wrapper | ||
| 13 | + * \author Josh Klontz \cite jklontz | ||
| 14 | + */ | ||
| 15 | +class SIFTDescriptorTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + Q_PROPERTY(int size READ get_size WRITE set_size RESET reset_size STORED false) | ||
| 19 | + Q_PROPERTY(QList<int> sizes READ get_sizes WRITE set_sizes RESET reset_sizes STORED false) | ||
| 20 | + Q_PROPERTY(int nFeatures READ get_nFeatures WRITE set_nFeatures RESET reset_nFeatures STORED false) | ||
| 21 | + Q_PROPERTY(int nOctaveLayers READ get_nOctaveLayers WRITE set_nOctaveLayers RESET reset_nOctaveLayers STORED false) | ||
| 22 | + Q_PROPERTY(double contrastThreshold READ get_contrastThreshold WRITE set_contrastThreshold RESET reset_contrastThreshold STORED false) | ||
| 23 | + Q_PROPERTY(double edgeThreshold READ get_edgeThreshold WRITE set_edgeThreshold RESET reset_edgeThreshold STORED false) | ||
| 24 | + Q_PROPERTY(double sigma READ get_sigma WRITE set_sigma RESET reset_sigma STORED false) | ||
| 25 | + BR_PROPERTY(int, size, 1) | ||
| 26 | + BR_PROPERTY(QList<int>, sizes, QList<int>()) | ||
| 27 | + BR_PROPERTY(int, nFeatures, 0) | ||
| 28 | + BR_PROPERTY(int, nOctaveLayers, 3) | ||
| 29 | + BR_PROPERTY(double, contrastThreshold, 0.04) | ||
| 30 | + BR_PROPERTY(double, edgeThreshold, 10) | ||
| 31 | + BR_PROPERTY(double, sigma, 1.6) | ||
| 32 | + | ||
| 33 | + SIFT sift; | ||
| 34 | + | ||
| 35 | + void init() | ||
| 36 | + { | ||
| 37 | + if (sizes.empty()) | ||
| 38 | + sizes.append(size); | ||
| 39 | + sift = SIFT(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + void project(const Template &src, Template &dst) const | ||
| 43 | + { | ||
| 44 | + std::vector<KeyPoint> keyPoints; | ||
| 45 | + foreach (const QPointF &val, src.file.points()) | ||
| 46 | + foreach (const int r, sizes) | ||
| 47 | + keyPoints.push_back(KeyPoint(val.x(), val.y(), r)); | ||
| 48 | + | ||
| 49 | + Mat m; | ||
| 50 | + sift(src, Mat(), keyPoints, m, true); | ||
| 51 | + m.setTo(0, m<0); // SIFT returns large negative values when it goes off the edge of the image. | ||
| 52 | + dst += m; | ||
| 53 | + } | ||
| 54 | +}; | ||
| 55 | + | ||
| 56 | +BR_REGISTER(Transform, SIFTDescriptorTransform) | ||
| 57 | + | ||
| 58 | +} // namespace br | ||
| 59 | + | ||
| 60 | +#include "siftdescriptor.moc" |
openbr/plugins/sentence.cpp deleted
| 1 | -#include <stdint.h> | ||
| 2 | -#include "openbr_internal.h" | ||
| 3 | - | ||
| 4 | -using namespace cv; | ||
| 5 | - | ||
| 6 | -namespace br | ||
| 7 | -{ | ||
| 8 | - | ||
| 9 | -/*! | ||
| 10 | - * \ingroup transforms | ||
| 11 | - * \brief Ordered words | ||
| 12 | - * \author Josh Klontz \cite jklontz | ||
| 13 | - */ | ||
| 14 | -class SentenceTransform : public UntrainableMetaTransform | ||
| 15 | -{ | ||
| 16 | - Q_OBJECT | ||
| 17 | - | ||
| 18 | - void project(const Template &src, Template &dst) const | ||
| 19 | - { | ||
| 20 | - QByteArray sentence; | ||
| 21 | - QDataStream stream(&sentence, QIODevice::WriteOnly); | ||
| 22 | - for (int i=0; i<src.size(); i++) { | ||
| 23 | - const Mat &m = src[i]; | ||
| 24 | - if (!m.data) continue; | ||
| 25 | - stream.writeRawData((const char*)&i, 4); | ||
| 26 | - stream.writeRawData((const char*)&m.rows, 4); | ||
| 27 | - stream.writeRawData((const char*)&m.cols, 4); | ||
| 28 | - stream.writeRawData((const char*)m.data, 4*m.rows*m.cols); | ||
| 29 | - } | ||
| 30 | - dst.file = src.file; | ||
| 31 | - dst.m() = Mat(1, sentence.size(), CV_8UC1, sentence.data()).clone(); | ||
| 32 | - } | ||
| 33 | -}; | ||
| 34 | - | ||
| 35 | -BR_REGISTER(Transform, SentenceTransform) | ||
| 36 | - | ||
| 37 | -/*! | ||
| 38 | - * \ingroup distances | ||
| 39 | - * \brief Distance between sentences | ||
| 40 | - * \author Josh Klontz \cite jklontz | ||
| 41 | - */ | ||
| 42 | -class SentenceSimilarityDistance : public UntrainableDistance | ||
| 43 | -{ | ||
| 44 | - Q_OBJECT | ||
| 45 | - | ||
| 46 | - float compare(const Mat &a, const Mat &b) const | ||
| 47 | - { | ||
| 48 | - uchar *aBuffer = a.data; | ||
| 49 | - uchar *bBuffer = b.data; | ||
| 50 | - const uchar *aEnd = aBuffer + a.cols; | ||
| 51 | - const uchar *bEnd = bBuffer + b.cols; | ||
| 52 | - | ||
| 53 | - int32_t aWord, bWord, aRows, bRows, aColumns, bColumns; | ||
| 54 | - float *aData, *bData; | ||
| 55 | - aWord = aRows = aColumns = -2; | ||
| 56 | - bWord = bRows = bColumns = -1; | ||
| 57 | - aData = bData = NULL; | ||
| 58 | - | ||
| 59 | - float distance = 0; | ||
| 60 | - int comparisons = 0; | ||
| 61 | - while (true) { | ||
| 62 | - if (aWord < bWord) { | ||
| 63 | - if (aBuffer == aEnd) return distance == 0 ? -std::numeric_limits<float>::max() : comparisons / distance; | ||
| 64 | - aWord = *reinterpret_cast<int32_t*>(aBuffer); | ||
| 65 | - aRows = *reinterpret_cast<int32_t*>(aBuffer+4); | ||
| 66 | - aColumns = *reinterpret_cast<int32_t*>(aBuffer+8); | ||
| 67 | - aData = reinterpret_cast<float*>(aBuffer+12); | ||
| 68 | - aBuffer += 12 + 4*aRows*aColumns; | ||
| 69 | - } else if (bWord < aWord) { | ||
| 70 | - if (bBuffer == bEnd) return comparisons == 0 ? -std::numeric_limits<float>::max() : comparisons / distance; | ||
| 71 | - bWord = *reinterpret_cast<int32_t*>(bBuffer); | ||
| 72 | - bRows = *reinterpret_cast<int32_t*>(bBuffer+4); | ||
| 73 | - bColumns = *reinterpret_cast<int32_t*>(bBuffer+8); | ||
| 74 | - bData = reinterpret_cast<float*>(bBuffer+12); | ||
| 75 | - bBuffer += 12 + 4*bRows*bColumns; | ||
| 76 | - } else { | ||
| 77 | - for (int i=0; i<aRows; i++) | ||
| 78 | - for (int j=0; j<bRows; j++) | ||
| 79 | - for (int k=0; k<aColumns; k++) | ||
| 80 | - distance += pow(aData[i*aColumns+k] - bData[j*bColumns+k], 2.f); | ||
| 81 | - comparisons += aRows * bRows * aColumns; | ||
| 82 | - aWord = -2; | ||
| 83 | - bWord = -1; | ||
| 84 | - } | ||
| 85 | - } | ||
| 86 | - } | ||
| 87 | -}; | ||
| 88 | - | ||
| 89 | -BR_REGISTER(Distance, SentenceSimilarityDistance) | ||
| 90 | - | ||
| 91 | -} // namespace br | ||
| 92 | - | ||
| 93 | -#include "sentence.moc" |
openbr/plugins/stasm4.cmake
openbr/plugins/frames.cpp renamed to openbr/plugins/video/aggregate.cpp
| 1 | -#include "openbr_internal.h" | 1 | +#include <openbr/plugins/openbr_internal.h> |
| 2 | 2 | ||
| 3 | namespace br | 3 | namespace br |
| 4 | { | 4 | { |
| @@ -56,33 +56,6 @@ private: | @@ -56,33 +56,6 @@ private: | ||
| 56 | 56 | ||
| 57 | BR_REGISTER(Transform, AggregateFrames) | 57 | BR_REGISTER(Transform, AggregateFrames) |
| 58 | 58 | ||
| 59 | -/*! | ||
| 60 | - * \ingroup transforms | ||
| 61 | - * \brief Only use one frame every n frames. | ||
| 62 | - * \author Austin Blanton \cite imaus10 | ||
| 63 | - * | ||
| 64 | - * For a video with m frames, DropFrames will pass on m/n frames. | ||
| 65 | - */ | ||
| 66 | -class DropFrames : public UntrainableMetaTransform | ||
| 67 | -{ | ||
| 68 | - Q_OBJECT | ||
| 69 | - Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | ||
| 70 | - BR_PROPERTY(int, n, 1) | ||
| 71 | - | ||
| 72 | - void project(const TemplateList &src, TemplateList &dst) const | ||
| 73 | - { | ||
| 74 | - if (src.first().file.get<int>("FrameNumber") % n != 0) return; | ||
| 75 | - dst = src; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - void project(const Template &src, Template &dst) const | ||
| 79 | - { | ||
| 80 | - (void) src; (void) dst; qFatal("shouldn't be here"); | ||
| 81 | - } | ||
| 82 | -}; | ||
| 83 | - | ||
| 84 | -BR_REGISTER(Transform, DropFrames) | ||
| 85 | - | ||
| 86 | } // namespace br | 59 | } // namespace br |
| 87 | 60 | ||
| 88 | -#include "frames.moc" | 61 | +#include "aggregate.moc" |
openbr/plugins/video/drop.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +namespace br | ||
| 4 | +{ | ||
| 5 | + | ||
| 6 | +/*! | ||
| 7 | + * \ingroup transforms | ||
| 8 | + * \brief Only use one frame every n frames. | ||
| 9 | + * \author Austin Blanton \cite imaus10 | ||
| 10 | + * | ||
| 11 | + * For a video with m frames, DropFrames will pass on m/n frames. | ||
| 12 | + */ | ||
| 13 | +class DropFrames : public UntrainableMetaTransform | ||
| 14 | +{ | ||
| 15 | + Q_OBJECT | ||
| 16 | + Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false) | ||
| 17 | + BR_PROPERTY(int, n, 1) | ||
| 18 | + | ||
| 19 | + void project(const TemplateList &src, TemplateList &dst) const | ||
| 20 | + { | ||
| 21 | + if (src.first().file.get<int>("FrameNumber") % n != 0) return; | ||
| 22 | + dst = src; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + void project(const Template &src, Template &dst) const | ||
| 26 | + { | ||
| 27 | + (void) src; (void) dst; qFatal("shouldn't be here"); | ||
| 28 | + } | ||
| 29 | +}; | ||
| 30 | + | ||
| 31 | +BR_REGISTER(Transform, DropFrames) | ||
| 32 | + | ||
| 33 | +} // namespace br | ||
| 34 | + | ||
| 35 | +#include "drop.moc" |