Commit dff3e093aaf2c596d4220c2cc34769c46e2edcdd

Authored by Jordan Cheney
1 parent 5c945c17

Update to Caffe framework

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