Commit dff3e093aaf2c596d4220c2cc34769c46e2edcdd
1 parent
5c945c17
Update to Caffe framework
Showing
4 changed files
with
76 additions
and
55 deletions
openbr/plugins/classification/caffe.cpp
| 1 | #include <openbr/plugins/openbr_internal.h> | 1 | #include <openbr/plugins/openbr_internal.h> |
| 2 | +#include <openbr/core/opencvutils.h> | ||
| 3 | +#include <openbr/core/qtutils.h> | ||
| 2 | 4 | ||
| 5 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 3 | #include <caffe/caffe.hpp> | 6 | #include <caffe/caffe.hpp> |
| 4 | 7 | ||
| 5 | using caffe::Caffe; | 8 | using caffe::Caffe; |
| 6 | -using caffe::Solver; | ||
| 7 | using caffe::Net; | 9 | using caffe::Net; |
| 10 | +using caffe::MemoryDataLayer; | ||
| 8 | using caffe::Blob; | 11 | using caffe::Blob; |
| 9 | using caffe::shared_ptr; | 12 | using caffe::shared_ptr; |
| 10 | -using caffe::vector; | 13 | + |
| 14 | +using namespace cv; | ||
| 11 | 15 | ||
| 12 | namespace br | 16 | namespace br |
| 13 | { | 17 | { |
| 14 | 18 | ||
| 15 | /*! | 19 | /*! |
| 16 | - * \brief A transform that wraps the Caffe Deep learning library | 20 | + * \brief A transform that wraps the Caffe deep learning library. This transform expects the input to a given Caffe model to be a MemoryDataLayer. |
| 21 | + * The output of the Caffe network is treated as a feature vector and is stored in dst. Batch processing is possible. For a given batch size set in | ||
| 22 | + * the memory data layer, src is expected to have an equal number of mats. Dst will always have the same size (number of mats) as src and the ordering | ||
| 23 | + * will be preserved, so dst[1] is the output of src[1] after it passes through the | ||
| 17 | * \author Jordan Cheney \cite jcheney | 24 | * \author Jordan Cheney \cite jcheney |
| 18 | - * \br_property QString modelFile path to prototxt model file | ||
| 19 | - * \br_property QString solverFile path to prototxt solver file | ||
| 20 | - * \br_property QString weightsFile path to caffemodel file | 25 | + * \br_property QString model path to prototxt model file |
| 26 | + * \br_property QString weights path to caffemodel file | ||
| 21 | * \br_property int gpuDevice ID of GPU to use. gpuDevice < 0 runs on the CPU only. | 27 | * \br_property int gpuDevice ID of GPU to use. gpuDevice < 0 runs on the CPU only. |
| 22 | * \br_link Caffe Integration Tutorial ../tutorials.md#caffe | 28 | * \br_link Caffe Integration Tutorial ../tutorials.md#caffe |
| 23 | * \br_link Caffe website http://caffe.berkeleyvision.org | 29 | * \br_link Caffe website http://caffe.berkeleyvision.org |
| 24 | */ | 30 | */ |
| 25 | -class CaffeTransform : public Transform | 31 | +class CaffeFVTransform : public UntrainableTransform |
| 26 | { | 32 | { |
| 27 | Q_OBJECT | 33 | Q_OBJECT |
| 28 | 34 | ||
| 29 | - Q_PROPERTY(QString modelFile READ get_modelFile WRITE set_modelFile RESET reset_modelFile STORED false) | ||
| 30 | - Q_PROPERTY(QString solverFile READ get_solverFile WRITE set_solverFile RESET reset_solverFile STORED false) | ||
| 31 | - Q_PROPERTY(QString weightsFile READ get_weightsFile WRITE set_weightsFile RESET reset_weightsFile STORED false) | 35 | + Q_PROPERTY(QString model READ get_model WRITE set_model RESET reset_model STORED false) |
| 36 | + Q_PROPERTY(QString weights READ get_weights WRITE set_weights RESET reset_weights STORED false) | ||
| 32 | Q_PROPERTY(int gpuDevice READ get_gpuDevice WRITE set_gpuDevice RESET reset_gpuDevice STORED false) | 37 | Q_PROPERTY(int gpuDevice READ get_gpuDevice WRITE set_gpuDevice RESET reset_gpuDevice STORED false) |
| 33 | - BR_PROPERTY(QString, modelFile, "") | ||
| 34 | - BR_PROPERTY(QString, solverFile, "") | ||
| 35 | - BR_PROPERTY(QString, weightsFile, "") | 38 | + BR_PROPERTY(QString, model, "") |
| 39 | + BR_PROPERTY(QString, weights, "") | ||
| 36 | BR_PROPERTY(int, gpuDevice, -1) | 40 | BR_PROPERTY(int, gpuDevice, -1) |
| 37 | 41 | ||
| 42 | + QSharedPointer<Net<float> > net; | ||
| 43 | + | ||
| 38 | void init() | 44 | void init() |
| 39 | { | 45 | { |
| 40 | if (gpuDevice >= 0) { | 46 | if (gpuDevice >= 0) { |
| @@ -43,47 +49,31 @@ class CaffeTransform : public Transform | @@ -43,47 +49,31 @@ class CaffeTransform : public Transform | ||
| 43 | } else { | 49 | } else { |
| 44 | Caffe::set_mode(Caffe::CPU); | 50 | Caffe::set_mode(Caffe::CPU); |
| 45 | } | 51 | } |
| 52 | + | ||
| 53 | + net.reset(new Net<float>(model.toStdString(), caffe::TEST)); | ||
| 54 | + net->CopyTrainedLayersFrom(weights.toStdString()); | ||
| 46 | } | 55 | } |
| 47 | 56 | ||
| 48 | - void train(const TemplateList &data) | 57 | + void project(const Template &src, Template &dst) const |
| 49 | { | 58 | { |
| 50 | - (void) data; | 59 | + MemoryDataLayer<float> *data_layer = static_cast<MemoryDataLayer<float> *>(net->layers()[0].get()); |
| 51 | 60 | ||
| 52 | - caffe::SolverParameter solver_param; | ||
| 53 | - caffe::ReadProtoFromTextFileOrDie(solverFile.toStdString(), &solver_param); | 61 | + if (src.size() != data_layer->batch_size()) |
| 62 | + qFatal("src should have %d (batch size) mats. It has %d mats.", data_layer->batch_size(), src.size()); | ||
| 54 | 63 | ||
| 55 | - shared_ptr<Solver<float> > solver(caffe::GetSolver<float>(solver_param)); | ||
| 56 | - solver->Solve(); | ||
| 57 | - } | 64 | + dst.file = src.file; |
| 58 | 65 | ||
| 59 | - void project(const Template &src, Template &dst) const | ||
| 60 | - { | ||
| 61 | - (void)src; (void)dst; | ||
| 62 | - Net<float> net(modelFile.toStdString(), caffe::TEST); | ||
| 63 | - net.CopyTrainedLayersFrom(weightsFile.toStdString()); | ||
| 64 | - | ||
| 65 | - vector<Blob<float> *> bottom_vec; // perhaps src data should go here? | ||
| 66 | - vector<int> test_score_output_id; | ||
| 67 | - vector<float> test_score; | ||
| 68 | - | ||
| 69 | - float loss; | ||
| 70 | - const vector<Blob<float> *> &result = net.Forward(bottom_vec, &loss); | ||
| 71 | - | ||
| 72 | - int idx = 0; | ||
| 73 | - for (int i = 0; i < (int)result.size(); i++) { | ||
| 74 | - const float *result_data = result[i]->cpu_data(); | ||
| 75 | - for (int j = 0; j < result[i]->count(); j++, idx++) { | ||
| 76 | - test_score.push_back(result_data[j]); | ||
| 77 | - test_score_output_id.push_back(i); | ||
| 78 | - | ||
| 79 | - if (Globals->verbose) | ||
| 80 | - qDebug("%s = %f", net.blob_names()[net.output_blob_indices()[i]].c_str(), result_data[j]); | ||
| 81 | - } | ||
| 82 | - } | 66 | + data_layer->AddMatVector(src.toVector().toStdVector(), std::vector<int>(src.size(), 0)); |
| 67 | + | ||
| 68 | + Blob<float> *output = net->ForwardPrefilled()[1]; // index 0 is the labels from the data layer (in this case the 0 array we passed in above). | ||
| 69 | + // index 1 is the ouput of the final layer, which is what we want | ||
| 70 | + int dim_features = output->count() / data_layer->batch_size(); | ||
| 71 | + for (int n = 0; n < data_layer->batch_size(); n++) | ||
| 72 | + dst += Mat(1, dim_features, CV_32FC1, output->mutable_cpu_data() + output->offset(n)); | ||
| 83 | } | 73 | } |
| 84 | }; | 74 | }; |
| 85 | 75 | ||
| 86 | -BR_REGISTER(Transform, CaffeTransform) | 76 | +BR_REGISTER(Transform, CaffeFVTransform) |
| 87 | 77 | ||
| 88 | } // namespace br | 78 | } // namespace br |
| 89 | 79 |
openbr/plugins/cmake/lmdbGallery.cmake deleted
| 1 | -set(BR_WITH_CAFFE OFF CACHE BOOL "Build with Caffe") | ||
| 2 | - | ||
| 3 | -if (${BR_WITH_CAFFE}) | ||
| 4 | - find_package(Caffe) | ||
| 5 | - set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Caffe_LIBRARIES}) | ||
| 6 | - include_directories(${Caffe_INCLUDE_DIRS}) | ||
| 7 | -else() | ||
| 8 | - set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/lmdbGallery.cpp) | ||
| 9 | -endif() | ||
| 10 | - |
openbr/plugins/imgproc/pad.cpp
0 → 100644
| 1 | +#include <openbr/plugins/openbr_internal.h> | ||
| 2 | + | ||
| 3 | +using namespace cv; | ||
| 4 | + | ||
| 5 | +namespace br | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +class PadTransform : public UntrainableTransform | ||
| 9 | +{ | ||
| 10 | + Q_OBJECT | ||
| 11 | + | ||
| 12 | + Q_PROPERTY(int padSize READ get_padSize WRITE set_padSize RESET reset_padSize STORED false) | ||
| 13 | + Q_PROPERTY(int padValue READ get_padValue WRITE set_padValue RESET reset_padValue STORED false) | ||
| 14 | + BR_PROPERTY(int, padSize, 0) | ||
| 15 | + BR_PROPERTY(int, padValue, 0) | ||
| 16 | + | ||
| 17 | + void project(const Template &src, Template &dst) const | ||
| 18 | + { | ||
| 19 | + dst.file = src.file; | ||
| 20 | + | ||
| 21 | + foreach (const Mat &m, src) { | ||
| 22 | + Mat padded = padValue * Mat::ones(m.rows + 2*padSize, m.cols + 2*padSize, m.type()); | ||
| 23 | + padded(Rect(padSize, padSize, padded.cols - padSize, padded.rows - padSize)) = m; | ||
| 24 | + dst += padded; | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +BR_REGISTER(Transform, PadTransform) | ||
| 30 | + | ||
| 31 | +} // namespace br | ||
| 32 | + | ||
| 33 | +#include "imgproc/pad.moc" |
openbr/plugins/imgproc/roi.cpp
| @@ -26,12 +26,16 @@ namespace br | @@ -26,12 +26,16 @@ namespace br | ||
| 26 | * \ingroup transforms | 26 | * \ingroup transforms |
| 27 | * \brief Crops the rectangular regions of interest. | 27 | * \brief Crops the rectangular regions of interest. |
| 28 | * \author Josh Klontz \cite jklontz | 28 | * \author Josh Klontz \cite jklontz |
| 29 | + * \br_property QString propName Optional property name for a rectangle in metadata. If no propName is given the transform will use rects stored in the file.rects field or build a rectangle using "X", "Y", "Width", and "Height" fields if they exist. | ||
| 30 | + * \br_property bool copyOnCrop If true make a clone of each crop before appending the crop to dst. This guarantees that the crops will be continuous in memory, which is an occasionally useful property. Default is false. | ||
| 29 | */ | 31 | */ |
| 30 | class ROITransform : public UntrainableTransform | 32 | class ROITransform : public UntrainableTransform |
| 31 | { | 33 | { |
| 32 | Q_OBJECT | 34 | Q_OBJECT |
| 33 | Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) | 35 | Q_PROPERTY(QString propName READ get_propName WRITE set_propName RESET reset_propName STORED false) |
| 36 | + Q_PROPERTY(bool copyOnCrop READ get_copyOnCrop WRITE set_copyOnCrop RESET reset_copyOnCrop STORED false) | ||
| 34 | BR_PROPERTY(QString, propName, "") | 37 | BR_PROPERTY(QString, propName, "") |
| 38 | + BR_PROPERTY(bool, copyOnCrop, false) | ||
| 35 | 39 | ||
| 36 | void project(const Template &src, Template &dst) const | 40 | void project(const Template &src, Template &dst) const |
| 37 | { | 41 | { |
| @@ -52,6 +56,10 @@ class ROITransform : public UntrainableTransform | @@ -52,6 +56,10 @@ class ROITransform : public UntrainableTransform | ||
| 52 | qWarning("No rects present in file."); | 56 | qWarning("No rects present in file."); |
| 53 | } | 57 | } |
| 54 | dst.file.clearRects(); | 58 | dst.file.clearRects(); |
| 59 | + | ||
| 60 | + if (copyOnCrop) | ||
| 61 | + for (int i = 0; i < dst.size(); i++) | ||
| 62 | + dst.replace(i, dst[i].clone()); | ||
| 55 | } | 63 | } |
| 56 | }; | 64 | }; |
| 57 | 65 |