Commit 12bdc2af authored by Vladislav Sovrasov's avatar Vladislav Sovrasov

dnn_modern: update docs, fix build problems

parent 63f6f18f
......@@ -15,6 +15,23 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
# MODULE REQUIREMENTS
# ----------------------------------------------------------------------------
set(TINY_DNN_CPP_PATH "${OpenCV_BINARY_DIR}/3rdparty/tinydnn")
set(TINY_DNN_CPP_ROOT "${TINY_DNN_CPP_PATH}/tiny-dnn-1.0.0a3")
ocv_download(FILENAME "v1.0.0a3.tar.gz"
HASH "adb1c512e09ca2c7a6faef36f9c53e59"
URL
"${OPENCV_TINY_DNN_URL}"
"$ENV{OPENCV_TINY_DNN_URL}"
"https://github.com/tiny-dnn/tiny-dnn/archive/"
DESTINATION_DIR "${TINY_DNN_CPP_PATH}"
STATUS TINY_DNN_DOWNLOAD_SUCCESS
ID "tiny-dnn"
UNPACK RELATIVE_URL)
if(NOT TINY_DNN_DOWNLOAD_SUCCESS)
message(STATUS "Failed to download tiny-dnn sources")
endif()
find_package(TinyDNN QUIET)
include(CheckCXXCompilerFlag)
......@@ -59,12 +76,22 @@ if(TINYDNN_USE_NNPACK)
list(APPEND REQUIRED_LIBRARIES ${NNPACK_LIB})
endif()
# we need to disable seializer unless we import cereal
add_definitions(-DCNN_NO_SERIALIZATION)
# we need to disable seializer unless we import cereal and we gonna use caffe converter
add_definitions(-DCNN_NO_SERIALIZATION -DCNN_USE_CAFFE_CONVERTER)
# NOTE: In case that proto files already exist,
# this is not needed anymore.
find_package(Protobuf)
find_package(Protobuf QUIET)
if(DEFINED PROTOBUF_PROTOC_EXECUTABLE AND EXISTS ${PROTOBUF_PROTOC_EXECUTABLE})
execute_process(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} caffe.proto --cpp_out=./
WORKING_DIRECTORY ${TINYDNN_INCLUDE_DIRS}/tiny_dnn/io/caffe)
else()
message(STATUS "The protocol buffer compiler is not found (PROTOBUF_PROTOC_EXECUTABLE='${PROTOBUF_PROTOC_EXECUTABLE}')")
ocv_module_disable(dnn_modern)
return()
endif()
list(APPEND REQUIRED_LIBRARIES ${PROTOBUF_LIBRARIES})
####
......@@ -76,7 +103,6 @@ list(APPEND REQUIRED_LIBRARIES ${PROTOBUF_LIBRARIES})
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
message(STATUS "C++11 support has been enabled by default.")
# Unix
if(CMAKE_COMPILER_IS_GNUCXX OR MINGW OR
......@@ -138,7 +164,9 @@ endif()
# DNN-MODERN MODULE
# ----------------------------------------------------------------------------
ocv_define_module(dnn_modern opencv_core opencv_imgproc opencv_imgcodecs WRAP python)
ocv_define_module(dnn_modern opencv_core opencv_imgproc WRAP python)
ocv_target_link_libraries(${the_module} ${REQUIRED_LIBRARIES})
ocv_target_include_directories(${the_module} ${TINYDNN_INCLUDE_DIRS})
target_compile_options(${the_module} PRIVATE "-Wno-error=non-virtual-dtor")
ocv_warnings_disable(CMAKE_CXX_FLAGS
-Wnon-virtual-dtor -Wunused-parameter -Wshadow -Wundef
/wd4265 /wd4100 /wd4458 /wd4244 /wd4456)
Modern Deep Learning Module
===========================
The module is wrapper to [tiny-dnn](https://github.com/tiny-dnn/tiny-dnn)
A header only, dependency-free deep learning framework in C++11
The module is wrapper to [tiny-dnn](https://github.com/tiny-dnn/tiny-dnn),
a header only, dependency-free deep learning framework in C++11.
Installation
------------
......@@ -12,19 +11,24 @@ Installation
- System under Unix or Windows
- C++11 compiler
- tiny-dnn headers
- protoc compiler (part of the [protobuf](https://developers.google.com/protocol-buffers/docs/overview) library)
**How to install tiny-dnn?**
CMake will try to download a certain version of tiny-dnn which was tested to build with OpenCV.
If the latest version is needed, location of the tiny-dnn folder can be specified manually:
Download tiny-dnn project somewhere in your system
- Download tiny-dnn project somewhere in your system
```
cd /opt
git clone https://github.com/tiny-dnn/tiny-dnn.git
```
Run your OpenCV CMake pointing to your tiny-dnn headers location
- Run your OpenCV CMake pointing to your tiny-dnn headers location
```
cd /opt/opencv/build
cmake -DTINYDNN_ROOT=/opt/tiny-dnn ..
make -j4
```
**Extra**
......@@ -42,3 +46,5 @@ Installation
Check project site for installation: [https://github.com/Maratyszcza/NNPACK](https://github.com/Maratyszcza/NNPACK)
cmake -DTINYDNN_USE_NNPACK=ON .. // not supported yet for Caffe loader
See detailed module API documentation in http://docs.opencv.org/trunk/d1/df7/group__dnn__modern.html
......@@ -19,6 +19,7 @@ set(TINYDNN_INCLUDE_SEARCH_PATHS
$ENV{TINYDNN_ROOT}
${TINYDNN_ROOT}
${TINYDNN_ROOT}/tiny_dnn
${TINY_DNN_CPP_ROOT}
)
find_path(TINYDNN_INCLUDE_DIR
......
......@@ -46,25 +46,33 @@
#define __OPENCV_DNN_M_HPP__
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
/** @defgroup dnn_modern Deep Learning Modern Module
@{
Base class for tiny-dnn converter
@}
* This module is based on the [tiny-dnn](https://github.com/tiny-dnn/tiny-dnn) framework.
* The module uses tiny-dnn to load and run pre-trained Caffe models.
* tiny-dnn's converter only supports single input/single output network without branches.
*/
namespace cv {
namespace dnn2 {
//! @addtogroup dnn_modern
//! @{
/** @brief Base class for tiny-dnn converter.
*/
class CV_EXPORTS_W BaseConverter
{
public:
virtual ~BaseConverter() {};
virtual void eval(const cv::InputArray image, std::vector<float_t>* results) = 0;
/**
@brief Evaluates single model output on single model input.
@param image input image.
@param results output form model.
*/
CV_WRAP virtual void eval(InputArray image, std::vector<float>& results) = 0;
};
/** @brief Class implementing the CaffeConverter.
......@@ -77,20 +85,22 @@ class CV_EXPORTS_W CaffeConverter : public BaseConverter {
public:
/**
@param model_file path to the prototxt file.
@param trained_file path to the caffemodel file.
@param mean_file path to binaryproto file.
@brief Creates a CaffeConverter object.
@param model_file path to the prototxt file.
@param trained_file path to the caffemodel file.
@param mean_file path to binaryproto file.
*/
CV_WRAP static Ptr<CaffeConverter> create(const cv::String& model_file,
const cv::String& trained_file,
const cv::String& mean_file=cv::String());
CV_WRAP static Ptr<CaffeConverter> create(const String& model_file,
const String& trained_file,
const String& mean_file = String());
virtual void eval(const cv::InputArray image, std::vector<float_t>* results) = 0;
CV_WRAP virtual void eval(InputArray image, CV_OUT std::vector<float>& results) = 0;
};
//! @}
} // namespace dnn2
} // namespace cv
#endif
/* End of file. */
#include <opencv2/dnn_modern.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
using namespace cv::dnn2;
......@@ -79,7 +81,7 @@ int main(int argc, char* argv[]) {
// inference !
vector<float_t> scores;
caffe_ptr->eval(img, &scores);
caffe_ptr->eval(img, scores);
// retrieve n labels
const int n = 5;
......
......@@ -43,9 +43,10 @@
*/
#include "precomp.hpp"
#include <opencv2/imgproc.hpp>
#define CNN_USE_CAFFE_CONVERTER
#include <tiny_dnn/tiny_dnn.h>
#include <tiny_dnn/io/caffe/caffe.pb.cc>
using namespace tiny_dnn;
using namespace tiny_dnn::activation;
......@@ -59,9 +60,9 @@ namespace dnn2 {
*/
class CaffeConverter_Impl : public CaffeConverter {
public:
explicit CaffeConverter_Impl(const cv::String& model_file,
const cv::String& trained_file,
const cv::String& mean_file) {
explicit CaffeConverter_Impl(const String& model_file,
const String& trained_file,
const String& mean_file) {
net_ = create_net_from_caffe_prototxt(model_file);
reload_weight_from_caffe_protobinary(trained_file, net_.get());
......@@ -73,31 +74,31 @@ class CaffeConverter_Impl : public CaffeConverter {
~CaffeConverter_Impl() {}
virtual void eval(const cv::InputArray image, std::vector<float>* results);
virtual void eval(InputArray image, std::vector<float>& results);
private:
cv::Mat compute_mean(const string& mean_file, const size_t width,
Mat compute_mean(const string& mean_file, const size_t width,
const size_t height);
cv::ColorConversionCodes get_cvt_codes(const int src_channels,
ColorConversionCodes get_cvt_codes(const int src_channels,
const int dst_channels);
void preprocess(const cv::Mat& img, const cv::Mat& mean,
const int num_channels, const cv::Size& geometry,
vector<cv::Mat>* input_channels);
void preprocess(const Mat& img, const Mat& mean,
const int num_channels, const Size& geometry,
vector<Mat>* input_channels);
cv::Mat mean_;
Mat mean_;
std::shared_ptr<network<sequential>> net_;
};
cv::Mat
Mat
CaffeConverter_Impl::compute_mean(const string& mean_file,
const size_t width,
const size_t height) {
caffe::BlobProto blob;
::detail::read_proto_from_binary(mean_file, &blob);
vector<cv::Mat> channels;
vector<Mat> channels;
auto data = blob.mutable_data()->mutable_data();
const size_t offset = blob.height() * blob.width();
......@@ -106,69 +107,69 @@ CaffeConverter_Impl::compute_mean(const string& mean_file,
channels.emplace_back(blob.height(), blob.width(), CV_32FC1, data);
}
cv::Mat mean;
cv::merge(channels, mean);
Mat meanChannel;
merge(channels, meanChannel);
return cv::Mat(cv::Size(width, height), mean.type(), cv::mean(mean));
return Mat(Size(width, height), meanChannel.type(), mean(meanChannel));
}
cv::ColorConversionCodes
ColorConversionCodes
CaffeConverter_Impl::get_cvt_codes(const int src_channels,
const int dst_channels) {
assert(src_channels != dst_channels);
if (dst_channels == 3) {
return src_channels == 1 ? cv::COLOR_GRAY2BGR : cv::COLOR_BGRA2BGR;
return src_channels == 1 ? COLOR_GRAY2BGR : COLOR_BGRA2BGR;
} else if (dst_channels == 1) {
return src_channels == 3 ? cv::COLOR_BGR2GRAY : cv::COLOR_BGRA2GRAY;
return src_channels == 3 ? COLOR_BGR2GRAY : COLOR_BGRA2GRAY;
} else {
throw runtime_error("unsupported color code");
}
}
void CaffeConverter_Impl::preprocess(const cv::Mat& img,
const cv::Mat& mean,
void CaffeConverter_Impl::preprocess(const Mat& img,
const Mat& mean,
const int num_channels,
const cv::Size& geometry,
vector<cv::Mat>* input_channels) {
cv::Mat sample;
const Size& geometry,
vector<Mat>* input_channels) {
Mat sample;
// convert color
if (img.channels() != num_channels) {
cv::cvtColor(img, sample,
cvtColor(img, sample,
get_cvt_codes(img.channels(), num_channels));
} else {
sample = img;
}
// resize
cv::Mat sample_resized;
cv::resize(sample, sample_resized, geometry);
Mat sample_resized;
resize(sample, sample_resized, geometry);
cv::Mat sample_float;
Mat sample_float;
sample_resized.convertTo(sample_float,
num_channels == 3 ? CV_32FC3 : CV_32FC1);
// subtract mean
if (mean.size().width > 0) {
cv::Mat sample_normalized;
cv::subtract(sample_float, mean, sample_normalized);
cv::split(sample_normalized, *input_channels);
Mat sample_normalized;
subtract(sample_float, mean, sample_normalized);
split(sample_normalized, *input_channels);
}
else {
cv::split(sample_float, *input_channels);
split(sample_float, *input_channels);
}
}
void CaffeConverter_Impl::eval(const cv::InputArray image,
std::vector<float>* results) {
const cv::Mat img = image.getMat();
void CaffeConverter_Impl::eval(InputArray image,
std::vector<float>& results) {
const Mat img = image.getMat();
const size_t channels = (*net_)[0]->in_data_shape()[0].depth_;
const size_t width = (*net_)[0]->in_data_shape()[0].width_;
const size_t height = (*net_)[0]->in_data_shape()[0].height_;
vector<cv::Mat> input_channels;
vector<Mat> input_channels;
vector<float> inputvec(width*height*channels);
for (size_t i = 0; i < channels; i++) {
......@@ -177,7 +178,7 @@ void CaffeConverter_Impl::eval(const cv::InputArray image,
}
// subtract mean from input
preprocess(img, mean_, 3, cv::Size(width, height), &input_channels);
preprocess(img, mean_, 3, Size(width, height), &input_channels);
const vector<tiny_dnn::float_t> vec(inputvec.begin(), inputvec.end());
......@@ -185,17 +186,17 @@ void CaffeConverter_Impl::eval(const cv::InputArray image,
auto result = net_->predict(vec);
// allocate output
results->clear();
results->reserve(result.size());
results.clear();
results.reserve(result.size());
for (size_t i = 0; i < result.size(); i++) {
results->push_back(result[i]);
results.push_back(result[i]);
}
}
Ptr<CaffeConverter> CaffeConverter::create(const cv::String& model_file,
const cv::String& trained_file,
const cv::String& mean_file) {
Ptr<CaffeConverter> CaffeConverter::create(const String& model_file,
const String& trained_file,
const String& mean_file) {
return makePtr<CaffeConverter_Impl>(model_file, trained_file, mean_file);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment