Skip to content

Commit 7e680bd

Browse files
committed
Merge pull request opencv#10215 from dkurt:dnn_js
2 parents 766a0c0 + f503515 commit 7e680bd

File tree

14 files changed

+326
-57
lines changed

14 files changed

+326
-57
lines changed

3rdparty/protobuf/src/google/protobuf/stubs/port.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,7 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF);
224224

225225
#if defined(__clang__) && defined(__has_cpp_attribute) \
226226
&& !defined(GOOGLE_PROTOBUF_OS_APPLE)
227-
# if defined(GOOGLE_PROTOBUF_OS_NACL) || defined(EMSCRIPTEN) || \
228-
__has_cpp_attribute(clang::fallthrough)
227+
# if defined(GOOGLE_PROTOBUF_OS_NACL) || __has_cpp_attribute(clang::fallthrough)
229228
# define GOOGLE_FALLTHROUGH_INTENDED [[clang::fallthrough]]
230229
# endif
231230
#endif
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# How to run deep networks in browser {#tutorial_dnn_javascript}
2+
3+
## Introduction
4+
This tutorial will show us how to run deep learning models using OpenCV.js right
5+
in a browser. Tutorial refers a sample of face detection and face recognition
6+
models pipeline.
7+
8+
## Face detection
9+
Face detection network gets BGR image as input and produces set of bounding boxes
10+
that might contain faces. All that we need is just select the boxes with a strong
11+
confidence.
12+
13+
## Face recognition
14+
Network is called OpenFace (project https://github.com/cmusatyalab/openface).
15+
Face recognition model receives RGB face image of size `96x96`. Then it returns
16+
`128`-dimensional unit vector that represents input face as a point on the unit
17+
multidimensional sphere. So difference between two faces is an angle between two
18+
output vectors.
19+
20+
## Sample
21+
All the sample is an HTML page that has JavaScript code to use OpenCV.js functionality.
22+
You may see an insertion of this page below. Press `Start` button to begin a demo.
23+
Press `Add a person` to name a person that is recognized as an unknown one.
24+
Next we'll discuss main parts of the code.
25+
26+
@htmlinclude js_face_recognition.html
27+
28+
-# Run face detection network to detect faces on input image.
29+
@snippet dnn/js_face_recognition.html Run face detection model
30+
You may play with input blob sizes to balance detection quality and efficiency.
31+
The bigger input blob the smaller faces may be detected.
32+
33+
-# Run face recognition network to receive `128`-dimensional unit feature vector by input face image.
34+
@snippet dnn/js_face_recognition.html Get 128 floating points feature vector
35+
36+
-# Perform a recognition.
37+
@snippet dnn/js_face_recognition.html Recognize
38+
Match a new feature vector with registered ones. Return a name of the best matched person.
39+
40+
-# The main loop.
41+
@snippet dnn/js_face_recognition.html Define frames processing
42+
A main loop of our application receives a frames from a camera and makes a recognition
43+
of an every detected face on the frame. We start this function ones when OpenCV.js was
44+
initialized and deep learning models were downloaded.

doc/tutorials/dnn/table_of_content_dnn.markdown

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,26 @@ Deep Neural Networks (dnn module) {#tutorial_table_of_content_dnn}
2525

2626
In this tutorial we describe the ways to schedule your networks using Halide backend in OpenCV deep learning module.
2727

28+
- @subpage tutorial_dnn_android
29+
30+
*Compatibility:* \> OpenCV 3.3
31+
32+
*Author:* Dmitry Kurtaev
33+
34+
This tutorial will show you how to run deep learning model using OpenCV on Android device.
35+
2836
- @subpage tutorial_dnn_yolo
2937

3038
*Compatibility:* \> OpenCV 3.3.1
3139

3240
*Author:* Alessandro de Oliveira Faria
3341

3442
In this tutorial you will learn how to use opencv_dnn module using yolo_object_detection with device capture, video file or image.
43+
44+
- @subpage tutorial_dnn_javascript
45+
46+
*Compatibility:* \> OpenCV 3.3.1
47+
48+
*Author:* Dmitry Kurtaev
49+
50+
In this tutorial we'll run deep learning models in browser using OpenCV.js.

modules/dnn/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ set(the_description "Deep neural network module. It allows to load models from d
1515

1616
ocv_add_dispatched_file("layers/layers_common" AVX AVX2)
1717

18-
ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java)
18+
ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab java js)
1919
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo
2020
-Wmissing-declarations -Wmissing-prototypes
2121
)

modules/dnn/include/opencv2/dnn/all_layers.hpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,6 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
221221
class CV_EXPORTS LRNLayer : public Layer
222222
{
223223
public:
224-
enum Type
225-
{
226-
CHANNEL_NRM,
227-
SPATIAL_NRM
228-
};
229224
int type;
230225

231226
int size;
@@ -238,14 +233,6 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
238233
class CV_EXPORTS PoolingLayer : public Layer
239234
{
240235
public:
241-
enum Type
242-
{
243-
MAX,
244-
AVE,
245-
STOCHASTIC,
246-
ROI
247-
};
248-
249236
int type;
250237
Size kernel, stride, pad;
251238
bool globalPooling;
@@ -474,13 +461,6 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
474461
class CV_EXPORTS EltwiseLayer : public Layer
475462
{
476463
public:
477-
enum EltwiseOp
478-
{
479-
PROD = 0,
480-
SUM = 1,
481-
MAX = 2,
482-
};
483-
484464
static Ptr<EltwiseLayer> create(const LayerParams &params);
485465
};
486466

modules/dnn/include/opencv2/dnn/dnn.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -423,8 +423,8 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
423423
* @param outputBlobs contains all output blobs for each layer specified in @p outBlobNames.
424424
* @param outBlobNames names for layers which outputs are needed to get
425425
*/
426-
CV_WRAP void forward(std::vector<std::vector<Mat> >& outputBlobs,
427-
const std::vector<String>& outBlobNames);
426+
void forward(std::vector<std::vector<Mat> >& outputBlobs,
427+
const std::vector<String>& outBlobNames);
428428

429429
//TODO:
430430
/** @brief Optimized forward.
@@ -467,7 +467,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
467467
* @note If updating blob is not empty then @p blob must have the same shape,
468468
* because network reshaping is not implemented yet.
469469
*/
470-
CV_WRAP void setInput(const Mat &blob, const String& name = "");
470+
CV_WRAP void setInput(InputArray blob, const String& name = "");
471471

472472
/** @brief Sets the new value for the learned param of the layer.
473473
* @param layer name or id of the layer.
@@ -733,7 +733,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
733733
* If @p crop is false, direct resize without cropping and preserving aspect ratio is performed.
734734
* @returns 4-dimansional Mat with NCHW dimensions order.
735735
*/
736-
CV_EXPORTS_W Mat blobFromImage(const Mat& image, double scalefactor=1.0, const Size& size = Size(),
736+
CV_EXPORTS_W Mat blobFromImage(InputArray image, double scalefactor=1.0, const Size& size = Size(),
737737
const Scalar& mean = Scalar(), bool swapRB=true, bool crop=true);
738738
/** @brief Creates 4-dimensional blob from series of images. Optionally resizes and
739739
* crops @p images from center, subtract @p mean values, scales values by @p scalefactor,

modules/dnn/src/dnn.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ static String toString(const T &v)
8484
return ss.str();
8585
}
8686

87-
Mat blobFromImage(const Mat& image, double scalefactor, const Size& size,
87+
Mat blobFromImage(InputArray image, double scalefactor, const Size& size,
8888
const Scalar& mean, bool swapRB, bool crop)
8989
{
9090
CV_TRACE_FUNCTION();
91-
std::vector<Mat> images(1, image);
91+
std::vector<Mat> images(1, image.getMat());
9292
return blobFromImages(images, scalefactor, size, mean, swapRB, crop);
9393
}
9494

@@ -1910,7 +1910,7 @@ void Net::setInputsNames(const std::vector<String> &inputBlobNames)
19101910
impl->netInputLayer->setNames(inputBlobNames);
19111911
}
19121912

1913-
void Net::setInput(const Mat &blob_, const String& name)
1913+
void Net::setInput(InputArray blob, const String& name)
19141914
{
19151915
CV_TRACE_FUNCTION();
19161916
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
@@ -1930,6 +1930,7 @@ void Net::setInput(const Mat &blob_, const String& name)
19301930
ld.umat_outputBlobs.resize( std::max(pin.oid+1, (int)ld.requiredOutputs.size()) );
19311931
ld.outputBlobsWrappers.resize(ld.outputBlobs.size());
19321932
MatShape prevShape = shape(ld.outputBlobs[pin.oid]);
1933+
Mat blob_ = blob.getMat();
19331934
bool oldShape = prevShape == shape(blob_);
19341935
if (oldShape)
19351936
{

modules/dnn/src/layers/eltwise_layer.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,27 @@ namespace dnn
5252
class EltwiseLayerImpl : public EltwiseLayer
5353
{
5454
public:
55-
EltwiseOp op;
55+
enum EltwiseOp
56+
{
57+
PROD = 0,
58+
SUM = 1,
59+
MAX = 2,
60+
} op;
5661
std::vector<float> coeffs;
5762

5863
EltwiseLayerImpl(const LayerParams& params)
5964
{
6065
setParamsFrom(params);
61-
op = EltwiseLayer::SUM;
66+
op = SUM;
6267
if (params.has("operation"))
6368
{
6469
String operation = params.get<String>("operation").toLowerCase();
6570
if (operation == "prod")
66-
op = EltwiseLayer::PROD;
71+
op = PROD;
6772
else if (operation == "sum")
68-
op = EltwiseLayer::SUM;
73+
op = SUM;
6974
else if (operation == "max")
70-
op = EltwiseLayer::MAX;
75+
op = MAX;
7176
else
7277
CV_Error(cv::Error::StsBadArg, "Unknown operaticon type \"" + operation + "\"");
7378
}
@@ -122,7 +127,7 @@ class EltwiseLayerImpl : public EltwiseLayer
122127
int channels;
123128
size_t planeSize;
124129

125-
EltwiseInvoker() : srcs(0), nsrcs(0), dst(0), coeffs(0), op(EltwiseLayer::PROD), nstripes(0), activ(0), channels(0), planeSize(0) {}
130+
EltwiseInvoker() : srcs(0), nsrcs(0), dst(0), coeffs(0), op(PROD), nstripes(0), activ(0), channels(0), planeSize(0) {}
126131

127132
static void run(const Mat** srcs, int nsrcs, Mat& dst,
128133
const std::vector<float>& coeffs, EltwiseOp op,
@@ -150,7 +155,7 @@ class EltwiseLayerImpl : public EltwiseLayer
150155
CV_Assert(dst.total() == dst.size[0] * p.channels * p.planeSize);
151156

152157
bool simpleCoeffs = true;
153-
if( op == EltwiseLayer::SUM && !coeffs.empty() )
158+
if( op == SUM && !coeffs.empty() )
154159
{
155160
CV_Assert( coeffs.size() == (size_t)nsrcs );
156161

@@ -192,7 +197,7 @@ class EltwiseLayerImpl : public EltwiseLayer
192197
const float* srcptr0 = srcs[0]->ptr<float>() + globalDelta;
193198
float* dstptr = dstptr0 + globalDelta;
194199

195-
if( op == EltwiseLayer::PROD )
200+
if( op == PROD )
196201
{
197202
for( k = 1; k < n; k++ )
198203
{
@@ -204,7 +209,7 @@ class EltwiseLayerImpl : public EltwiseLayer
204209
srcptr0 = (const float*)dstptr;
205210
}
206211
}
207-
else if( op == EltwiseLayer::MAX )
212+
else if( op == MAX )
208213
{
209214
for( k = 1; k < n; k++ )
210215
{

modules/dnn/src/layers/lrn_layer.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ class LRNLayerImpl : public LRNLayer
6767
type = -1;
6868
String nrmType = params.get<String>("norm_region", "ACROSS_CHANNELS");
6969
if (nrmType == "ACROSS_CHANNELS")
70-
type = LRNLayer::CHANNEL_NRM;
70+
type = CHANNEL_NRM;
7171
else if (nrmType == "WITHIN_CHANNEL")
72-
type = LRNLayer::SPATIAL_NRM;
72+
type = SPATIAL_NRM;
7373
else
7474
CV_Error(Error::StsBadArg, "Unknown region type \"" + nrmType + "\"");
7575

@@ -397,6 +397,13 @@ class LRNLayerImpl : public LRNLayer
397397
}
398398
return flops;
399399
}
400+
401+
private:
402+
enum Type
403+
{
404+
CHANNEL_NRM,
405+
SPATIAL_NRM
406+
};
400407
};
401408

402409
Ptr<LRNLayer> LRNLayer::create(const LayerParams& params)

modules/dnn/src/layers/pooling_layer.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,27 +63,27 @@ class PoolingLayerImpl : public PoolingLayer
6363
public:
6464
PoolingLayerImpl(const LayerParams& params)
6565
{
66-
type = PoolingLayer::MAX;
66+
type = MAX;
6767
computeMaxIdx = true;
6868
globalPooling = false;
6969

7070
if (params.has("pool"))
7171
{
7272
String pool = params.get<String>("pool").toLowerCase();
7373
if (pool == "max")
74-
type = PoolingLayer::MAX;
74+
type = MAX;
7575
else if (pool == "ave")
76-
type = PoolingLayer::AVE;
76+
type = AVE;
7777
else if (pool == "stochastic")
78-
type = PoolingLayer::STOCHASTIC;
78+
type = STOCHASTIC;
7979
else
8080
CV_Error(Error::StsBadArg, "Unknown pooling type \"" + pool + "\"");
8181
getPoolingKernelParams(params, kernel.height, kernel.width, globalPooling,
8282
pad.height, pad.width, stride.height, stride.width, padMode);
8383
}
8484
else if (params.has("pooled_w") || params.has("pooled_h") || params.has("spatial_scale"))
8585
{
86-
type = PoolingLayer::ROI;
86+
type = ROI;
8787
}
8888
setParamsFrom(params);
8989
ceilMode = params.get<bool>("ceil_mode", true);
@@ -115,8 +115,7 @@ class PoolingLayerImpl : public PoolingLayer
115115
{
116116
return backendId == DNN_BACKEND_DEFAULT ||
117117
backendId == DNN_BACKEND_HALIDE && haveHalide() &&
118-
(type == PoolingLayer::MAX ||
119-
type == PoolingLayer::AVE && !pad.width && !pad.height);
118+
(type == MAX || type == AVE && !pad.width && !pad.height);
120119
}
121120

122121
#ifdef HAVE_OPENCL
@@ -200,9 +199,9 @@ class PoolingLayerImpl : public PoolingLayer
200199

201200
virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &inputs)
202201
{
203-
if (type == PoolingLayer::MAX)
202+
if (type == MAX)
204203
return initMaxPoolingHalide(inputs);
205-
else if (type == PoolingLayer::AVE)
204+
else if (type == AVE)
206205
return initAvePoolingHalide(inputs);
207206
else
208207
return Ptr<BackendNode>();
@@ -221,7 +220,7 @@ class PoolingLayerImpl : public PoolingLayer
221220
float spatialScale;
222221

223222
PoolingInvoker() : src(0), rois(0), dst(0), mask(0), nstripes(0),
224-
computeMaxIdx(0), poolingType(PoolingLayer::MAX), spatialScale(0) {}
223+
computeMaxIdx(0), poolingType(MAX), spatialScale(0) {}
225224

226225
static void run(const Mat& src, const Mat& rois, Mat& dst, Mat& mask, Size kernel,
227226
Size stride, Size pad, int poolingType, float spatialScale,
@@ -698,7 +697,7 @@ class PoolingLayerImpl : public PoolingLayer
698697
out.height = 1;
699698
out.width = 1;
700699
}
701-
else if (type == PoolingLayer::ROI)
700+
else if (type == ROI)
702701
{
703702
out.height = pooledSize.height;
704703
out.width = pooledSize.width;
@@ -757,6 +756,14 @@ class PoolingLayerImpl : public PoolingLayer
757756
}
758757
return flops;
759758
}
759+
private:
760+
enum Type
761+
{
762+
MAX,
763+
AVE,
764+
STOCHASTIC,
765+
ROI
766+
};
760767
};
761768

762769
Ptr<PoolingLayer> PoolingLayer::create(const LayerParams& params)

0 commit comments

Comments
 (0)