Commit b34029cc89b22994e6464b16479488ee7a775525
1 parent
f645840e
Incremental progress for plugins reorg
Showing
113 changed files
with
5111 additions
and
4674 deletions
Too many changes.
To preserve performance only 100 of 113 files are displayed.
openbr/plugins/ebif.cpp renamed to openbr/plugins/classification/ebif.cpp
| 1 | 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 | 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 | 4 | using namespace cv; |
| 25 | 5 | |
| ... | ... | @@ -28,58 +8,6 @@ namespace br |
| 28 | 8 | |
| 29 | 9 | /*! |
| 30 | 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 | 11 | * \brief K nearest neighbors classifier. |
| 84 | 12 | * \author Josh Klontz \cite jklontz |
| 85 | 13 | */ |
| ... | ... | @@ -151,148 +79,6 @@ class KNNTransform : public Transform |
| 151 | 79 | |
| 152 | 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 | 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
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 | 3 | namespace br |
| 10 | 4 | { |
| ... | ... | @@ -103,10 +97,10 @@ class DownsampleTrainingTransform : public Transform |
| 103 | 97 | |
| 104 | 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 | 104 | void train(const TemplateList &data) |
| 111 | 105 | { |
| 112 | 106 | if (!transform || !transform->trainable) |
| ... | ... | @@ -117,274 +111,9 @@ class DownsampleTrainingTransform : public Transform |
| 117 | 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 | 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 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <opencv2/objdetect/objdetect.hpp> |
| 18 | -#include "openbr_internal.h" | |
| 18 | +#include <openbr/plugins/openbr_internal.h> | |
| 19 | 19 | #include "openbr/core/opencvutils.h" |
| 20 | 20 | #include "openbr/core/resource.h" |
| 21 | 21 | #include "openbr/core/qtutils.h" | ... | ... |
openbr/plugins/eyes.cpp renamed to openbr/plugins/detection/eyes.cpp
| ... | ... | @@ -35,8 +35,9 @@ |
| 35 | 35 | |
| 36 | 36 | #include <opencv2/imgproc/imgproc.hpp> |
| 37 | 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 | 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 | 652 | |
| 653 | 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 | 655 | } // namespace br |
| 696 | 656 | |
| 697 | 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 | 928 | |
| 929 | 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 | 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
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 | 3 | using namespace cv; |
| 23 | 4 | |
| ... | ... | @@ -26,52 +7,10 @@ namespace br |
| 26 | 7 | |
| 27 | 8 | /*! |
| 28 | 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 | 10 | * \brief Quantizes the values into bins. |
| 72 | 11 | * \author Josh Klontz \cite jklontz |
| 73 | 12 | */ |
| 74 | -class BinTransform : public UntrainableTransform | |
| 13 | +class HistBinTransform : public UntrainableTransform | |
| 75 | 14 | { |
| 76 | 15 | Q_OBJECT |
| 77 | 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 | 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 | 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 | 5 | using namespace cv; |
| 9 | 6 | |
| ... | ... | @@ -12,23 +9,6 @@ namespace br |
| 12 | 9 | |
| 13 | 10 | /*! |
| 14 | 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 | 12 | * \brief Sliding window feature extraction from a multi-channel integral image. |
| 33 | 13 | * \author Josh Klontz \cite jklontz |
| 34 | 14 | */ |
| ... | ... | @@ -121,254 +101,6 @@ class IntegralSamplerTransform : public UntrainableTransform |
| 121 | 101 | |
| 122 | 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 | 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 | 498 | |
| 499 | 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 | 526 | * \ingroup transforms |
| 503 | 527 | * \brief Normalize points to be relative to a single point | ... | ... |
openbr/plugins/lbp.cpp
| ... | ... | @@ -46,8 +46,6 @@ class LBPTransform : public UntrainableTransform |
| 46 | 46 | uchar lut[256]; |
| 47 | 47 | uchar null; |
| 48 | 48 | |
| 49 | - friend class ColoredU2Transform; | |
| 50 | - | |
| 51 | 49 | /* Returns the number of 0->1 or 1->0 transitions in i */ |
| 52 | 50 | static int numTransitions(int i) |
| 53 | 51 | { |
| ... | ... | @@ -125,74 +123,6 @@ class LBPTransform : public UntrainableTransform |
| 125 | 123 | |
| 126 | 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 | 126 | } // namespace br |
| 197 | 127 | |
| 198 | 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" | ... | ... |